ProSHADE  0.7.6.6 (JUL 2022)
Protein Shape Detection
ProSHADE_maths.cpp
Go to the documentation of this file.
1 
23 //==================================================== ProSHADE
24 #include "ProSHADE_maths.hpp"
25 
38 void ProSHADE_internal_maths::complexMultiplication ( proshade_double* r1, proshade_double* i1, proshade_double* r2, proshade_double* i2, proshade_double* retReal, proshade_double* retImag )
39 {
40  //================================================ Multiplication
41  *retReal = (*r1)*(*r2) - (*i1)*(*i2);
42  *retImag = (*r1)*(*i2) + (*i1)*(*r2);
43 
44  //================================================ Return
45  return ;
46 
47 }
48 
62 void ProSHADE_internal_maths::complexMultiplicationConjug ( proshade_double* r1, proshade_double* i1, proshade_double* r2, proshade_double* i2, proshade_double* retReal, proshade_double* retImag )
63 {
64  //================================================ Multiplication
65  *retReal = (*r1)*(*r2) + (*i1)*(*i2);
66  *retImag = -(*r1)*(*i2) + (*i1)*(*r2);
67 
68  //================================================ Return
69  return ;
70 
71 }
72 
83 proshade_double ProSHADE_internal_maths::complexMultiplicationRealOnly ( proshade_double* r1, proshade_double* i1, proshade_double* r2, proshade_double* i2 )
84 {
85  //================================================ Multiplication
86  proshade_double ret = (*r1)*(*r2) - (*i1)*(*i2);
87 
88  //================================================ Return
89  return ( ret );
90 
91 }
92 
103 proshade_double ProSHADE_internal_maths::complexMultiplicationConjugRealOnly ( proshade_double* r1, proshade_double* i1, proshade_double* r2, proshade_double* i2 )
104 {
105  //================================================ Multiplication
106  proshade_double ret = (*r1)*(*r2) + (*i1)*(*i2);
107 
108  //================================================ Return
109  return ( ret );
110 
111 }
112 
121 void ProSHADE_internal_maths::vectorMeanAndSD ( std::vector<proshade_double>* vec, proshade_double*& ret )
122 {
123  //================================================ Get mean
124  ret[0] = std::accumulate ( vec->begin(), vec->end(), 0.0 ) / static_cast<proshade_double> ( vec->size() );
125 
126  //================================================ Get standard deviation
127  proshade_double squaredSum = std::inner_product ( vec->begin(), vec->end(), vec->begin(), 0.0 );
128  ret[1] = std::sqrt ( ( squaredSum / static_cast<proshade_double> ( vec->size() ) ) - std::pow ( ret[0], 2.0 ) );
129 
130  //================================================ Check for NaN's
131  const FloatingPoint< proshade_double > lhs1 ( ret[0] );
132  const FloatingPoint< proshade_double > lhs2 ( ret[1] );
133  if ( !lhs1.AlmostEquals ( lhs1 ) ) { ret[0] = 0.0; }
134  if ( !lhs2.AlmostEquals ( lhs2 ) ) { ret[1] = 0.0; }
135 
136  //================================================ Return
137  return ;
138 
139 }
140 
149 void ProSHADE_internal_maths::vectorMedianAndIQR ( std::vector<proshade_double>* vec, proshade_double*& ret )
150 {
151  //================================================ Sanity check
152  if ( vec->size() < 3 ) { ret[0] = 0.0; ret[1] = 0.0; return; }
153 
154  //================================================ Sort the vector
155  std::sort ( vec->begin(), vec->end() );
156 
157  //================================================ Get median
158  if ( static_cast<proshade_unsign> ( vec->size() ) % 2 == 0)
159  {
160  ret[0] = ( vec->at( ( static_cast<proshade_unsign> ( vec->size() ) / 2 ) - 1 ) +
161  vec->at( static_cast<proshade_unsign> ( vec->size() ) / 2 ) ) / 2.0;
162  }
163  else
164  {
165  ret[0] = vec->at( static_cast<proshade_unsign> ( vec->size() ) / 2 );
166  }
167 
168  //================================================ Get first and third quartile
169  proshade_double Q1, Q3;
170  if ( static_cast<proshade_unsign> ( vec->size() ) % 2 == 0)
171  {
172  Q1 = ( vec->at( ( static_cast<proshade_unsign> ( vec->size() ) / 4 ) - 1 ) +
173  vec->at( static_cast<proshade_unsign> ( vec->size() ) / 4 ) ) / 2.0;
174  Q3 = ( vec->at( ( ( static_cast<proshade_unsign> ( vec->size() ) / 4 ) * 3 ) - 1 ) +
175  vec->at( ( static_cast<proshade_unsign> ( vec->size() ) / 4 ) * 3 ) ) / 2.0;
176  }
177  else
178  {
179  Q1 = vec->at( static_cast<proshade_unsign> ( vec->size() ) / 4 );
180  Q3 = vec->at( ( static_cast<proshade_unsign> ( vec->size() ) / 4 ) * 3 );
181  }
182 
183  //================================================ And now save the IQR
184  ret[1] = Q3 - Q1;
185 
186  //================================================ Return
187  return ;
188 
189 }
190 
200 void ProSHADE_internal_maths::arrayMedianAndIQR ( proshade_double* vec, proshade_unsign vecSize, proshade_double*& ret )
201 {
202  //================================================ Sort the vector
203  std::sort ( vec, vec + vecSize );
204 
205  //================================================ Get median
206  if ( vecSize % 2 == 0)
207  {
208  ret[0] = ( vec[ ( vecSize / 2 ) - 1 ] + vec[ vecSize / 2 ] ) / 2.0;
209  }
210  else
211  {
212  ret[0] = vec[ vecSize / 2 ];
213  }
214 
215  //================================================ Get first and third quartile
216  proshade_double Q1, Q3;
217  if ( vecSize % 2 == 0)
218  {
219  Q1 = ( vec[ ( vecSize / 4 ) - 1 ] + vec[ vecSize / 4 ] ) / 2.0;
220  Q3 = ( vec[ ( ( vecSize / 4 ) * 3 ) - 1 ] + vec[ ( vecSize / 4 ) * 3 ] ) / 2.0;
221  }
222  else
223  {
224  Q1 = vec[ vecSize / 4 ];
225  Q3 = vec[ ( vecSize / 4 ) * 3 ];
226  }
227 
228  //================================================ And now save the IQR
229  ret[1] = Q3 - Q1;
230 
231  //================================================ Return
232  return ;
233 
234 }
235 
246 proshade_double ProSHADE_internal_maths::pearsonCorrCoeff ( proshade_double* valSet1, proshade_double* valSet2, proshade_unsign length )
247 {
248  //================================================ Find vector means
249  proshade_double xMean = 0.0;
250  proshade_double yMean = 0.0;
251  proshade_double zeroCount = 0.0;
252  for ( proshade_unsign iter = 0; iter < length; iter++ )
253  {
254  xMean += valSet1[iter];
255  yMean += valSet2[iter];
256  }
257  xMean /= static_cast<proshade_double> ( length ) - zeroCount;
258  yMean /= static_cast<proshade_double> ( length ) - zeroCount;
259 
260  //================================================ Get Pearson's correlation coefficient
261  proshade_double xmmymm = 0.0;
262  proshade_double xmmsq = 0.0;
263  proshade_double ymmsq = 0.0;
264  for ( proshade_unsign iter = 0; iter < length; iter++ )
265  {
266  xmmymm += ( valSet1[iter] - xMean ) * ( valSet2[iter] - yMean );
267  xmmsq += pow( valSet1[iter] - xMean, 2.0 );
268  ymmsq += pow( valSet2[iter] - yMean, 2.0 );
269  }
270 
271  proshade_double ret = xmmymm / ( sqrt(xmmsq) * sqrt(ymmsq) );
272 
273  //================================================ Done
274  if ( std::isnan ( ret ) ) { return ( 0.0 ); }
275  return ( ret );
276 
277 }
278 
289 void ProSHADE_internal_maths::getLegendreAbscAndWeights ( proshade_unsign order, proshade_double* abscissas, proshade_double* weights, proshade_unsign noSteps )
290 {
291  //================================================ Sanity check
292  if ( order < 2 )
293  {
294  throw ProSHADE_exception ( "The integration order is too low.", "EI00019", __FILE__, __LINE__, __func__, "The Gauss-Legendre integration order is less than 2. This\n : seems very low; if you have a very small structure or very\n : low resolution, please manually increase the integration\n : order. Otherwise, please report this as a bug." );
295  }
296 
297  //================================================ Initialise
298  proshade_double polyValue = 0.0;
299  proshade_double deriValue = 0.0;
300  proshade_double weightSum = 0.0;
301 
302  //================================================ Find the polynomial and derivative values at 0
303  getGLPolyAtZero ( order,
304  &polyValue,
305  &deriValue );
306 
307  //================================================ If the order is odd, then 0 is a root and we know the value already
308  if ( order % 2 == 1 )
309  {
310  abscissas[((order-1)/2)] = polyValue;
311  weights[((order-1)/2)] = deriValue;
312  }
313  //================================================ But if order is even, find the first root as follows
314  else
315  {
316  getGLFirstRealRoot ( polyValue, order, &abscissas[(order/2)], &weights[(order/2)], noSteps );
317  }
318 
319  //================================================ Now, having computed the first root, complete the series
320  completeAbscissasAndWeights ( order, abscissas, weights, noSteps );
321 
322  //================================================ Correct weights by abscissa values
323  for ( proshade_unsign iter = 0; iter < order; iter++ )
324  {
325  weights[iter] = 2.0 / ( 1.0 - abscissas[iter] ) / ( 1.0 + abscissas[iter] ) / weights[iter] / weights[iter];
326  weightSum += weights[iter];
327  }
328 
329  //================================================ Normalise weights
330  for ( proshade_unsign iter = 0; iter < order; iter++ )
331  {
332  weights[iter] = 2.0 * weights[iter] / weightSum;
333  }
334 
335  //================================================ Done
336  return ;
337 }
338 
349 void ProSHADE_internal_maths::getGLPolyAtZero ( proshade_unsign order, proshade_double *polyValue, proshade_double *deriValue )
350 {
351  //================================================ Initialise
352  proshade_double hlpVal = 0.0;
353  proshade_double prevPoly = 1.0;
354  proshade_double prevPrevPoly = 0.0;
355  proshade_double prevDeri = 0.0;
356  proshade_double prevPrevDeri = 0.0;
357 
358  for ( proshade_unsign ordIt = 0; ordIt < order; ordIt++ )
359  {
360  hlpVal = static_cast<proshade_double> ( ordIt );
361  *polyValue = -hlpVal * prevPrevPoly / ( hlpVal + 1.0 );
362  *deriValue = ( ( 2.0 * hlpVal + 1.0 ) * prevPoly - hlpVal * prevPrevDeri ) / ( hlpVal + 1.0 );
363  prevPrevPoly = prevPoly;
364  prevPoly = *polyValue;
365  prevPrevDeri = prevDeri;
366  prevDeri = *deriValue;
367  }
368 
369  //================================================ Done
370  return ;
371 
372 }
373 
386 void ProSHADE_internal_maths::getGLFirstRealRoot ( proshade_double polyAtZero, proshade_unsign order, proshade_double *firstRoot, proshade_double *firstRootDeriv, proshade_unsign noSteps )
387 {
388  //================================================ Sanity check
389  if ( noSteps < 2 )
390  {
391  throw ProSHADE_exception ( "The number of steps is too low.", "EI00020", __FILE__, __LINE__, __func__, "The number of steps limit is less than 2. This\n : seems very low; if you have a very small structure or very\n : low resolution, please manually increase the integration\n : order. Otherwise, please report this as a bug." );
392  }
393 
394  //================================================ Initialise variables
395  *firstRoot = advanceGLPolyValue ( 0.0, -M_PI / 2.0, 0.0, order, noSteps );
396  proshade_double hlp = 0.0;
397  proshade_double hlpVal = static_cast<proshade_double> ( order );
398  proshade_double *polyTerms;
399  proshade_double *deriTerms;
400 
401  //================================================ Allocate memory
402  polyTerms = new proshade_double [noSteps+2];
403  deriTerms = new proshade_double [noSteps+1];
404  ProSHADE_internal_misc::checkMemoryAllocation ( polyTerms, __FILE__, __LINE__, __func__ );
405  ProSHADE_internal_misc::checkMemoryAllocation ( deriTerms, __FILE__, __LINE__, __func__ );
406 
407  //================================================ Pre-set values
408  polyTerms[0] = 0.0;
409  polyTerms[1] = polyAtZero;
410  deriTerms[0] = 0.0;
411 
412  //================================================ Prepare polynomial decomposition into terms
413  for ( proshade_unsign iter = 0; iter <= noSteps - 2; iter = iter + 2 )
414  {
415  hlp = static_cast<proshade_double> ( iter );
416 
417  polyTerms[iter+2] = 0.0;
418  polyTerms[iter+3] = ( hlp * ( hlp + 1.0 ) - hlpVal * ( hlpVal + 1.0 ) ) * polyTerms[iter+1] / (hlp + 1.0) / (hlp + 2.0 );
419 
420  deriTerms[iter+1] = 0.0;
421  deriTerms[iter+2] = ( hlp + 2.0 ) * polyTerms[iter+3];
422  }
423 
424  //================================================ Evaluate the polynomial and its derivative to determine the first root and derivative value
425  for ( proshade_double iter = 0; iter < noSteps; iter++ )
426  {
427  *firstRoot = *firstRoot - evaluateGLPolynomial ( polyTerms, *firstRoot, noSteps ) / evaluateGLPolynomial ( deriTerms, *firstRoot, noSteps-1 );
428  }
429  *firstRootDeriv = evaluateGLPolynomial ( deriTerms, *firstRoot, noSteps-1 );
430 
431  //================================================ Free memory
432  delete polyTerms;
433  delete deriTerms;
434 
435  //================================================ Done
436  return ;
437 
438 }
439 
450 proshade_double ProSHADE_internal_maths::evaluateGLPolynomial ( proshade_double *series, proshade_double target, proshade_unsign terms )
451 {
452  //================================================ Initalise
453  proshade_double factorialValue = 1.0;
454  proshade_double value = 0.0;
455 
456  //================================================ Evaluate the polynomial
457  for ( proshade_unsign iter = 1; iter <= terms; iter++ )
458  {
459  value = value + series[iter] * factorialValue;
460  factorialValue = factorialValue * target;
461  }
462 
463  //================================================ Done
464  return ( value );
465 
466 }
467 
480 proshade_double ProSHADE_internal_maths::advanceGLPolyValue ( proshade_double from, proshade_double to, proshade_double valAtFrom, proshade_unsign order, proshade_unsign noSteps )
481 {
482  //================================================ Initialise variables
483  proshade_double hlpVal = 0.0;
484  proshade_double stepSize = 0.0;
485  proshade_double valChange = 0.0;
486  proshade_double valSecChange = 0.0;
487  proshade_double squareOrder = 0.0;
488  proshade_double curPos = from;
489  proshade_double curVal = valAtFrom;
490 
491  //================================================ Set initial values
492  stepSize = ( to - from ) / static_cast<proshade_double> ( noSteps );
493  squareOrder = sqrt ( static_cast<proshade_double> ( order * ( order + 1 ) ) );
494 
495  //================================================ Go through the series and iteratively improve the estimate
496  for ( proshade_unsign iter = 0; iter < noSteps; iter++ )
497  {
498  hlpVal = ( 1.0 - curVal ) * ( 1.0 + curVal );
499  valChange = - stepSize * hlpVal / ( squareOrder * sqrt ( hlpVal ) - ( curVal * std::sin ( 2.0 * curPos ) / 2.0 ) );
500 
501  curVal += valChange;
502  curPos += stepSize;
503 
504  hlpVal = ( 1.0 - curVal ) * ( 1.0 + curVal );
505  valSecChange = - stepSize * hlpVal / ( squareOrder * sqrt ( hlpVal ) - ( curVal * std::sin ( 2.0 * curPos ) / 2.0 ) );
506  curVal = curVal + ( valSecChange - valChange ) / 2.0;
507  }
508 
509  //================================================ Done
510  return curVal;
511 
512 }
513 
524 void ProSHADE_internal_maths::completeAbscissasAndWeights ( proshade_unsign order, proshade_double* abscissas, proshade_double* weights, proshade_unsign noSteps )
525 {
526  //================================================ Initialise internal variables
527  proshade_double hlpStepVal = 0.0;
528  proshade_double hlpOrderVal = static_cast<proshade_double> ( order );
529  proshade_double abscValueChange = 0.0;
530  proshade_double prevAbsc = 0.0;
531  proshade_double *polyDecomposition;
532  proshade_double *deriDecomposition;
533  proshade_unsign knownRootPos = 0;
534  proshade_unsign oddEvenSwitch = 0;
535 
536  //================================================ Pre-set internal values
537  if ( order % 2 == 1 )
538  {
539  knownRootPos = ( order - 1 ) / 2;
540  oddEvenSwitch = 1;
541  }
542  else
543  {
544  knownRootPos = order / 2;
545  oddEvenSwitch = 0;
546  }
547 
548  //================================================ Allocate memory
549  polyDecomposition = new proshade_double[noSteps+2];
550  deriDecomposition = new proshade_double[noSteps+1];
551  ProSHADE_internal_misc::checkMemoryAllocation ( polyDecomposition, __FILE__, __LINE__, __func__ );
552  ProSHADE_internal_misc::checkMemoryAllocation ( deriDecomposition, __FILE__, __LINE__, __func__ );
553 
554  //================================================ For each abscissa-weight pair after the first root
555  for ( proshade_unsign serIt = knownRootPos + 1; serIt < order; serIt++ )
556  {
557  //============================================ Init loop
558  prevAbsc = abscissas[serIt-1];
559  abscValueChange = advanceGLPolyValue ( M_PI/2.0, -M_PI/2.0, prevAbsc, order, noSteps ) - prevAbsc;
560 
561  //============================================ Init polynomial decomposition array
562  polyDecomposition[0] = 0.0;
563  polyDecomposition[1] = 0.0;
564  polyDecomposition[2] = weights[serIt-1];
565 
566  //============================================ Init polynomial derivative decomposition array
567  deriDecomposition[0] = 0.0;
568  deriDecomposition[1] = polyDecomposition[2];
569 
570  //============================================ Compute the polynomial and its derivative decomposition into terms
571  for ( proshade_unsign stIt = 0; stIt <= noSteps - 2; stIt++ )
572  {
573  hlpStepVal = static_cast<proshade_double> ( stIt );
574 
575  polyDecomposition[stIt+3] = ( 2.0 * prevAbsc * ( hlpStepVal + 1.0 ) * polyDecomposition[stIt+2] + ( hlpStepVal * ( hlpStepVal + 1.0 ) - hlpOrderVal *
576  ( hlpOrderVal + 1.0 ) ) * polyDecomposition[stIt+1] / ( hlpStepVal + 1.0 ) ) / ( 1.0 - prevAbsc ) / ( 1.0 + prevAbsc ) /
577  ( hlpStepVal + 2.0 );
578 
579  deriDecomposition[stIt+2] = ( hlpStepVal + 2.0 ) * polyDecomposition[stIt+3];
580  }
581 
582  //============================================ Evaluate the polynomial and its derivative to determine the root and derivative value
583  for ( proshade_unsign iter = 0; iter < noSteps; iter++ )
584  {
585  abscValueChange = abscValueChange - evaluateGLPolynomial ( polyDecomposition, abscValueChange, noSteps ) / evaluateGLPolynomial ( deriDecomposition, abscValueChange, noSteps-1 );
586  }
587 
588  //============================================ Save results
589  abscissas[serIt] = prevAbsc + abscValueChange;
590  weights[serIt] = evaluateGLPolynomial ( deriDecomposition, abscValueChange, noSteps - 1 );
591  }
592 
593  //================================================ The negative roots and their weights have the same distance as the positive roots (i.e. abscissas[firstRoot+1] == -abscissas[firstRoot-1]) and same weight
594  for ( proshade_unsign serIt = 0; serIt < knownRootPos + oddEvenSwitch; serIt++ )
595  {
596  abscissas[serIt] = -abscissas[order-serIt-1];
597  weights[serIt] = weights[order-serIt-1];
598  }
599 
600  //================================================ Free memory
601  delete polyDecomposition;
602  delete deriDecomposition;
603 
604  //================================================ Done
605  return ;
606 
607 }
608 
624 proshade_double ProSHADE_internal_maths::gaussLegendreIntegrationReal ( proshade_double* vals, proshade_unsign valsSize, proshade_unsign order, proshade_double* abscissas, proshade_double* weights, proshade_double integralOverRange, proshade_double maxSphereDists )
625 {
626  //================================================ Initialise local variables
627  proshade_double ret = 0.0;
628  proshade_complex* intData = new proshade_complex[order];
629  ProSHADE_internal_misc::checkMemoryAllocation ( intData, __FILE__, __LINE__, __func__ );
630  proshade_complex posVals;
631  proshade_unsign lesserPos = 0;
632  proshade_unsign upperPos = 0;
633  proshade_double lesserWeight = 0.0;
634  proshade_double upperWeight = 0.0;
635 
636  //================================================ Rescale to <order> points
637  for ( proshade_unsign absIter = 0; absIter < order; absIter++ )
638  {
639  //============================================ Init loop
640  posVals[0] = 0.0;
641  posVals[1] = 0.0;
642 
643  //============================================ Find real position of abscissas
644  posVals[0] = ( ( abscissas[absIter] + 1.0 ) / 2.0 ) * integralOverRange;
645 
646 
647  //============================================ Find lesser and upper bounds
648  for ( proshade_unsign valIt = 0; valIt < valsSize; valIt++ )
649  {
650  if ( ( ( static_cast< proshade_double > ( valIt ) * maxSphereDists ) <= posVals[0] ) && ( ( ( static_cast< proshade_double > ( valIt ) + 1.0 ) * maxSphereDists ) > posVals[0] ) )
651  {
652  lesserPos = static_cast<proshade_unsign> ( valIt );
653  upperPos = static_cast<proshade_unsign> ( valIt + 1 );
654  break;
655  }
656  }
657 
658  //============================================ Linear Interpolation
659  lesserWeight = 0.0;
660  upperWeight = 0.0;
661  if ( lesserPos != 0 )
662  {
663  //======================================== Here we realise that the lesser and upper bounds were determined on scale 1 ... N, while our values are on scale 0 ... N-1 and therefore after determining the linear interpolation weights, we subtract 1 from both lesserPos and upperPos; however ...
664  lesserWeight = static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists );
665  upperWeight = 1.0 - lesserWeight;
666 
667  posVals[1] = ( lesserWeight * vals[lesserPos-1] ) + ( upperWeight * vals[upperPos-1] );
668  }
669  else
670  {
671  //======================================== ... this then means that we would require position -1 for when the integration value is between 0 and the first shell. To resolve this, we assume that the values are 0 below the first shell and proceed as follows:
672  upperWeight = 1.0 - ( static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists ) );
673 
674  posVals[1] = ( upperWeight * vals[upperPos-1] );
675  }
676 
677  intData[absIter][0] = posVals[0];
678  intData[absIter][1] = posVals[1];
679  }
680 
681  //================================================ Integrate
682  for ( proshade_unsign absPoint = 0; absPoint < order; absPoint++ )
683  {
684  ret += ( weights[absPoint] * intData[absPoint][1] );
685  }
686 
687  //================================================ Normalise
688  ret *= ( integralOverRange / 2.0 );
689 
690  //================================================ Release memory
691  delete[] intData;
692 
693  //================================================ Done
694  return ( ret );
695 
696 }
697 
714 void ProSHADE_internal_maths::gaussLegendreIntegration ( proshade_complex* vals, proshade_unsign valsSize, proshade_unsign order, proshade_double* abscissas, proshade_double* weights, proshade_double integralOverRange, proshade_double maxSphereDists, proshade_double* retReal, proshade_double* retImag )
715 {
716  //================================================ Initialise local variables
717  proshade_triplet* intData = new proshade_triplet [order];
718  ProSHADE_internal_misc::checkMemoryAllocation ( intData, __FILE__, __LINE__, __func__ );
719  proshade_triplet posVals;
720  proshade_unsign lesserPos = 0;
721  proshade_unsign upperPos = 0;
722  proshade_double lesserWeight = 0.0;
723  proshade_double upperWeight = 0.0;
724 
725  //================================================ Rescale to <order> points
726  for ( proshade_unsign absIter = 0; absIter < order; absIter++ )
727  {
728  //============================================ Init loop
729  posVals[0] = 0.0;
730  posVals[1] = 0.0;
731  posVals[2] = 0.0;
732 
733  //============================================ Find real position of abscissas
734  posVals[0] = ( ( abscissas[absIter] + 1.0 ) / 2.0 ) * integralOverRange;
735 
736 
737  //============================================ Find lesser and upper bounds
738  for ( proshade_unsign valIt = 0; valIt < valsSize; valIt++ )
739  {
740  if ( ( ( static_cast< proshade_double > ( valIt ) * maxSphereDists ) <= posVals[0] ) && ( ( ( static_cast< proshade_double > ( valIt ) + 1.0 ) * maxSphereDists ) > posVals[0] ) )
741  {
742  lesserPos = static_cast<proshade_unsign> ( valIt );
743  upperPos = static_cast<proshade_unsign> ( valIt + 1 );
744  break;
745  }
746  }
747 
748  //============================================ Linear Interpolation
749  lesserWeight = 0.0;
750  upperWeight = 0.0;
751  if ( lesserPos != 0 )
752  {
753  //======================================== Here we realise that the lesser and upper bounds were determined on scale 1 ... N, while our values are on scale 0 ... N-1 and therefore after determining the linear interpolation weights, we subtract 1 from both lesserPos and upperPos; however ...
754  lesserWeight = static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists );
755  upperWeight = 1.0 - lesserWeight;
756 
757  posVals[1] = ( lesserWeight * vals[lesserPos-1][0] ) + ( upperWeight * vals[upperPos-1][0] );
758  posVals[2] = ( lesserWeight * vals[lesserPos-1][1] ) + ( upperWeight * vals[upperPos-1][1] );
759  }
760  else
761  {
762  //======================================== ... this then means that we would require position -1 for when the integration value is between 0 and the first shell. To resolve this, we assume that the values are 0 below the first shell and proceed as follows:
763  upperWeight = 1.0 - ( static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists ) );
764 
765  posVals[1] = ( upperWeight * vals[upperPos-1][0] );
766  posVals[2] = ( upperWeight * vals[upperPos-1][1] );
767  }
768 
769  intData[absIter][0] = posVals[0];
770  intData[absIter][1] = posVals[1];
771  intData[absIter][2] = posVals[2];
772  }
773 
774  //================================================ Integrate
775  *retReal = 0.0;
776  *retImag = 0.0;
777  for ( proshade_unsign absPoint = 0; absPoint < order; absPoint++ )
778  {
779  *retReal += ( weights[absPoint] * intData[absPoint][1] );
780  *retImag += ( weights[absPoint] * intData[absPoint][2] );
781  }
782 
783  //================================================ Normalise
784  *retReal *= ( integralOverRange / 2.0 );
785  *retImag *= ( integralOverRange / 2.0 );
786 
787  //================================================ Release memory
788  delete[] intData;
789 
790  //================================================ Done
791  return ;
792 
793 }
794 
807 void ProSHADE_internal_maths::complexMatrixSVDSigmasOnly ( proshade_complex** mat, int dim, double*& singularValues )
808 {
809  //================================================ Initialise local variables
810  char job = 'N'; // Save computation of parts of U and V matrices, they are not needed here
811  std::complex<double> *rotMatU = new std::complex<double> [dim*dim]; // The U matrix space
812  std::complex<double> *rotMatV = new std::complex<double> [dim*dim]; // The V^T matrix space
813  std::complex<double> *work = new std::complex<double> [( 4 * dim)]; // Workspace, minimum required is 3*dim, using more for performance
814  int workDim = ( 4 * dim); // Formalism stating just that
815  double* rwork = new double[(7 * dim)]; // Required by LAPACK, from 3.7 requires 7 * dim
816  int* iwork = new int[(8 * dim)]; // Required by LAPACK
817  int returnValue = 0; // This will tell if operation succeeded
818 
819  //================================================ Check memory allocation
820  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatU, __FILE__, __LINE__, __func__ );
821  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatV, __FILE__, __LINE__, __func__ );
822  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
823  ProSHADE_internal_misc::checkMemoryAllocation ( rwork, __FILE__, __LINE__, __func__ );
824  ProSHADE_internal_misc::checkMemoryAllocation ( iwork, __FILE__, __LINE__, __func__ );
825 
826  //================================================ Load input data into array in column-major order
827  std::complex<double> *matrixToDecompose = new std::complex<double>[dim*dim];
828  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
829  for ( int rowIt = 0; rowIt < dim; rowIt++ )
830  {
831  for ( int colIt = 0; colIt < dim; colIt++ )
832  {
833  matrixToDecompose[(colIt*dim)+rowIt] = std::complex<double> ( mat[rowIt][colIt][0], mat[rowIt][colIt][1] );
834  }
835  }
836 
837  //================================================ Run LAPACK ZGESDD
838  zgesdd_ ( &job, &dim, &dim, matrixToDecompose, &dim, singularValues, rotMatU, &dim, rotMatV, &dim,
839  work, &workDim, rwork, iwork, &returnValue );
840 
841  //================================================ Free memory
842  delete[] rotMatU;
843  delete[] rotMatV;
844  delete[] work;
845  delete[] rwork;
846  delete[] iwork;
847  delete[] matrixToDecompose;
848 
849  //================================================ Check result
850  if ( returnValue != 0 )
851  {
852  throw ProSHADE_exception ( "The LAPACK complex SVD algorithm did not converge!", "EL00021", __FILE__, __LINE__, __func__, "LAPACK algorithm for computing the singular value\n : decomposition of complex matrices did not converge and\n : therefore it was not possible to combine SH coefficients\n : from multiple shells. Changing the resolution may help,\n : contact me if this error persists." );
853  }
854 
855  //================================================ Done
856  return ;
857 
858 }
859 
874 void ProSHADE_internal_maths::realMatrixSVDUandVOnly ( proshade_double* mat, int dim, proshade_double* uAndV, bool fail )
875 {
876  //================================================ Initialise local variables
877  char job = 'A'; // Save computation of parts of U and V matrices, they are not needed here
878  double* singularValues = new double[dim]; // The array of singular values
879  double *rotMatU = new double [dim*dim]; // The U matrix space
880  double *rotMatV = new double [dim*dim]; // The V^T matrix space
881  double *work = new double [static_cast< proshade_unsign >( ( 3 * dim ) + pow( dim, 2 ) * dim)]; // Workspace, minimum required is 4*dim^2 + 7*dim, using more for performance
882  int workDim = static_cast< int > ( 2 * ( ( 4 * dim * dim ) + ( 7 * dim ) ) ); // Formalism stating just that
883  double* rwork = new double[static_cast<proshade_unsign>((5 * dim) + 5 * pow(dim,2))]; // Required by LAPACK
884  int* iwork = new int[(8 * dim)]; // Required by LAPACK
885  int returnValue = 0; // This will tell if operation succeeded
886  ProSHADE_internal_misc::checkMemoryAllocation ( singularValues, __FILE__, __LINE__, __func__ );
887  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatU, __FILE__, __LINE__, __func__ );
888  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatV, __FILE__, __LINE__, __func__ );
889  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
890  ProSHADE_internal_misc::checkMemoryAllocation ( rwork, __FILE__, __LINE__, __func__ );
891  ProSHADE_internal_misc::checkMemoryAllocation ( iwork, __FILE__, __LINE__, __func__ );
892 
893  //================================================ Load input data into array in column-major order
894  double *matrixToDecompose = new double[dim*dim];
895  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
896  for ( int rowIt = 0; rowIt < dim; rowIt++ )
897  {
898  for ( int colIt = 0; colIt < dim; colIt++ )
899  {
900  matrixToDecompose[(colIt*dim)+rowIt] = mat[(rowIt*dim)+colIt];
901  }
902  }
903 
904  //================================================ Run LAPACK ZGESDD
905  dgesdd_ ( &job, &dim, &dim, matrixToDecompose, &dim, singularValues, rotMatU, &dim, rotMatV, &dim,
906  work, &workDim, rwork, iwork, &returnValue );
907 
908  //================================================ Free memory
909  delete[] work;
910  delete[] rwork;
911  delete[] iwork;
912  delete[] matrixToDecompose;
913  delete[] singularValues;
914 
915  //================================================ Check result
916  if ( ( returnValue != 0 ) && ( fail ) )
917  {
918  throw ProSHADE_exception ( "The LAPACK complex SVD algorithm did not converge!", "EL00022", __FILE__, __LINE__, __func__, "LAPACK algorithm for computing the singular value\n : decomposition of complex matrices did not converge and\n : therefore it was not possible to optimise the peak\n : positions in the (self-)rotation function. Changing the\n : resolution may help, contact me if this error persists." );
919  }
920  if ( ( returnValue != 0 ) && ( !fail ) )
921  {
922  uAndV[0] = -777.7;
923  return ;
924  }
925 
926  //================================================ Save U
927  for ( proshade_signed rowIt = 0; rowIt < dim; rowIt++ )
928  {
929  for ( proshade_signed colIt = 0; colIt < dim; colIt++ )
930  {
931  uAndV[(rowIt*3)+colIt] = rotMatU[( rowIt * 3 ) + colIt];
932  }
933  }
934 
935  //================================================ Save V
936  for ( proshade_signed rowIt = 0; rowIt < dim; rowIt++ )
937  {
938  for ( proshade_signed colIt = 0; colIt < dim; colIt++ )
939  {
940  uAndV[(rowIt*3)+colIt+9] = rotMatV[( rowIt * 3 ) + colIt];
941  }
942  }
943 
944  //================================================ Release the rest of the memory
945  delete[] rotMatU;
946  delete[] rotMatV;
947 
948  //================================================ Done
949  return ;
950 
951 }
952 
966 void ProSHADE_internal_maths::getEulerZYZFromSOFTPosition ( proshade_signed band, proshade_signed x, proshade_signed y, proshade_signed z, proshade_double* eulerAlpha, proshade_double* eulerBeta, proshade_double* eulerGamma )
967 {
968  //================================================ Convert index to Euler angles
969  *eulerAlpha = M_PI * static_cast<proshade_double> ( y ) / ( static_cast<proshade_double> ( band ) ) ;
970  *eulerBeta = M_PI * ( 2.0 * static_cast<proshade_double> ( x ) ) / ( 4.0 * static_cast<proshade_double> ( band ) ) ;
971  *eulerGamma = M_PI * static_cast<proshade_double> ( z ) / ( static_cast<proshade_double> ( band ) ) ;
972 
973  //================================================ Done
974  return ;
975 
976 }
977 
991 void ProSHADE_internal_maths::getSOFTPositionFromEulerZYZ ( proshade_signed band, proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double* x, proshade_double* y, proshade_double* z )
992 {
993  //================================================ Convert Euler angles to indices
994  *x = ( eulerBeta * static_cast<proshade_double> ( band ) * 2.0 ) / M_PI;
995  *y = ( eulerGamma * static_cast<proshade_double> ( band ) ) / M_PI;
996  *z = ( eulerAlpha * static_cast<proshade_double> ( band ) ) / M_PI;
997 
998  //================================================ Keep value within boundaries
999  if ( *x >= ( 2.0 * static_cast<proshade_double> ( band - 1 ) ) ) { *x = ( 2.0 * static_cast<proshade_double> ( band ) ) - 1.0; }
1000  if ( *y >= ( 2.0 * static_cast<proshade_double> ( band - 1 ) ) ) { *y = ( 2.0 * static_cast<proshade_double> ( band ) ) - 1.0; }
1001  if ( *z >= ( 2.0 * static_cast<proshade_double> ( band - 1 ) ) ) { *z = ( 2.0 * static_cast<proshade_double> ( band ) ) - 1.0; }
1002 
1003  if ( *x < 0.0 ) { *x = 0.0; }
1004  if ( *y < 0.0 ) { *y = 0.0; }
1005  if ( *z < 0.0 ) { *z = 0.0; }
1006 
1007  //================================================ Done
1008  return ;
1009 
1010 }
1011 
1019 void ProSHADE_internal_maths::getRotationMatrixFromEulerZYZAngles ( proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double* matrix )
1020 {
1021  //================================================ First row
1022  matrix[0] = cos ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) - sin ( eulerAlpha ) * sin ( eulerGamma );
1023  matrix[1] = sin ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) + cos ( eulerAlpha ) * sin ( eulerGamma );
1024  matrix[2] = -sin ( eulerBeta ) * cos ( eulerGamma );
1025 
1026  //================================================ Second row
1027  matrix[3] = -cos ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) - sin ( eulerAlpha ) * cos ( eulerGamma );
1028  matrix[4] = -sin ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) + cos ( eulerAlpha ) * cos ( eulerGamma );
1029  matrix[5] = sin ( eulerBeta ) * sin ( eulerGamma );
1030 
1031  //================================================ Third row
1032  matrix[6] = cos ( eulerAlpha ) * sin ( eulerBeta );
1033  matrix[7] = sin ( eulerAlpha ) * sin ( eulerBeta );
1034  matrix[8] = cos ( eulerBeta );
1035 
1036  //================================================ Done
1037  return ;
1038 
1039 }
1040 
1048 void ProSHADE_internal_maths::getRotationMatrixFromEulerZYZAngles ( proshade_single eulerAlpha, proshade_single eulerBeta, proshade_single eulerGamma, proshade_single* matrix )
1049 {
1050  //================================================ First row
1051  matrix[0] = cos ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) - sin ( eulerAlpha ) * sin ( eulerGamma );
1052  matrix[1] = sin ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) + cos ( eulerAlpha ) * sin ( eulerGamma );
1053  matrix[2] = -sin ( eulerBeta ) * cos ( eulerGamma );
1054 
1055  //================================================ Second row
1056  matrix[3] = -cos ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) - sin ( eulerAlpha ) * cos ( eulerGamma );
1057  matrix[4] = -sin ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) + cos ( eulerAlpha ) * cos ( eulerGamma );
1058  matrix[5] = sin ( eulerBeta ) * sin ( eulerGamma );
1059 
1060  //================================================ Third row
1061  matrix[6] = cos ( eulerAlpha ) * sin ( eulerBeta );
1062  matrix[7] = sin ( eulerAlpha ) * sin ( eulerBeta );
1063  matrix[8] = cos ( eulerBeta );
1064 
1065  //================================================ Done
1066  return ;
1067 
1068 }
1069 
1083  void ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( proshade_double* rotMat, proshade_double* x, proshade_double* y, proshade_double* z, proshade_double* ang, proshade_signed verbose )
1084 {
1085  //================================================ Initialise
1086  proshade_double angleTolerance = 0.01;
1087  proshade_double closeToZero = 0.0000001;
1088 
1089  //================================================ Find the angle
1090  *ang = std::acos ( ( std::max ( -1.0, std::min ( 3.0, rotMat[0] + rotMat[4] + rotMat[8] ) ) - 1.0 ) / 2.0 );
1091 
1092  //================================================ Any singularity?
1093  if ( std::abs ( std::sin ( *ang ) ) < angleTolerance )
1094  {
1095  //============================================ Initialise local variables
1096  char jobLeftEigs = 'N'; // This tells LAPACK not to compute left eigenvectors.
1097  char jobRightEigs = 'V'; // This tells LAPACK to compute right eigenvectors.
1098  int dim = 3; // The order of the matrix
1099  double* eigValReal = new double[dim]; // Real parts of the eigenvalues
1100  double* eigValImag = new double[dim]; // Imaginary parts of the eigenvalues
1101  double* leftEigVectors = new double[dim*dim*2]; // Left eigenvectors containing matrix
1102  double* rightEigVectors = new double[dim*dim*2]; // Right eigenvectors containing matrix
1103  double* work = new double[10*4*dim]; // Workspace. 4 * dim should be minimum, but more is better
1104  int workSize = 10*4*dim; // Saving the work array size for passing.
1105  int returnValue = 0; // This will tell if operation succeeded
1106 
1107  //============================================ Check memory allocation
1108  ProSHADE_internal_misc::checkMemoryAllocation ( eigValReal, __FILE__, __LINE__, __func__ );
1109  ProSHADE_internal_misc::checkMemoryAllocation ( eigValImag, __FILE__, __LINE__, __func__ );
1110  ProSHADE_internal_misc::checkMemoryAllocation ( leftEigVectors, __FILE__, __LINE__, __func__ );
1111  ProSHADE_internal_misc::checkMemoryAllocation ( rightEigVectors, __FILE__, __LINE__, __func__ );
1112  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
1113 
1114  //============================================ Load input data into array in column-major order
1115  double* matrixToDecompose = new double[dim*dim];
1116  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
1117  for ( int rowIt = 0; rowIt < dim; rowIt++ )
1118  {
1119  for ( int colIt = 0; colIt < dim; colIt++ )
1120  {
1121  matrixToDecompose[(colIt*dim)+rowIt] = static_cast< double > ( rotMat[(rowIt*dim)+colIt] );
1122  }
1123  }
1124 
1125  //============================================ Run LAPACK ZGESDD
1126  dgeev_ ( &jobLeftEigs, &jobRightEigs, &dim, matrixToDecompose, &dim, eigValReal, eigValImag, leftEigVectors, &dim,
1127  rightEigVectors, &dim, work, &workSize, &returnValue );
1128 
1129  //============================================ Check for errors
1130  if ( returnValue != 0 )
1131  {
1132  //======================================== Report error and return zero values
1133  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! Eigenval/Eigenvector algorithm did not converge.", "WS00069" );
1134  *x = 0.0;
1135  *y = 0.0;
1136  *z = 0.0;
1137 
1138  //======================================== Release memory
1139  delete[] eigValReal;
1140  delete[] eigValImag;
1141  delete[] leftEigVectors;
1142  delete[] rightEigVectors;
1143  delete[] work;
1144  delete[] matrixToDecompose;
1145 
1146  //======================================== Done
1147  return ;
1148  }
1149 
1150  //============================================ If values are close to zero, just set them to zero
1151  for ( int i = 0; i < 9; i++ ) { if ( std::abs(rightEigVectors[i]) < closeToZero ) { rightEigVectors[i] = 0.0; } }
1152  for ( int i = 0; i < 3; i++ ) { if ( std::abs(eigValReal[i]) < closeToZero ) { eigValReal[i] = 0.0; } if ( std::abs(eigValImag[i]) < closeToZero ) { eigValImag[i] = 0.0; } }
1153 
1154  //============================================ Find which eigenvalue is close to 1 and has imaginary part close to zero
1155  proshade_signed eigIt = -1;
1156  for ( size_t it = 0; it < 3; it++ )
1157  {
1158  if ( ( eigValReal[it] > ( 1.0 - closeToZero ) ) && ( eigValReal[it] < ( 1.0 + closeToZero ) ) )
1159  {
1160  if ( ( eigValImag[it] > ( 0.0 - closeToZero ) ) && ( eigValImag[it] < ( 0.0 + closeToZero ) ) )
1161  {
1162  eigIt = static_cast< proshade_signed > ( it );
1163  break;
1164  }
1165  }
1166  }
1167 
1168  //============================================ Any axis found?
1169  if ( eigIt == -1 )
1170  {
1171  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! Failed to find eigenvalue with value 1 for this rotation matrix. Is this a rotation matrix?", "WS00072" );
1172  *x = 0.0;
1173  *y = 0.0;
1174  *z = 0.0;
1175  }
1176  else
1177  {
1178  //======================================== Parse LAPACK eigenvectors matrix
1179  int colIt;
1180  for( int rowIt = 0; rowIt < dim; rowIt++ )
1181  {
1182  colIt = 0;
1183  while( colIt < dim )
1184  {
1185  if( std::abs ( eigValImag[colIt] ) < closeToZero )
1186  {
1187  if ( colIt == eigIt ) { if ( rowIt == 0 ) { *x = rightEigVectors[rowIt+colIt*dim]; } if ( rowIt == 1 ) { *y = rightEigVectors[rowIt+colIt*dim]; } if ( rowIt == 2 ) { *z = rightEigVectors[rowIt+colIt*dim]; } }
1188  colIt++;
1189  }
1190  else
1191  {
1192 // In order to access the
1193 // std::cout << " ( " << rightEigVectors[rowIt+colIt*dim] << " + " << rightEigVectors[rowIt+(colIt+1)*dim] << " i )";
1194 // other eigenvectors, use this:
1195 // std::cout << " ( " << rightEigVectors[rowIt+colIt*dim] << " + " << -rightEigVectors[rowIt+(colIt+1)*dim] << " i )";
1196  colIt += 2;
1197  }
1198  }
1199  }
1200  }
1201 
1202  //============================================ Normalise axis length
1203  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1204  *x /= normFactor;
1205  *y /= normFactor;
1206  *z /= normFactor;
1207 
1208 
1209  //============================================ Free memory
1210  delete[] eigValReal;
1211  delete[] eigValImag;
1212  delete[] leftEigVectors;
1213  delete[] rightEigVectors;
1214  delete[] work;
1215  delete[] matrixToDecompose;
1216  }
1217  else
1218  {
1219  //============================================= Axis
1220  *x = rotMat[7] - rotMat[5];
1221  *y = rotMat[2] - rotMat[6];
1222  *z = rotMat[3] - rotMat[1];
1223 
1224  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1225  *x /= normFactor;
1226  *y /= normFactor;
1227  *z /= normFactor;
1228 
1229  //============================================= Make sure largest axis is positive
1230  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1231  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1232  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1233  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1234  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1235  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1236  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1237  {
1238  *x *= -1.0;
1239  *y *= -1.0;
1240  *z *= -1.0;
1241  *ang *= -1.0;
1242  }
1243  }
1244 
1245  //================================================ Standardise angle to range 0 to 2pi
1246  if ( *ang < 0.0 ) { *ang = ( 2.0 * M_PI ) + *ang; }
1247 
1248  //================================================ Done
1249  return ;
1250 
1251 }
1252 
1266  void ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( std::vector< proshade_double >* rotMat, proshade_double* x, proshade_double* y, proshade_double* z, proshade_double* ang, proshade_signed verbose )
1267 {
1268  //================================================ Initialise
1269  proshade_double angleTolerance = 0.01;
1270  proshade_double closeToZero = 0.0000001;
1271 
1272  //================================================ Find the angle
1273  *ang = std::acos ( ( std::max ( -1.0, std::min ( 3.0, rotMat->at(0) + rotMat->at(4) + rotMat->at(8) ) ) - 1.0 ) / 2.0 );
1274 
1275  //================================================ Any singularity?
1276  if ( std::abs ( std::sin ( *ang ) ) < angleTolerance )
1277  {
1278  //============================================ Initialise local variables
1279  char jobLeftEigs = 'N'; // This tells LAPACK not to compute left eigenvectors.
1280  char jobRightEigs = 'V'; // This tells LAPACK to compute right eigenvectors.
1281  int dim = 3; // The order of the matrix
1282  double* eigValReal = new double[dim]; // Real parts of the eigenvalues
1283  double* eigValImag = new double[dim]; // Imaginary parts of the eigenvalues
1284  double* leftEigVectors = new double[dim*dim*2]; // Left eigenvectors containing matrix
1285  double* rightEigVectors = new double[dim*dim*2]; // Right eigenvectors containing matrix
1286  double* work = new double[10*4*dim]; // Workspace. 4 * dim should be minimum, but more is better
1287  int workSize = 10*4*dim; // Saving the work array size for passing.
1288  int returnValue = 0; // This will tell if operation succeeded
1289 
1290  //============================================ Check memory allocation
1291  ProSHADE_internal_misc::checkMemoryAllocation ( eigValReal, __FILE__, __LINE__, __func__ );
1292  ProSHADE_internal_misc::checkMemoryAllocation ( eigValImag, __FILE__, __LINE__, __func__ );
1293  ProSHADE_internal_misc::checkMemoryAllocation ( leftEigVectors, __FILE__, __LINE__, __func__ );
1294  ProSHADE_internal_misc::checkMemoryAllocation ( rightEigVectors, __FILE__, __LINE__, __func__ );
1295  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
1296 
1297  //============================================ Load input data into array in column-major order
1298  double* matrixToDecompose = new double[dim*dim];
1299  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
1300  for ( int rowIt = 0; rowIt < dim; rowIt++ )
1301  {
1302  for ( int colIt = 0; colIt < dim; colIt++ )
1303  {
1304  matrixToDecompose[(colIt*dim)+rowIt] = static_cast< double > ( rotMat->at( static_cast< size_t > ( ( rowIt * dim ) + colIt ) ) );
1305  }
1306  }
1307 
1308  //============================================ Run LAPACK ZGESDD
1309  dgeev_ ( &jobLeftEigs, &jobRightEigs, &dim, matrixToDecompose, &dim, eigValReal, eigValImag, leftEigVectors, &dim,
1310  rightEigVectors, &dim, work, &workSize, &returnValue );
1311 
1312  //============================================ Check for errors
1313  if ( returnValue != 0 )
1314  {
1315  //======================================== Report error and return zero values
1316  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! Eigenval/Eigenvector algorithm did not converge.", "WS00069" );
1317  *x = 0.0;
1318  *y = 0.0;
1319  *z = 0.0;
1320 
1321  //======================================== Release memory
1322  delete[] eigValReal;
1323  delete[] eigValImag;
1324  delete[] leftEigVectors;
1325  delete[] rightEigVectors;
1326  delete[] work;
1327  delete[] matrixToDecompose;
1328 
1329  //======================================== Done
1330  return ;
1331  }
1332 
1333  //============================================ If values are close to zero, just set them to zero
1334  for ( int i = 0; i < 9; i++ ) { if ( std::abs(rightEigVectors[i]) < closeToZero ) { rightEigVectors[i] = 0.0; } }
1335  for ( int i = 0; i < 3; i++ ) { if ( std::abs(eigValReal[i]) < closeToZero ) { eigValReal[i] = 0.0; } if ( std::abs(eigValImag[i]) < closeToZero ) { eigValImag[i] = 0.0; } }
1336 
1337  //============================================ Find which eigenvalue is close to 1 and has imaginary part close to zero
1338  proshade_signed eigIt = -1;
1339  for ( size_t it = 0; it < 3; it++ )
1340  {
1341  if ( ( eigValReal[it] > ( 1.0 - closeToZero ) ) && ( eigValReal[it] < ( 1.0 + closeToZero ) ) )
1342  {
1343  if ( ( eigValImag[it] > ( 0.0 - closeToZero ) ) && ( eigValImag[it] < ( 0.0 + closeToZero ) ) )
1344  {
1345  eigIt = static_cast< proshade_signed > ( it );
1346  break;
1347  }
1348  }
1349  }
1350 
1351  //============================================ Any axis found?
1352  if ( eigIt == -1 )
1353  {
1354  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! Failed to find eigenvalue with value 1 for this rotation matrix. Is this a rotation matrix?", "WS00072" );
1355  *x = 0.0;
1356  *y = 0.0;
1357  *z = 0.0;
1358  }
1359  else
1360  {
1361  //======================================== Parse LAPACK eigenvectors matrix
1362  int colIt;
1363  for( int rowIt = 0; rowIt < dim; rowIt++ )
1364  {
1365  colIt = 0;
1366  while( colIt < dim )
1367  {
1368  if( std::abs ( eigValImag[colIt] ) < closeToZero )
1369  {
1370  if ( colIt == eigIt ) { if ( rowIt == 0 ) { *x = rightEigVectors[rowIt+colIt*dim]; } if ( rowIt == 1 ) { *y = rightEigVectors[rowIt+colIt*dim]; } if ( rowIt == 2 ) { *z = rightEigVectors[rowIt+colIt*dim]; } }
1371  colIt++;
1372  }
1373  else
1374  {
1375 // In order to access the
1376 // std::cout << " ( " << rightEigVectors[rowIt+colIt*dim] << " + " << rightEigVectors[rowIt+(colIt+1)*dim] << " i )";
1377 // other eigenvectors, use this:
1378 // std::cout << " ( " << rightEigVectors[rowIt+colIt*dim] << " + " << -rightEigVectors[rowIt+(colIt+1)*dim] << " i )";
1379  colIt += 2;
1380  }
1381  }
1382  }
1383  }
1384 
1385  //============================================ Normalise axis length
1386  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1387  *x /= normFactor;
1388  *y /= normFactor;
1389  *z /= normFactor;
1390 
1391  //============================================= Make sure largest axis is positive
1392  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1393  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1394  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1395  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1396  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1397  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1398  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1399  {
1400  *x *= -1.0;
1401  *y *= -1.0;
1402  *z *= -1.0;
1403  *ang *= -1.0;
1404  }
1405 
1406  //================================================ Free memory
1407  delete[] eigValReal;
1408  delete[] eigValImag;
1409  delete[] leftEigVectors;
1410  delete[] rightEigVectors;
1411  delete[] work;
1412  delete[] matrixToDecompose;
1413  }
1414  else
1415  {
1416  //============================================= Axis
1417  *x = rotMat->at(7) - rotMat->at(5);
1418  *y = rotMat->at(2) - rotMat->at(6);
1419  *z = rotMat->at(3) - rotMat->at(1);
1420 
1421  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1422  *x /= normFactor;
1423  *y /= normFactor;
1424  *z /= normFactor;
1425 
1426  //============================================= Make sure largest axis is positive
1427  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1428  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1429  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1430  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1431  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1432  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1433  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1434  {
1435  *x *= -1.0;
1436  *y *= -1.0;
1437  *z *= -1.0;
1438  *ang *= -1.0;
1439  }
1440  }
1441 
1442  //================================================ Standardise angle to range 0 to 2pi
1443  if ( *ang < 0.0 ) { *ang = ( 2.0 * M_PI ) + *ang; }
1444 
1445  //================================================ Done
1446  return ;
1447 
1448 }
1449 
1458 void ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( proshade_double* rotMat, proshade_double x, proshade_double y, proshade_double z, proshade_double ang )
1459 {
1460  //================================================ If angle is 0 or infinity (anything divided by 0), return identity matrix
1461  if ( ( ang == 0.0 ) || ( std::isinf ( ang ) ) )
1462  {
1463  //============================================ Create identity
1464  for ( proshade_unsign i = 0; i < 9; i++ ) { rotMat[i] = 0.0; }
1465  rotMat[0] = 1.0;
1466  rotMat[4] = 1.0;
1467  rotMat[8] = 1.0;
1468 
1469  //============================================ Done
1470  return ;
1471  }
1472 
1473  //================================================ Compute the matrix
1474  proshade_double cAng = cos ( ang );
1475  proshade_double sAng = sin ( ang );
1476  proshade_double tAng = 1.0 - cAng;
1477 
1478  rotMat[0] = cAng + x * x * tAng;
1479  rotMat[4] = cAng + y * y * tAng;
1480  rotMat[8] = cAng + z * z * tAng;
1481 
1482  proshade_double tmp1 = x * y * tAng;
1483  proshade_double tmp2 = z * sAng;
1484  rotMat[3] = tmp1 + tmp2;
1485  rotMat[1] = tmp1 - tmp2;
1486 
1487  tmp1 = x * z * tAng;
1488  tmp2 = y * sAng;
1489  rotMat[6] = tmp1 - tmp2;
1490  rotMat[2] = tmp1 + tmp2;
1491 
1492  tmp1 = y * z * tAng;
1493  tmp2 = x * sAng;
1494  rotMat[7] = tmp1 + tmp2;
1495  rotMat[5] = tmp1 - tmp2;
1496 
1497  //================================================ Done
1498  return ;
1499 
1500 }
1501 
1510 void ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( proshade_single* rotMat, proshade_double x, proshade_double y, proshade_double z, proshade_double ang )
1511 {
1512  //================================================ If angle is 0 or infinity (anything divided by 0), return identity matrix
1513  if ( ( ang == 0.0 ) || ( std::isinf ( ang ) ) )
1514  {
1515  //============================================ Create identity
1516  for ( size_t i = 0; i < 9; i++ ) { rotMat[i] = 0.0f; }
1517  rotMat[0] = 1.0f;
1518  rotMat[4] = 1.0f;
1519  rotMat[8] = 1.0f;
1520 
1521  //============================================ Done
1522  return ;
1523  }
1524 
1525  //================================================ Compute the matrix
1526  proshade_single cAng = cos ( static_cast< proshade_single > ( ang ) );
1527  proshade_single sAng = sin ( static_cast< proshade_single > ( ang ) );
1528  proshade_single tAng = 1.0f - cAng;
1529 
1530  rotMat[0] = cAng + static_cast< proshade_single > ( x ) * static_cast< proshade_single > ( x ) * tAng;
1531  rotMat[4] = cAng + static_cast< proshade_single > ( y ) * static_cast< proshade_single > ( y ) * tAng;
1532  rotMat[8] = cAng + static_cast< proshade_single > ( z ) * static_cast< proshade_single > ( z ) * tAng;
1533 
1534  proshade_single tmp1 = static_cast< proshade_single > ( x ) * static_cast< proshade_single > ( y ) * tAng;
1535  proshade_single tmp2 = static_cast< proshade_single > ( z ) * sAng;
1536  rotMat[3] = tmp1 + tmp2;
1537  rotMat[1] = tmp1 - tmp2;
1538 
1539  tmp1 = static_cast< proshade_single > ( x ) * static_cast< proshade_single > ( z ) * tAng;
1540  tmp2 = static_cast< proshade_single > ( y ) * sAng;
1541  rotMat[6] = tmp1 - tmp2;
1542  rotMat[2] = tmp1 + tmp2;
1543 
1544  tmp1 = static_cast< proshade_single > ( y ) * static_cast< proshade_single > ( z ) * tAng;
1545  tmp2 = static_cast< proshade_single > ( x ) * sAng;
1546  rotMat[7] = tmp1 + tmp2;
1547  rotMat[5] = tmp1 - tmp2;
1548 
1549  //================================================ Done
1550  return ;
1551 
1552 }
1553 
1561 void ProSHADE_internal_maths::getEulerZYZFromRotMatrix ( proshade_double* rotMat, proshade_double* eA, proshade_double* eB, proshade_double* eG )
1562 {
1563  //================================================ Convert to Eulers
1564  if ( std::abs( rotMat[8] ) < 0.99999 )
1565  {
1566  //============================================ This case occurs when there is no singularity in the rotation matrix (i.e. it does not have 0 or 180 degrees angle)
1567  *eA = std::atan2 ( rotMat[7], rotMat[6] );
1568  *eB = std::acos ( rotMat[8] );
1569  *eG = std::atan2 ( rotMat[5], -rotMat[2] );
1570  }
1571  else
1572  {
1573  //============================================ This case occurs when there is either 0 or 180 degrees rotation angle in the rotation matrix and therefore when beta is zero.
1574  if ( rotMat[8] >= 0.99999 )
1575  {
1576  //======================================== In this case, beta = 0 and alpha and gamma are only defined in terms of their sum. So we arbitrarily set gamma to 0 and solve alpha.
1577  *eA = std::atan2 ( rotMat[3], rotMat[0] );
1578  *eB = 0.0;
1579  *eG = 0.0;
1580  }
1581  if ( rotMat[8] <= -0.99999 )
1582  {
1583  //======================================== In this case, beta = PI and alpha and gamma are only defined in terms of their difference. So we arbitrarily set gamma to 0 and solve alpha.
1584  *eA = std::atan2 ( rotMat[3], rotMat[0] );
1585  *eB = M_PI;
1586  *eG = 0.0;
1587  }
1588  }
1589 
1590  //================================================ Get the angles to proper range
1591  if ( *eA < 0.0 ) { *eA = 2.0 * M_PI + *eA; }
1592  if ( *eB < 0.0 ) { *eB = M_PI + *eB; }
1593  if ( *eG < 0.0 ) { *eG = 2.0 * M_PI + *eG; }
1594 
1595  //================================================ Done
1596  return ;
1597 
1598 }
1599 
1612 void ProSHADE_internal_maths::getEulerZYZFromAngleAxis ( proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double axAng, proshade_double* eA, proshade_double* eB, proshade_double* eG )
1613 {
1614  //================================================ If angle is 0 or infinity (anything divided by 0), return no rotation
1615  if ( ( axAng == 0.0 ) || ( std::isinf ( axAng ) ) )
1616  {
1617  //============================================ Return 0 ; 0 ; 0 for no angle
1618  *eA = 0.0;
1619  *eB = 0.0;
1620  *eG = 0.0;
1621 
1622  //============================================ Done
1623  return ;
1624  }
1625 
1626  //================================================ Compute required rotation matrix elements
1627  proshade_double cAng = std::cos ( axAng );
1628  proshade_double sAng = std::sin ( axAng );
1629  proshade_double tAng = 1.0 - cAng;
1630 
1631  proshade_double element22 = cAng + axZ * axZ * tAng;
1632 
1633  proshade_double tmp1 = axX * axZ * tAng;
1634  proshade_double tmp2 = axY * sAng;
1635  proshade_double element20 = tmp1 - tmp2;
1636  proshade_double element02 = tmp1 + tmp2;
1637 
1638  tmp1 = axY * axZ * tAng;
1639  tmp2 = axX * sAng;
1640  proshade_double element21 = tmp1 + tmp2;
1641  proshade_double element12 = tmp1 - tmp2;
1642 
1643  //================================================ Convert to Eulers
1644  if ( std::abs( element22 ) <= 0.99999 )
1645  {
1646  //============================================ This case occurs when there is no singularity in the rotation matrix (i.e. it does not have 0 or 180 degrees angle)
1647  *eA = std::atan2 ( element21, element20 );
1648  *eB = std::acos ( element22 );
1649  *eG = std::atan2 ( element12, -element02 );
1650  }
1651  else
1652  {
1653  //============================================ Compute some extra rotation matrix elements
1654  proshade_double element10 = ( axX * axY * tAng ) + ( axZ * sAng );
1655  proshade_double element11 = cAng + axY * axY * tAng;
1656 
1657  //============================================ This case occurs when there is either 0 or 180 degrees rotation angle in the rotation matrix and therefore when beta is zero.
1658  if ( element22 >= 0.99999 )
1659  {
1660  //======================================== In this case, beta = 0 and alpha and gamma are only defined in terms of their sum. So we arbitrarily set gamma to 0 and solve alpha.
1661  *eA = std::atan2 ( element10, element11 );
1662  *eB = 0.0;
1663  *eG = 0.0;
1664  }
1665  if ( element22 <= -0.99999 )
1666  {
1667  //======================================== In this case, beta = PI and alpha and gamma are only defined in terms of their difference. So we arbitrarily set gamma to 0 and solve alpha.
1668  *eA = -std::atan2 ( element10, element11 );
1669  *eB = M_PI;
1670  *eG = 0.0;
1671  }
1672  }
1673 
1674  //================================================ Get the angles to proper range
1675  if ( *eA < 0.0 ) { *eA = 2.0 * M_PI + *eA; }
1676  if ( *eB < 0.0 ) { *eB = M_PI + *eB; }
1677  if ( *eG < 0.0 ) { *eG = 2.0 * M_PI + *eG; }
1678 
1679  //================================================ Done
1680  return ;
1681 
1682 }
1683 
1693 void ProSHADE_internal_maths::multiplyTwoSquareMatrices ( proshade_double* A, proshade_double* B, proshade_double* res, proshade_unsign dim )
1694 {
1695  //================================================ Set res to 0.0s
1696  for ( proshade_unsign iter = 0; iter < 9; iter++ ) { res[iter] = 0.0; }
1697 
1698  //================================================ Compute the matrix multiplication
1699  for ( proshade_unsign row = 0; row < dim; row++ )
1700  {
1701  for ( proshade_unsign col = 0; col < dim; col++ )
1702  {
1703  for ( proshade_unsign inner = 0; inner < dim; inner++ )
1704  {
1705  res[(row*dim)+col] += A[(inner*dim)+row] * B[(col*dim)+inner];
1706  }
1707  }
1708  }
1709 
1710  //================================================ Done
1711  return ;
1712 
1713 }
1714 
1719 std::vector < proshade_signed > ProSHADE_internal_maths::primeFactorsDecomp ( proshade_signed number )
1720 {
1721  //================================================ Initialise variables
1722  std::vector < proshade_signed > ret;
1723 
1724  //================================================ Deal with negative numbers
1725  bool changeSign = false;
1726  if ( number < 0 ) { changeSign = true; number = -number; }
1727 
1728  //================================================ Deal with zero and one
1729  if ( number == 0 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, 0 ); return ( ret ); }
1730  if ( number == 1 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, 1 ); return ( ret ); }
1731 
1732  //================================================ Divide by 2 as long as you can
1733  while ( number % 2 == 0 )
1734  {
1736  number = number / 2;
1737  }
1738 
1739  //================================================ Check all odd numbers up to the square root
1740  for ( proshade_double posDiv = 3; posDiv <= sqrt ( static_cast< proshade_double > ( number ) ); posDiv += 2.0 )
1741  {
1742  // If posDiv is a divisor of the number, save the result
1743  while ( number % static_cast< proshade_signed > ( posDiv ) == 0 )
1744  {
1745  ProSHADE_internal_misc::addToSignedVector ( &ret, static_cast< proshade_signed > ( posDiv ) );
1746  number = number / static_cast< proshade_signed > ( posDiv );
1747  }
1748  }
1749 
1750  //================================================ If the number was a large prime number, save it as it is
1751  if ( number > 2 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, number ); }
1752 
1753  //================================================ Finish dealing with negative numbers
1754  if ( changeSign ) { ret.at(0) = -ret.at(0); }
1755 
1756  //================================================ Done
1757  return ( ret );
1758 
1759 }
1760 
1768 proshade_double ProSHADE_internal_maths::normalDistributionValue ( proshade_double mean, proshade_double standardDev, proshade_double value )
1769 {
1770  //================================================ Compute and return
1771  return ( ( 1.0 / sqrt ( 2.0 * M_PI * pow(standardDev,2.0) ) ) * std::exp ( - pow( value - mean, 2.0 ) / 2.0 * pow(standardDev,2.0) ) );
1772 
1773 }
1774 
1785 proshade_double ProSHADE_internal_maths::computeDotProduct ( proshade_double* x1, proshade_double* y1, proshade_double* z1, proshade_double* x2, proshade_double* y2, proshade_double* z2 )
1786 {
1787  //================================================ Compute and return
1788  return ( (*x1 * *x2) + (*y1 * *y2) + (*z1 * *z2) );
1789 }
1790 
1801 proshade_double ProSHADE_internal_maths::computeDotProduct ( proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2 )
1802 {
1803  //================================================ Compute and return
1804  return ( (x1 * x2) + (y1 * y2) + (z1 * z2) );
1805 }
1806 
1817 proshade_double* ProSHADE_internal_maths::computeCrossProduct ( proshade_double* x1, proshade_double* y1, proshade_double* z1, proshade_double* x2, proshade_double* y2, proshade_double* z2 )
1818 {
1819  //================================================ Allocate memory
1820  proshade_double* crossProd = new proshade_double[3];
1821  ProSHADE_internal_misc::checkMemoryAllocation ( crossProd, __FILE__, __LINE__, __func__ );
1822 
1823  //================================================ Compute
1824  crossProd[0] = ( (*y1) * (*z2) ) - ( (*z1) * (*y2) );
1825  crossProd[1] = ( (*z1) * (*x2) ) - ( (*x1) * (*z2) );
1826  crossProd[2] = ( (*x1) * (*y2) ) - ( (*y1) * (*x2) );
1827 
1828  //================================================ Done
1829  return ( crossProd );
1830 
1831 }
1832 
1843 proshade_double* ProSHADE_internal_maths::computeCrossProduct ( proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2 )
1844 {
1845  //================================================ Allocate memory
1846  proshade_double* crossProd = new proshade_double[3];
1847  ProSHADE_internal_misc::checkMemoryAllocation ( crossProd, __FILE__, __LINE__, __func__ );
1848 
1849  //================================================ Compute
1850  crossProd[0] = ( y1 * z2 ) - ( z1 * y2 );
1851  crossProd[1] = ( z1 * x2 ) - ( x1 * z2 );
1852  crossProd[2] = ( x1 * y2 ) - ( y1 * x2 );
1853 
1854  //================================================ Done
1855  return ( crossProd );
1856 
1857 }
1858 
1865 proshade_double* ProSHADE_internal_maths::compute3x3MatrixMultiplication ( proshade_double* mat1, proshade_double* mat2 )
1866 {
1867  //================================================ Allocate memory
1868  proshade_double* ret = new proshade_double[9];
1869  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1870 
1871  //================================================ Multiply
1872  ret[0] = ( mat1[0] * mat2[0] ) + ( mat1[1] * mat2[3] ) + ( mat1[2] * mat2[6] );
1873  ret[1] = ( mat1[0] * mat2[1] ) + ( mat1[1] * mat2[4] ) + ( mat1[2] * mat2[7] );
1874  ret[2] = ( mat1[0] * mat2[2] ) + ( mat1[1] * mat2[5] ) + ( mat1[2] * mat2[8] );
1875  ret[3] = ( mat1[3] * mat2[0] ) + ( mat1[4] * mat2[3] ) + ( mat1[5] * mat2[6] );
1876  ret[4] = ( mat1[3] * mat2[1] ) + ( mat1[4] * mat2[4] ) + ( mat1[5] * mat2[7] );
1877  ret[5] = ( mat1[3] * mat2[2] ) + ( mat1[4] * mat2[5] ) + ( mat1[5] * mat2[8] );
1878  ret[6] = ( mat1[6] * mat2[0] ) + ( mat1[7] * mat2[3] ) + ( mat1[8] * mat2[6] );
1879  ret[7] = ( mat1[6] * mat2[1] ) + ( mat1[7] * mat2[4] ) + ( mat1[8] * mat2[7] );
1880  ret[8] = ( mat1[6] * mat2[2] ) + ( mat1[7] * mat2[5] ) + ( mat1[8] * mat2[8] );
1881 
1882  //================================================ Done
1883  return ( ret );
1884 
1885 }
1886 
1895 proshade_double* ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( proshade_double* mat, proshade_double x, proshade_double y, proshade_double z )
1896 {
1897  //================================================ Allocate memory
1898  proshade_double* ret = new proshade_double[3];
1899  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1900 
1901  //================================================ Compute the multiplication
1902  ret[0] = ( x * mat[0] ) + ( y * mat[1] ) + ( z * mat[2] );
1903  ret[1] = ( x * mat[3] ) + ( y * mat[4] ) + ( z * mat[5] );
1904  ret[2] = ( x * mat[6] ) + ( y * mat[7] ) + ( z * mat[8] );
1905 
1906  //================================================ Done
1907  return ( ret );
1908 
1909 }
1910 
1919 proshade_single* ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( proshade_single* mat, proshade_single x, proshade_single y, proshade_single z )
1920 {
1921  //================================================ Allocate memory
1922  proshade_single* ret = new proshade_single[3];
1923  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1924 
1925  //================================================ Compute the multiplication
1926  ret[0] = ( x * mat[0] ) + ( y * mat[1] ) + ( z * mat[2] );
1927  ret[1] = ( x * mat[3] ) + ( y * mat[4] ) + ( z * mat[5] );
1928  ret[2] = ( x * mat[6] ) + ( y * mat[7] ) + ( z * mat[8] );
1929 
1930  //================================================ Done
1931  return ( ret );
1932 
1933 }
1934 
1940 proshade_double* ProSHADE_internal_maths::compute3x3MatrixInverse ( proshade_double* mat )
1941 {
1942  //================================================ Allocate memory
1943  proshade_double* inverse = new proshade_double[9];
1944  ProSHADE_internal_misc::checkMemoryAllocation ( inverse, __FILE__, __LINE__, __func__ );
1945 
1946  //================================================ Compute determinant
1947  proshade_double matDet = ( mat[0] * mat[4] * mat[8] ) +
1948  ( mat[1] * mat[5] * mat[6] ) +
1949  ( mat[2] * mat[3] * mat[7] ) -
1950  ( mat[0] * mat[5] * mat[7] ) -
1951  ( mat[1] * mat[3] * mat[8] ) -
1952  ( mat[2] * mat[4] * mat[6] );
1953 
1954  //================================================ Compute inverse matrix
1955  inverse[0] = ( mat[4] * mat[8] - mat[5] * mat[7] ) / matDet;
1956  inverse[1] = ( mat[2] * mat[7] - mat[1] * mat[8] ) / matDet;
1957  inverse[2] = ( mat[1] * mat[5] - mat[2] * mat[4] ) / matDet;
1958  inverse[3] = ( mat[5] * mat[6] - mat[3] * mat[8] ) / matDet;
1959  inverse[4] = ( mat[0] * mat[8] - mat[2] * mat[6] ) / matDet;
1960  inverse[5] = ( mat[2] * mat[3] - mat[0] * mat[5] ) / matDet;
1961  inverse[6] = ( mat[3] * mat[7] - mat[4] * mat[6] ) / matDet;
1962  inverse[7] = ( mat[1] * mat[6] - mat[0] * mat[7] ) / matDet;
1963  inverse[8] = ( mat[0] * mat[4] - mat[1] * mat[3] ) / matDet;
1964 
1965  //================================================ Done
1966  return ( inverse );
1967 }
1968 
1974 {
1975  //================================================ Initialise variables
1976  proshade_single tmp;
1977 
1978  //================================================ Transpose the non-diagonal values
1979  tmp = mat[1];
1980  mat[1] = mat[3];
1981  mat[3] = tmp;
1982 
1983  tmp = mat[2];
1984  mat[2] = mat[6];
1985  mat[6] = tmp;
1986 
1987  tmp = mat[5];
1988  mat[5] = mat[7];
1989  mat[7] = tmp;
1990 
1991  //================================================ Done
1992  return ;
1993 
1994 }
1995 
2001 {
2002  //================================================ Initialise variables
2003  proshade_double tmp;
2004 
2005  //================================================ Transpose the non-diagonal values
2006  tmp = mat[1];
2007  mat[1] = mat[3];
2008  mat[3] = tmp;
2009 
2010  tmp = mat[2];
2011  mat[2] = mat[6];
2012  mat[6] = tmp;
2013 
2014  tmp = mat[5];
2015  mat[5] = mat[7];
2016  mat[7] = tmp;
2017 
2018  //================================================ Done
2019  return ;
2020 
2021 }
2022 
2028 proshade_double* ProSHADE_internal_maths::build3x3MatrixFromDiag ( proshade_double* diag )
2029 {
2030  //================================================ Allocate memory
2031  proshade_double* ret = new proshade_double[9];
2032  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
2033 
2034  //================================================ Build
2035  ret[0] = diag[0];
2036  ret[1] = 0.0;
2037  ret[2] = 0.0;
2038  ret[3] = 0.0;
2039  ret[4] = diag[1];
2040  ret[5] = 0.0;
2041  ret[6] = 0.0;
2042  ret[7] = 0.0;
2043  ret[8] = diag[2];
2044 
2045  //================================================ Done
2046  return ( ret );
2047 
2048 }
2049 
2057 proshade_double* ProSHADE_internal_maths::build3x3MatrixFromXYZRotations ( proshade_double xRot, proshade_double yRot, proshade_double zRot )
2058 {
2059  //================================================ Allocate memory
2060  proshade_double* ret = new proshade_double[9];
2061  proshade_double* XRM = new proshade_double[9];
2062  proshade_double* YRM = new proshade_double[9];
2063  proshade_double* ZRM = new proshade_double[9];
2064  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
2065  ProSHADE_internal_misc::checkMemoryAllocation ( XRM, __FILE__, __LINE__, __func__ );
2066  ProSHADE_internal_misc::checkMemoryAllocation ( YRM, __FILE__, __LINE__, __func__ );
2067  ProSHADE_internal_misc::checkMemoryAllocation ( ZRM, __FILE__, __LINE__, __func__ );
2068 
2069  //================================================ Convert to radians
2070  proshade_double xRad = xRot * ( M_PI / 180.0 );
2071  proshade_double yRad = yRot * ( M_PI / 180.0 );
2072  proshade_double zRad = zRot * ( M_PI / 180.0 );
2073 
2074  //================================================ Build the X, Y and Z rotation matrices
2075  XRM[0] = 1.0; XRM[1] = 0.0; XRM[2] = 0.0;
2076  XRM[3] = 0.0; XRM[4] = std::cos ( xRad ); XRM[5] = -std::sin ( xRad );
2077  XRM[6] = 0.0; XRM[7] = std::sin ( xRad ); XRM[8] = std::cos ( xRad );
2078 
2079  YRM[0] = std::cos ( yRad ); YRM[1] = 0.0; YRM[2] = std::sin ( yRad );
2080  YRM[3] = 0.0; YRM[4] = 1.0; YRM[5] = 0.0;
2081  YRM[6] = -std::sin ( yRad ); YRM[7] = 0.0; YRM[8] = std::cos ( yRad );
2082 
2083  ZRM[0] = std::cos ( zRad ); ZRM[1] = -std::sin ( zRad ); ZRM[2] = 0.0;
2084  ZRM[3] = std::sin ( zRad ); ZRM[4] = std::cos ( zRad ); ZRM[5] = 0.0;
2085  ZRM[6] = 0.0; ZRM[7] = 0.0; ZRM[8] = 1.0;
2086 
2087  //================================================ Multiply in XYZ order
2088  proshade_double* tmpMat = compute3x3MatrixMultiplication ( XRM, YRM );
2089  ret = compute3x3MatrixMultiplication ( tmpMat, ZRM );
2090 
2091  //================================================ Release memory
2092  delete[] tmpMat;
2093  delete[] XRM;
2094  delete[] YRM;
2095  delete[] ZRM;
2096 
2097  //================================================ Done
2098  return ( ret );
2099 
2100 }
2101 
2119 proshade_double* ProSHADE_internal_maths::findRotMatMatchingVectors ( proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2 )
2120 {
2121  //================================================ Allocate required memory
2122  proshade_double* inPlaneRotation = new proshade_double[9];
2123  proshade_double* basisChangeMat = new proshade_double[9];
2124  ProSHADE_internal_misc::checkMemoryAllocation ( inPlaneRotation, __FILE__, __LINE__, __func__ );
2125  ProSHADE_internal_misc::checkMemoryAllocation ( basisChangeMat, __FILE__, __LINE__, __func__ );
2126 
2127  //================================================ Normalise inputs
2128  proshade_double normF = std::sqrt( std::pow( x1, 2.0 ) + std::pow ( y1, 2.0 ) + std::pow ( z1, 2.0 ) );
2129  x1 /= normF; y1 /= normF; z1 /= normF;
2130 
2131  normF = std::sqrt( std::pow( x2, 2.0 ) + std::pow ( y2, 2.0 ) + std::pow ( z2, 2.0 ) );
2132  x2 /= normF; y2 /= normF; z2 /= normF;
2133 
2134  //================================================ Compute cross product's magnitude
2135  proshade_double* crossProd = ProSHADE_internal_maths::computeCrossProduct( &x1, &y1, &z1, &x2, &y2, &z2 );
2136  proshade_double crossProdMag = std::sqrt( std::pow( crossProd[0], 2.0 ) + std::pow ( crossProd[1], 2.0 ) + std::pow ( crossProd[2], 2.0 ) );
2137  delete[] crossProd;
2138 
2139  //================================================ Compute dot product
2140  proshade_double dotProd = ProSHADE_internal_maths::computeDotProduct ( &x1, &y1, &z1, &x2, &y2, &z2 );
2141 
2142  //================================================ Construct the in-plane rotation matrix
2143  inPlaneRotation[0] = dotProd; inPlaneRotation[1] = -crossProdMag; inPlaneRotation[2] = 0.0;
2144  inPlaneRotation[3] = crossProdMag; inPlaneRotation[4] = dotProd; inPlaneRotation[5] = 0.0;
2145  inPlaneRotation[6] = 0.0; inPlaneRotation[7] = 0.0; inPlaneRotation[8] = 1.0;
2146 
2147  //================================================ Construct change of basis matrix
2148  crossProd = ProSHADE_internal_maths::computeCrossProduct( &x2, &y2, &z2, &x1, &y1, &z1 );
2149  normF = std::sqrt ( std::pow ( x2 - ( dotProd * x1 ), 2.0 ) + std::pow ( y2 - ( dotProd * y1 ), 2.0 ) + std::pow ( z2 - ( dotProd * z1 ), 2.0 ) );
2150 
2151  basisChangeMat[0] = x1; basisChangeMat[1] = ( x2 - ( dotProd * x1 ) ) / normF; basisChangeMat[2] = crossProd[0];
2152  basisChangeMat[3] = y1; basisChangeMat[4] = ( y2 - ( dotProd * y1 ) ) / normF; basisChangeMat[5] = crossProd[1];
2153  basisChangeMat[6] = z1; basisChangeMat[7] = ( z2 - ( dotProd * z1 ) ) / normF; basisChangeMat[8] = crossProd[2];
2154 
2155  //================================================ Invert the change of basis matrix
2156  proshade_double* basisChangeMatInverse = ProSHADE_internal_maths::compute3x3MatrixInverse ( basisChangeMat );
2157 
2158  //================================================ Multiply inverse of change of basis matrix with the in plane rotation matrix, then multiply the result with the inverse
2159  proshade_double* tmpMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( basisChangeMat, inPlaneRotation );
2160  proshade_double* rotMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( tmpMat, basisChangeMatInverse );
2161 
2162  //================================================ Release memory
2163  delete[] crossProd;
2164  delete[] inPlaneRotation;
2165  delete[] basisChangeMat;
2166  delete[] basisChangeMatInverse;
2167  delete[] tmpMat;
2168 
2169  //================================================ Done
2170  return ( rotMat );
2171 
2172 }
2173 
2186 proshade_double* ProSHADE_internal_maths::compute3x3MoorePenrosePseudoInverseOfIMinusMat ( std::vector < proshade_double >* rMat, proshade_signed verbose )
2187 {
2188  //================================================ Initialise local variables and allocate the memory
2189  int dim = 3; // Number of dimensions
2190  char job = 'A'; // Save computation of parts of U and V matrices, they are not needed here
2191  double *singularValues = new double[dim]; // The array of singular values
2192  double *rotMatU = new double [dim*dim]; // The U matrix space
2193  double *rotMatV = new double [dim*dim]; // The V^T matrix space
2194  double *work = new double [static_cast< proshade_unsign >( ( 3 * dim ) + pow( dim, 2 ) * dim)]; // Workspace, minimum required is 4*dim^2 + 7*dim, using more for performance
2195  int workDim = static_cast< int > ( 2 * ( ( 4 * dim * dim ) + ( 7 * dim ) ) ); // Formalism stating just that
2196  double* rwork = new double[static_cast<proshade_unsign>((5 * dim) + 5 * pow(dim,2))]; // Required by LAPACK
2197  int* iwork = new int[(8 * dim)]; // Required by LAPACK
2198  int returnValue = 0; // This will tell if operation succeeded
2199  double *matrixToDecompose = new double[dim*dim];
2200 
2201  //================================================ Check the memory allocation
2202  ProSHADE_internal_misc::checkMemoryAllocation ( singularValues, __FILE__, __LINE__, __func__ );
2203  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatU, __FILE__, __LINE__, __func__ );
2204  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatV, __FILE__, __LINE__, __func__ );
2205  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
2206  ProSHADE_internal_misc::checkMemoryAllocation ( rwork, __FILE__, __LINE__, __func__ );
2207  ProSHADE_internal_misc::checkMemoryAllocation ( iwork, __FILE__, __LINE__, __func__ );
2208  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
2209 
2210  //================================================ Load input data into array in column-major order
2211  for ( int rowIt = 0; rowIt < dim; rowIt++ )
2212  {
2213  for ( int colIt = 0; colIt < dim; colIt++ )
2214  {
2215  if ( rowIt == colIt ) { matrixToDecompose[(colIt*dim)+rowIt] = 1.0 - rMat->at( static_cast< size_t > ( ( rowIt * dim ) + colIt ) ); }
2216  else { matrixToDecompose[(colIt*dim)+rowIt] = 0.0 - rMat->at( static_cast< size_t > ( ( rowIt * dim ) + colIt ) ); }
2217  }
2218  }
2219 
2220  //================================================ Run LAPACK ZGESDD
2221  dgesdd_ ( &job, &dim, &dim, matrixToDecompose, &dim, singularValues, rotMatU, &dim, rotMatV, &dim,
2222  work, &workDim, rwork, iwork, &returnValue );
2223 
2224  //================================================ Check the convergence
2225  if ( returnValue != 0 )
2226  {
2227  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! SVD algorithm did not converge.", "WS00069" );
2228  }
2229 
2230  //================================================ Determine positivity
2231  bool anyPositive = false;
2232  std::vector< bool > positivityTest;
2233  for ( proshade_unsign it = 0; it < static_cast< proshade_unsign > ( dim ); it++ )
2234  {
2235  positivityTest.push_back ( singularValues[it] > 0.001 );
2236  if ( positivityTest.at(it) ) { anyPositive = true; }
2237  }
2238 
2239  //================================================ Compute according to positivity
2240  proshade_double* pseudoInverseMat;
2241  if ( anyPositive )
2242  {
2243  //============================================ Set all non-positive singular values and appropriate matrix rows/columns to zero
2244  if ( !positivityTest.at(0) )
2245  {
2246  singularValues[0] = 0.0;
2247  rotMatU[0] = 0.0;
2248  rotMatU[1] = 0.0;
2249  rotMatU[2] = 0.0;
2250  rotMatV[0] = 0.0;
2251  rotMatV[3] = 0.0;
2252  rotMatV[6] = 0.0;
2253  }
2254  else { singularValues[0] = 1.0 / singularValues[0]; }
2255 
2256  if ( !positivityTest.at(1) )
2257  {
2258  singularValues[1] = 0.0;
2259  rotMatU[3] = 0.0;
2260  rotMatU[4] = 0.0;
2261  rotMatU[5] = 0.0;
2262  rotMatV[1] = 0.0;
2263  rotMatV[4] = 0.0;
2264  rotMatV[7] = 0.0;
2265  }
2266  else { singularValues[1] = 1.0 / singularValues[1]; }
2267 
2268  if ( !positivityTest.at(2) )
2269  {
2270  singularValues[2] = 0.0;
2271  rotMatU[6] = 0.0;
2272  rotMatU[7] = 0.0;
2273  rotMatU[8] = 0.0;
2274  rotMatV[2] = 0.0;
2275  rotMatV[5] = 0.0;
2276  rotMatV[8] = 0.0;
2277  }
2278  else { singularValues[2] = 1.0 / singularValues[2]; }
2279 
2280  //============================================ All positive values formula
2281  proshade_double* diagMat = ProSHADE_internal_maths::build3x3MatrixFromDiag ( singularValues );
2282  proshade_double* hlpMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( diagMat, rotMatU );
2283  pseudoInverseMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( rotMatV, hlpMat );
2284 
2285  //============================================ Release memory
2286  delete[] diagMat;
2287  delete[] hlpMat;
2288  }
2289  else
2290  {
2291  //============================================ No axis in matrix
2292  pseudoInverseMat = new proshade_double[9];
2293  ProSHADE_internal_misc::checkMemoryAllocation ( pseudoInverseMat, __FILE__, __LINE__, __func__ );
2294 
2295  for ( size_t mIt = 0; mIt < 9; mIt++ ) { pseudoInverseMat[mIt] = 0.0; }
2296  }
2297 
2298  //================================================ Free memory
2299  delete[] work;
2300  delete[] rwork;
2301  delete[] iwork;
2302  delete[] matrixToDecompose;
2303  delete[] singularValues;
2304  delete[] rotMatU;
2305  delete[] rotMatV;
2306 
2307  //================================================ Done
2308  return ( pseudoInverseMat );
2309 
2310 }
2311 
2333 std::vector < proshade_double > ProSHADE_internal_maths::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 )
2334 {
2335  //================================================ Initialise variables
2336  std::vector < proshade_double > ret;
2337 
2338  //================================================ Solution
2339  proshade_double solX = ( -sqrt ( pow ( 2.0 * x1 * y1 * dot2 * y2 + 2.0 * x1 * z1 * dot2 * z2 - 2.0 * x1 * dot1 * pow ( y2, 2.0 ) - 2.0 * x1 * dot1 * pow ( z2, 2.0 ) - 2.0 * pow ( y1, 2.0 ) * dot2 * x2 + 2.0 * y1 * dot1 * x2 * y2 - 2.0 * pow ( z1, 2.0 ) * dot2 * x2 + 2.0 * z1 * dot1 * x2 * z2, 2.0 ) -
2340  4.0 * ( pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * x1 * y1 * x2 * y2 - 2.0 * x1 * z1 * x2 * z2 + pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) ) *
2341  ( pow ( y1, 2.0 ) * pow ( dot2, 2.0 ) - pow ( y1, 2.0 ) * pow ( z2, 2.0 ) + 2.0 * y1 * z1 * y2 * z2 - 2.0 * y1 * dot1 * dot2 * y2 + pow ( z1, 2.0 ) * pow ( dot2, 2.0 ) - pow ( z1, 2.0 ) * pow ( y2, 2.0 ) - 2.0 * z1 * dot1 * dot2 * z2 + pow ( dot1, 2.0 ) * pow ( y2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( z2, 2.0 ) ) ) -
2342  2.0 * x1 * y1 * dot2 * y2 - 2.0 * x1 * z1 * dot2 * z2 + 2.0 * x1 * dot1 * pow ( y2, 2.0 ) + 2.0 * x1 * dot1 * pow ( z2, 2.0 ) + 2.0 * pow ( y1, 2.0 ) * dot2 * x2 - 2.0 * y1 * dot1 * x2 * y2 + 2.0 * pow ( z1, 2.0 ) * dot2 * x2 - 2.0 * z1 * dot1 * x2 * z2 ) /
2343  ( 2.0 * ( pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * x1 * y1 * x2 * y2 - 2.0 * x1 * z1 * x2 * z2 + pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) ) );
2344  proshade_double solY = ( ( dot2 * pow ( x2, 2.0 ) * pow ( z1, 3.0 ) ) /
2345  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2346  ( dot1 * pow ( x2, 2.0 ) * z2 * pow ( z1, 2.0 ) ) /
2347  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2348  ( 2.0 * x1 * dot2 * x2 * z2 * pow ( z1, 2.0 ) ) /
2349  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) - dot2 * z1 -
2350  ( x2 * sqrt ( pow ( - 2.0 * dot2 * x2 * pow ( y1, 2.0 ) + 2.0 * x1 * dot2 * y2 * y1 + 2.0 * dot1 * x2 * y2 * y1 - 2.0 * x1 * dot1 * pow ( y2, 2.0 ) - 2.0 * x1 * dot1 * pow ( z2, 2.0 ) - 2.0 * pow ( z1, 2.0 ) * dot2 * x2 + 2.0 * x1 * z1 * dot2 * z2 + 2.0 * z1 * dot1 * x2 * z2, 2.0 ) -
2351  4.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) *
2352  ( pow ( y1, 2.0 ) * pow ( dot2, 2.0 ) + pow ( z1, 2.0 ) * pow ( dot2, 2.0 ) - 2.0 * y1 * dot1 * y2 * dot2 - 2.0 * z1 * dot1 * z2 * dot2 - pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( y2, 2.0 ) - pow ( y1, 2.0 ) * pow ( z2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( z2, 2.0 ) + 2.0 * y1 * z1 * y2 * z2 ) ) * z1 ) /
2353  ( 2.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2354  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) * z1 ) /
2355  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2356  ( x1 * dot1 * x2 * pow ( y2, 2.0 ) * z1 ) /
2357  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2358  ( pow ( x1, 2.0 ) * dot2 * pow ( z2, 2.0 ) * z1 ) /
2359  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2360  ( 2.0 * x1 * dot1 * x2 * pow ( z2, 2.0 ) * z1 ) /
2361  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2362  ( y1 * dot1 * pow ( x2, 2.0 ) * y2 * z1 ) /
2363  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2364  ( x1 * y1 * dot2 * x2 * y2 * z1 ) /
2365  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) + dot1 * z2 +
2366  ( x1 * z2 * sqrt ( pow ( -2.0 * dot2 * x2 * pow ( y1, 2.0 ) + 2.0 * x1 * dot2 * y2 * y1 + 2.0 * dot1 * x2 * y2 * y1 - 2.0 * x1 * dot1 * pow ( y2, 2.0 ) - 2.0 * x1 * dot1 * pow ( z2, 2.0 ) - 2.0 * pow ( z1, 2.0 ) * dot2 * x2 + 2.0 * x1 * z1 * dot2 * z2 + 2.0 * z1 * dot1 * x2 * z2, 2.0 ) -
2367  4.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) *
2368  ( pow ( y1, 2.0 ) * pow ( dot2, 2.0 ) + pow ( z1, 2.0 ) * pow ( dot2, 2.0 ) - 2.0 * y1 * dot1 * y2 * dot2 - 2.0 * z1 * dot1 * z2 * dot2 - pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( y2, 2.0 ) - pow ( y1, 2.0 ) * pow ( z2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( z2, 2.0 ) + 2.0 * y1 * z1 * y2 * z2 ) ) ) /
2369  ( 2.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2370  ( pow ( x1, 2.0 ) * dot1 * pow ( z2, 3.0 ) ) /
2371  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2372  ( pow ( x1, 2.0 ) * dot1 * pow ( y2, 2.0 ) * z2 ) /
2373  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2374  ( x1 * pow ( y1, 2.0 ) * dot2 * x2 * z2 ) /
2375  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2376  ( pow ( x1, 2.0 ) * y1 * dot2 * y2 * z2 ) /
2377  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2378  ( x1 * y1 * dot1 * x2 * y2 * z2 ) /
2379  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) / ( y1 * z2 - z1 * y2 );
2380  proshade_double solZ = ( - ( dot2 * pow ( x2, 2.0 ) * y2 * pow ( z1, 3.0 ) ) /
2381  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2382  ( dot2 * pow ( x2, 2.0 ) * pow ( z1, 2.0 ) ) /
2383  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2384  ( dot1 * pow ( x2, 2.0 ) * y2 * z2 * pow ( z1, 2.0 ) ) /
2385  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2386  ( 2.0 * x1 * dot2 * x2 * y2 * z2 * pow ( z1, 2.0 ) ) /
2387  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2388  ( x2 * y2 * sqrt ( pow ( -2.0 * dot2 * x2 * pow ( y1, 2.0 ) + 2.0 * x1 * dot2 * y2 * y1 + 2.0 * dot1 * x2 * y2 * y1 - 2.0 * x1 * dot1 * pow ( y2, 2.0 ) - 2.0 * x1 * dot1 * pow ( z2, 2.0 ) - 2.0 * pow ( z1, 2.0 ) * dot2 * x2 + 2.0 * x1 * z1 * dot2 * z2 + 2.0 * z1 * dot1 * x2 * z2, 2.0 ) -
2389  4.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) *
2390  ( pow ( y1, 2.0 ) * pow ( dot2, 2.0 ) + pow ( z1, 2.0 ) * pow ( dot2, 2.0 ) - 2.0 * y1 * dot1 * y2 * dot2 - 2.0 * z1 * dot1 * z2 * dot2 - pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( y2, 2.0 ) - pow ( y1, 2.0 ) * pow ( z2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( z2, 2.0 ) + 2.0 * y1 * z1 * y2 * z2 ) ) * z1 ) /
2391  ( 2.0 * ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2392  ( dot2 * y2 * z1 ) / ( y1 * z2 - z1 * y2 ) +
2393  ( dot1 * pow ( x2, 2.0 ) * z2 * z1 ) /
2394  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2395  ( x1 * dot2 * x2 * z2 * z1 ) /
2396  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2397  ( x1 * dot1 * x2 * pow ( y2, 3.0 ) * z1 ) /
2398  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2399  ( y1 * dot1 * pow ( x2, 2.0 ) * pow ( y2, 2.0 ) * z1 ) /
2400  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2401  ( x1 * y1 * dot2 * x2 * pow ( y2, 2.0 ) * z1 ) /
2402  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2403  ( pow ( x1, 2.0 ) * dot2 * y2 * pow ( z2, 2.0 ) * z1 ) /
2404  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2405  ( 2.0 * x1 * dot1 * x2 * y2 * pow ( z2, 2.0 ) * z1 ) /
2406  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2407  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) * y2 * z1 ) /
2408  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) + dot2 +
2409  ( x2 * sqrt ( pow ( - 2.0 * dot2 * x2 * pow ( y1, 2.0 ) + 2.0 * x1 * dot2 * y2 * y1 + 2.0 * dot1 * x2 * y2 * y1 - 2.0 * x1 * dot1 * pow ( y2, 2.0 ) - 2.0 * x1 * dot1 * pow ( z2, 2.0 ) - 2.0 * pow ( z1, 2.0 ) * dot2 * x2 + 2.0 * x1 * z1 * dot2 * z2 + 2.0 * z1 * dot1 * x2 * z2, 2.0 ) -
2410  4.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) *
2411  ( pow ( y1, 2.0 ) * pow ( dot2, 2.0 ) + pow ( z1, 2.0 ) * pow ( dot2, 2.0 ) - 2.0 * y1 * dot1 * y2 * dot2 - 2.0 * z1 * dot1 * z2 * dot2 - pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( y2, 2.0 ) - pow ( y1, 2.0 ) * pow ( z2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( z2, 2.0 ) + 2.0 * y1 * z1 * y2 * z2 ) ) ) /
2412  ( 2.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2413  ( x1 * y2 * z2 * sqrt ( pow ( - 2.0 * dot2 * x2 * pow ( y1, 2.0 ) + 2.0 * x1 * dot2 * y2 * y1 + 2.0 * dot1 * x2 * y2 * y1 - 2.0 * x1 * dot1 * pow ( y2, 2.0 ) - 2.0 * x1 * dot1 * pow ( z2, 2.0 ) - 2.0 * pow ( z1, 2.0 ) * dot2 * x2 + 2.0 * x1 * z1 * dot2 * z2 + 2.0 * z1 * dot1 * x2 * z2, 2.0 ) -
2414  4.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) *
2415  ( pow ( y1, 2.0 ) * pow ( dot2, 2.0 ) + pow ( z1, 2.0 ) * pow ( dot2, 2.0 ) - 2.0 * y1 * dot1 * y2 * dot2 - 2.0 * z1 * dot1 * z2 * dot2 - pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( y2, 2.0 ) - pow ( y1, 2.0 ) * pow ( z2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( z2, 2.0 ) + 2.0 * y1 * z1 * y2 * z2 ) ) ) /
2416  ( 2.0 * ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2417  ( dot1 * y2 * z2 ) / ( y1 * z2 - z1 * y2 ) -
2418  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) ) /
2419  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2420  ( x1 * dot1 * x2 * pow ( y2, 2.0 ) ) /
2421  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2422  ( x1 * dot1 * x2 * pow ( z2, 2.0 ) ) /
2423  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2424  ( y1 * dot1 * pow ( x2, 2.0 ) * y2 ) /
2425  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2426  ( x1 * y1 * dot2 * x2 * y2 ) /
2427  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2428  ( pow ( x1, 2.0 ) * dot1 * y2 * pow ( z2, 3.0 ) ) /
2429  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2430  ( pow ( x1, 2.0 ) * dot1 * pow ( y2, 3.0 ) * z2 ) /
2431  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2432  ( pow ( x1, 2.0 ) * y1 * dot2 * pow ( y2, 2.0 ) * z2 ) /
2433  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2434  ( x1 * y1 * dot1 * x2 * pow ( y2, 2.0 ) * z2 ) /
2435  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2436  ( x1 * pow ( y1, 2.0 ) * dot2 * x2 * y2 * z2 ) /
2437  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) ) / z2;
2438 
2439  //================================================ Set largest axis element to positive (ProSHADE standard)
2440  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) );
2441  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solX ) );
2442  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solY ) );
2443  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solZ ) );
2444  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( solX < 0.0 ) ) ||
2445  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( solY < 0.0 ) ) ||
2446  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( solZ < 0.0 ) ) ) { solX *= -1.0; solY *= -1.0; solZ *= -1.0; }
2447 
2448  //================================================ Save solutions
2452 
2453  //================================================ Done
2454  return ( ret );
2455 
2456 }
2457 
2479 std::vector < proshade_double > ProSHADE_internal_maths::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 )
2480 {
2481  //================================================ Initialise variables
2482  std::vector < proshade_double > ret;
2483 
2484  //================================================ Solution
2485  proshade_double solX = - ( y1 * dot2 * z3 - y1 * dot3 * z2 - z1 * dot2 * y3 + z1 * dot3 * y2 + dot1 * y3 * z2 - dot1 * z3 * y2 ) /
2486  ( -x1 * y3 * z2 + x1 * z3 * y2 + y1 * x3 * z2 - y1 * z3 * x2 - z1 * x3 * y2 + z1 * y3 * x2 );
2487  proshade_double solY = - ( x1 * dot2 * z3 - x1 * dot3 * z2 - z1 * dot2 * x3 + z1 * dot3 * x2 + dot1 * x3 * z2 - dot1 * z3 * x2 ) /
2488  ( x1 * y3 * z2 - x1 * z3 * y2 - y1 * x3 * z2 + y1 * z3 * x2 + z1 * x3 * y2 - z1 * y3 * x2 );
2489  proshade_double solZ = - ( x1 * dot2 * y3 - x1 * dot3 * y2 - y1 * dot2 * x3 + y1 * dot3 * x2 + dot1 * x3 * y2 - dot1 * y3 * x2 ) /
2490  ( -x1 * y3 * z2 + x1 * z3 * y2 + y1 * x3 * z2 - y1 * z3 * x2 - z1 * x3 * y2 + z1 * y3 * x2 );
2491 
2492  //================================================ Normalise the axis to magnitude 1
2493  proshade_double normFactor = sqrt ( pow ( solX, 2.0 ) + pow ( solY, 2.0 ) + pow ( solZ, 2.0 ) );
2494  solX /= normFactor;
2495  solY /= normFactor;
2496  solZ /= normFactor;
2497 
2498  //================================================ Set largest axis element to positive (ProSHADE standard)
2499  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) );
2500  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solX ) );
2501  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solY ) );
2502  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solZ ) );
2503  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( solX < 0.0 ) ) ||
2504  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( solY < 0.0 ) ) ||
2505  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( solZ < 0.0 ) ) ) { solX *= -1.0; solY *= -1.0; solZ *= -1.0; }
2506 
2507  //================================================ Save solutions
2511 
2512  //================================================ Done
2513  return ( ret );
2514 
2515 }
2516 
2523 std::vector< proshade_double > ProSHADE_internal_maths::multiplyGroupElementMatrices ( std::vector< proshade_double >* el1, std::vector< proshade_double >* el2 )
2524 {
2525  //================================================ Initialise variables
2526  std::vector< proshade_double > ret;
2527 
2528  //================================================ Compute
2529  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(0) ) +
2530  ( el1->at(1) * el2->at(3) ) +
2531  ( el1->at(2) * el2->at(6) ) );
2532  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(1) ) +
2533  ( el1->at(1) * el2->at(4) ) +
2534  ( el1->at(2) * el2->at(7) ) );
2535  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(2) ) +
2536  ( el1->at(1) * el2->at(5) ) +
2537  ( el1->at(2) * el2->at(8) ) );
2538 
2539  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(0) ) +
2540  ( el1->at(4) * el2->at(3) ) +
2541  ( el1->at(5) * el2->at(6) ) );
2542  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(1) ) +
2543  ( el1->at(4) * el2->at(4) ) +
2544  ( el1->at(5) * el2->at(7) ) );
2545  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(2) ) +
2546  ( el1->at(4) * el2->at(5) ) +
2547  ( el1->at(5) * el2->at(8) ) );
2548 
2549  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(0) ) +
2550  ( el1->at(7) * el2->at(3) ) +
2551  ( el1->at(8) * el2->at(6) ) );
2552  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(1) ) +
2553  ( el1->at(7) * el2->at(4) ) +
2554  ( el1->at(8) * el2->at(7) ) );
2555  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(2) ) +
2556  ( el1->at(7) * el2->at(5) ) +
2557  ( el1->at(8) * el2->at(8) ) );
2558 
2559  //================================================ Done
2560  return ( ret );
2561 
2562 }
2563 
2576 bool ProSHADE_internal_maths::rotationMatrixSimilarity ( std::vector< proshade_double >* mat1, std::vector< proshade_double >* mat2, proshade_double tolerance )
2577 {
2578  //================================================ Initialise variables
2579  bool ret = false;
2580 
2581  //================================================ Compare to tolerance
2582  if ( tolerance > std::abs ( ProSHADE_internal_maths::rotationMatrixSimilarityValue ( mat1, mat2 ) ) ) { ret = true; }
2583 
2584  //================================================ Done
2585  return ( ret );
2586 
2587 }
2588 
2601 bool ProSHADE_internal_maths::rotationMatrixSimilarity ( proshade_double* mat1, proshade_double* mat2, proshade_double tolerance )
2602 {
2603  //================================================ Initialise variables
2604  bool ret = false;
2605 
2606  //================================================ Compare to tolerance
2607  if ( tolerance > std::abs ( ProSHADE_internal_maths::rotationMatrixSimilarityValue ( mat1, mat2 ) ) ) { ret = true; }
2608 
2609  //================================================ Done
2610  return ( ret );
2611 
2612 }
2613 
2624 proshade_double ProSHADE_internal_maths::rotationMatrixSimilarityValue ( std::vector< proshade_double >* mat1, std::vector< proshade_double >* mat2 )
2625 {
2626  //================================================ Compute trace of mat1 * mat2^T
2627  proshade_double ret = ( mat1->at(0) * mat2->at(0) ) + ( mat1->at(1) * mat2->at(1) ) + ( mat1->at(2) * mat2->at(2) );
2628  ret += ( mat1->at(3) * mat2->at(3) ) + ( mat1->at(4) * mat2->at(4) ) + ( mat1->at(5) * mat2->at(5) );
2629  ret += ( mat1->at(6) * mat2->at(6) ) + ( mat1->at(7) * mat2->at(7) ) + ( mat1->at(8) * mat2->at(8) );
2630 
2631  //================================================ Subtract 3 (so that we would have 0 in case of identical matrices)
2632  ret -= 3.0;
2633 
2634  //================================================ Done
2635  return ( ret );
2636 
2637 }
2638 
2649 proshade_double ProSHADE_internal_maths::rotationMatrixSimilarityValue ( proshade_double* mat1, proshade_double* mat2 )
2650 {
2651  //================================================ Compute trace of mat1 * mat2^T
2652  proshade_double ret = ( mat1[0] * mat2[0] ) + ( mat1[1] * mat2[1] ) + ( mat1[2] * mat2[2] );
2653  ret += ( mat1[3] * mat2[3] ) + ( mat1[4] * mat2[4] ) + ( mat1[5] * mat2[5] );
2654  ret += ( mat1[6] * mat2[6] ) + ( mat1[7] * mat2[7] ) + ( mat1[8] * mat2[8] );
2655 
2656  //================================================ Subtract 3 (so that we would have 0 in case of identical matrices)
2657  ret -= 3.0;
2658 
2659  //================================================ Done
2660  return ( ret );
2661 
2662 }
2663 
2680 bool ProSHADE_internal_maths::vectorOrientationSimilarity ( proshade_double a1, proshade_double a2, proshade_double a3, proshade_double b1, proshade_double b2, proshade_double b3, proshade_double tolerance )
2681 {
2682  //================================================ Initialise variables
2683  bool ret = false;
2684 
2685  //================================================ Cosine distance
2686  proshade_double cosDist = ( ( a1 * b1 ) + ( a2 * b2 ) + ( a3 * b3 ) ) /
2687  ( sqrt( pow( a1, 2.0 ) + pow( a2, 2.0 ) + pow( a3, 2.0 ) ) *
2688  sqrt( pow( b1, 2.0 ) + pow( b2, 2.0 ) + pow( b3, 2.0 ) ) );
2689 
2690  //================================================ Compare the absolute value of distance to 1.0 - tolerance
2691  if ( std::abs( cosDist ) > ( 1.0 - tolerance ) ) { ret = true; }
2692 
2693  //================================================ Done
2694  return ( ret );
2695 
2696 }
2697 
2714 bool ProSHADE_internal_maths::vectorOrientationSimilaritySameDirection ( proshade_double a1, proshade_double a2, proshade_double a3, proshade_double b1, proshade_double b2, proshade_double b3, proshade_double tolerance )
2715 {
2716  //================================================ Initialise variables
2717  bool ret = false;
2718 
2719  //================================================ Cosine distance
2720  proshade_double cosDist = ( ( a1 * b1 ) + ( a2 * b2 ) + ( a3 * b3 ) ) /
2721  ( sqrt( pow( a1, 2.0 ) + pow( a2, 2.0 ) + pow( a3, 2.0 ) ) *
2722  sqrt( pow( b1, 2.0 ) + pow( b2, 2.0 ) + pow( b3, 2.0 ) ) );
2723 
2724  //================================================ Compare the absolute value of distance to 1.0 - tolerance
2725  if ( cosDist > ( 1.0 - tolerance ) ) { ret = true; }
2726 
2727  //================================================ Done
2728  return ( ret );
2729 
2730 }
2731 
2744 void ProSHADE_internal_maths::optimiseAxisBiCubicInterpolation ( proshade_double* bestLattitude, proshade_double* bestLongitude, proshade_double* bestSum, std::vector<proshade_unsign>* sphereList, std::vector<ProSHADE_internal_spheres::ProSHADE_rotFun_sphere*>* sphereMappedRotFun, proshade_double step )
2745 {
2746  //================================================ Initialise variables
2747  proshade_double lonM, lonP, latM, latP, movSum;
2748  std::vector<proshade_double> latVals ( 3 );
2749  std::vector<proshade_double> lonVals ( 3 );
2750  proshade_double learningRate = 0.1;
2751  proshade_double prevVal = *bestSum;
2752  proshade_double valChange = 999.9;
2753  proshade_double origBestLat = std::round ( *bestLattitude );
2754  proshade_double origBestLon = std::round ( *bestLongitude );
2755  proshade_double tmpVal;
2756 
2757  //================================================ Initialise interpolators in all directions around the point of interest
2758  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsMinusMinus;
2759  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsMinusPlus;
2760  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsPlusMinus;
2761  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsPlusPlus;
2762  prepareBiCubicInterpolatorsMinusMinus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsMinusMinus, sphereMappedRotFun );
2763  prepareBiCubicInterpolatorsMinusPlus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsMinusPlus, sphereMappedRotFun );
2764  prepareBiCubicInterpolatorsPlusMinus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsPlusMinus, sphereMappedRotFun );
2765  prepareBiCubicInterpolatorsPlusPlus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsPlusPlus, sphereMappedRotFun );
2766 
2767  //================================================ Start the pseudo gradient ascent (while there is some change)
2768  while ( valChange > 0.0001 )
2769  {
2770  //============================================ Find the surrounding points to the currently best position
2771  lonM = *bestLongitude - step;
2772  lonP = *bestLongitude + step;
2773  latM = *bestLattitude - step;
2774  latP = *bestLattitude + step;
2775 
2776  //============================================ Deal with optimising outside of prepared range - recursion
2777  const FloatingPoint< proshade_double > lhs1 ( *bestLattitude ), rhs1 ( origBestLat - 1.0 );
2778  const FloatingPoint< proshade_double > lhs2 ( *bestLattitude ), rhs2 ( origBestLat + 1.0 );
2779  const FloatingPoint< proshade_double > lhs3 ( *bestLongitude ), rhs3 ( origBestLon - 1.0 );
2780  const FloatingPoint< proshade_double > lhs4 ( *bestLongitude ), rhs4 ( origBestLon + 1.0 );
2781  if ( latM < ( origBestLat - 1.0 ) ) { tmpVal = *bestLattitude; *bestLattitude = origBestLat - 1.0; optimiseAxisBiCubicInterpolation ( bestLattitude, bestLongitude, bestSum, sphereList, sphereMappedRotFun, step ); if ( lhs1.AlmostEquals ( rhs1 ) ) { *bestLattitude = tmpVal; } break; }
2782  if ( latP > ( origBestLat + 1.0 ) ) { tmpVal = *bestLattitude; *bestLattitude = origBestLat + 1.0; optimiseAxisBiCubicInterpolation ( bestLattitude, bestLongitude, bestSum, sphereList, sphereMappedRotFun, step ); if ( lhs2.AlmostEquals ( rhs2 ) ) { *bestLattitude = tmpVal; } break; }
2783  if ( lonM < ( origBestLon - 1.0 ) ) { tmpVal = *bestLongitude; *bestLongitude = origBestLon - 1.0; optimiseAxisBiCubicInterpolation ( bestLattitude, bestLongitude, bestSum, sphereList, sphereMappedRotFun, step ); if ( lhs3.AlmostEquals ( rhs3 ) ) { *bestLongitude = tmpVal; } break; }
2784  if ( lonP > ( origBestLon + 1.0 ) ) { tmpVal = *bestLongitude; *bestLongitude = origBestLon + 1.0; optimiseAxisBiCubicInterpolation ( bestLattitude, bestLongitude, bestSum, sphereList, sphereMappedRotFun, step ); if ( lhs4.AlmostEquals ( rhs4 ) ) { *bestLongitude = tmpVal; } break; }
2785 
2786  //============================================ Prepare vectors of tested positions
2787  latVals.at(0) = latM; latVals.at(1) = *bestLattitude; latVals.at(2) = latP;
2788  lonVals.at(0) = lonM; lonVals.at(1) = *bestLongitude; lonVals.at(2) = lonP;
2789 
2790  //============================================ Find the best change
2791  for ( proshade_unsign laIt = 0; laIt < static_cast<proshade_unsign> ( latVals.size() ); laIt++ )
2792  {
2793  for ( proshade_unsign loIt = 0; loIt < static_cast<proshade_unsign> ( lonVals.size() ); loIt++ )
2794  {
2795  //==================================== For this combination of lat and lon, find sum over spheres
2796  movSum = 1.0;
2797  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sphereList->size() ); iter++ )
2798  {
2799  //================================ Interpolate using correct interpolators
2800  if ( ( latVals.at(laIt) <= origBestLat ) && ( lonVals.at(loIt) <= origBestLon ) ) { movSum += interpolsMinusMinus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2801  if ( ( latVals.at(laIt) <= origBestLat ) && ( lonVals.at(loIt) > origBestLon ) ) { movSum += interpolsMinusPlus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2802  if ( ( latVals.at(laIt) > origBestLat ) && ( lonVals.at(loIt) <= origBestLon ) ) { movSum += interpolsPlusMinus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2803  if ( ( latVals.at(laIt) > origBestLat ) && ( lonVals.at(loIt) > origBestLon ) ) { movSum += interpolsPlusPlus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2804  }
2805 
2806  //==================================== If position has improved, save it
2807  if ( *bestSum < movSum )
2808  {
2809  *bestSum = movSum;
2810  *bestLongitude = lonVals.at(loIt);
2811  *bestLattitude = latVals.at(laIt);
2812  }
2813  }
2814  }
2815 
2816  //============================================ Prepare for next iteration
2817  valChange = std::floor ( 100000.0 * ( *bestSum - prevVal ) ) / 100000.0;
2818  prevVal = std::floor ( 100000.0 * ( *bestSum ) ) / 100000.0;
2819  step = std::min ( 0.2, std::max ( ( valChange / step ) * learningRate, 0.01 ) );
2820  if ( learningRate >= 0.02 ) { learningRate -= 0.01; }
2821  }
2822 
2823  //================================================ Release interpolators memory
2824  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsMinusMinus.size() ); intIt++ ) { delete interpolsMinusMinus.at(intIt); }
2825  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsMinusPlus.size() ); intIt++ ) { delete interpolsMinusPlus.at(intIt); }
2826  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsPlusMinus.size() ); intIt++ ) { delete interpolsPlusMinus.at(intIt); }
2827  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsPlusPlus.size() ); intIt++ ) { delete interpolsPlusPlus.at(intIt); }
2828 
2829  //================================================ Done
2830  return ;
2831 }
2832 
2844 void ProSHADE_internal_maths::prepareBiCubicInterpolatorsMinusMinus ( proshade_double bestLattitude, proshade_double bestLongitude, std::vector<proshade_unsign>* sphereList, std::vector<ProSHADE_internal_maths::BicubicInterpolator*>* interpols, std::vector<ProSHADE_internal_spheres::ProSHADE_rotFun_sphere*>* sphereMappedRotFun )
2845 {
2846  //================================================ Initialise local variables
2847  proshade_signed latHlp, lonHlp;
2848  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2849 
2850  //================================================ Prepare the interpolator objects for interpolation around the position
2851  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2852  {
2853  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2854  proshade_double** interpGrid = new proshade_double*[4];
2855  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2856 
2857  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2858  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2859  {
2860  interpGrid[iter] = new proshade_double[4];
2861  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2862  }
2863 
2864  //============================================ Fill in the value grid on which the interpolation is to be done
2865  for ( proshade_signed latIt = 0; latIt < 4; latIt++ )
2866  {
2867  for ( proshade_signed lonIt = 0; lonIt < 4; lonIt++ )
2868  {
2869  latHlp = static_cast< proshade_signed > ( bestLattitude - 2.0 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2870  lonHlp = static_cast< proshade_signed > ( bestLongitude - 2.0 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2871  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2872  }
2873  }
2874 
2875  //============================================ Create the interpolators
2876  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude - 1.0, bestLongitude - 1.0 );
2877  interpols->emplace_back ( biCubInterp );
2878 
2879  //============================================ Release memory
2880  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2881  delete[] interpGrid;
2882  }
2883 
2884  //================================================ Done
2885  return ;
2886 }
2887 
2899 void ProSHADE_internal_maths::prepareBiCubicInterpolatorsMinusPlus ( proshade_double bestLattitude, proshade_double bestLongitude, std::vector<proshade_unsign>* sphereList, std::vector<ProSHADE_internal_maths::BicubicInterpolator*>* interpols, std::vector<ProSHADE_internal_spheres::ProSHADE_rotFun_sphere*>* sphereMappedRotFun )
2900 {
2901  //================================================ Initialise local variables
2902  proshade_signed latHlp, lonHlp;
2903  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2904 
2905  //================================================ Prepare the interpolator objects for interpolation around the position
2906  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2907  {
2908  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2909  proshade_double** interpGrid = new proshade_double*[4];
2910  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2911 
2912  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2913  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2914  {
2915  interpGrid[iter] = new proshade_double[4];
2916  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2917  }
2918 
2919  //============================================ Fill in the value grid on which the interpolation is to be done
2920  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2921  {
2922  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2923  {
2924  latHlp = static_cast< proshade_signed > ( bestLattitude - 2 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2925  lonHlp = static_cast< proshade_signed > ( bestLongitude - 1 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2926  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ) , static_cast< proshade_unsign > ( lonHlp ) );
2927  }
2928  }
2929 
2930  //============================================ Create the interpolators
2931  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude - 1.0, bestLongitude );
2932  interpols->emplace_back ( biCubInterp );
2933 
2934  //============================================ Release memory
2935  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2936  delete[] interpGrid;
2937  }
2938 
2939  //================================================ Done
2940  return ;
2941 }
2942 
2954 void ProSHADE_internal_maths::prepareBiCubicInterpolatorsPlusMinus ( proshade_double bestLattitude, proshade_double bestLongitude, std::vector<proshade_unsign>* sphereList, std::vector<ProSHADE_internal_maths::BicubicInterpolator*>* interpols, std::vector<ProSHADE_internal_spheres::ProSHADE_rotFun_sphere*>* sphereMappedRotFun )
2955 {
2956  //================================================ Initialise local variables
2957  proshade_signed latHlp, lonHlp;
2958  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2959 
2960  //================================================ Prepare the interpolator objects for interpolation around the position
2961  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2962  {
2963  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2964  proshade_double** interpGrid = new proshade_double*[4];
2965  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2966 
2967  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2968  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2969  {
2970  interpGrid[iter] = new proshade_double[4];
2971  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2972  }
2973 
2974  //============================================ Fill in the value grid on which the interpolation is to be done
2975  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2976  {
2977  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2978  {
2979  latHlp = static_cast< proshade_signed > ( bestLattitude - 1 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2980  lonHlp = static_cast< proshade_signed > ( bestLongitude - 2 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2981  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2982  }
2983  }
2984 
2985  //============================================ Create the interpolators
2986  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude, bestLongitude - 1.0 );
2987  interpols->emplace_back ( biCubInterp );
2988 
2989  //============================================ Release memory
2990  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2991  delete[] interpGrid;
2992  }
2993 
2994  //================================================ Done
2995  return ;
2996 }
2997 
3009 void ProSHADE_internal_maths::prepareBiCubicInterpolatorsPlusPlus ( proshade_double bestLattitude, proshade_double bestLongitude, std::vector<proshade_unsign>* sphereList, std::vector<ProSHADE_internal_maths::BicubicInterpolator*>* interpols, std::vector<ProSHADE_internal_spheres::ProSHADE_rotFun_sphere*>* sphereMappedRotFun )
3010 {
3011  //================================================ Initialise local variables
3012  proshade_signed latHlp, lonHlp;
3013  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
3014 
3015  //================================================ Prepare the interpolator objects for interpolation around the position
3016  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
3017  {
3018  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
3019  proshade_double** interpGrid = new proshade_double*[4];
3020  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
3021 
3022  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
3023  for ( proshade_unsign iter = 0; iter < 4; iter++ )
3024  {
3025  interpGrid[iter] = new proshade_double[4];
3026  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
3027  }
3028 
3029  //============================================ Fill in the value grid on which the interpolation is to be done
3030  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
3031  {
3032  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
3033  {
3034  latHlp = static_cast< proshade_signed > ( bestLattitude - 1 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
3035  lonHlp = static_cast< proshade_signed > ( bestLongitude - 1 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
3036  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
3037  }
3038  }
3039 
3040  //============================================ Create the interpolators
3041  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude, bestLongitude );
3042  interpols->emplace_back ( biCubInterp );
3043 
3044  //============================================ Release memory
3045  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
3046  delete[] interpGrid;
3047  }
3048 
3049  //================================================ Done
3050  return ;
3051 }
3052 
3064 bool ProSHADE_internal_maths::isAxisUnique ( std::vector< proshade_double* >* CSymList, proshade_double* axis, proshade_double tolerance, bool improve )
3065 {
3066  //================================================ Initialise variables
3067  bool ret = true;
3068  proshade_unsign whichImprove = 0;
3069 
3070  //================================================ For each already detected member
3071  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
3072  {
3073  //============================================ Is fold the same?
3074  const FloatingPoint< proshade_double > lhs ( CSymList->at(grIt)[0] ), rhs ( axis[0] );
3075  if ( lhs.AlmostEquals ( rhs ) )
3076  {
3077  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], axis[1], axis[2], axis[3], tolerance ) )
3078  {
3079  ret = false;
3080  whichImprove = grIt;
3081  break;
3082  }
3083  }
3084  }
3085 
3086  //================================================ Improve, if required
3087  if ( improve && !ret )
3088  {
3089  if ( axis[5] > CSymList->at(whichImprove)[5] )
3090  {
3091  CSymList->at(whichImprove)[1] = axis[1];
3092  CSymList->at(whichImprove)[2] = axis[2];
3093  CSymList->at(whichImprove)[3] = axis[3];
3094  CSymList->at(whichImprove)[4] = axis[4];
3095  CSymList->at(whichImprove)[5] = axis[5];
3096  }
3097  }
3098 
3099  //================================================ Done
3100  return ( ret );
3101 
3102 }
3103 
3116 bool ProSHADE_internal_maths::isAxisUnique ( std::vector< proshade_double* >* CSymList, proshade_double X, proshade_double Y, proshade_double Z, proshade_double fold, proshade_double tolerance )
3117 {
3118  //================================================ Initialise variables
3119  bool ret = true;
3120 
3121  //================================================ For each already detected member
3122  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
3123  {
3124  const FloatingPoint< proshade_double > lhs ( fold ), rhs ( CSymList->at(grIt)[0] );
3125  if ( lhs.AlmostEquals ( rhs ) )
3126  {
3127  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], X, Y, Z, tolerance ) )
3128  {
3129  ret = false;
3130  break;
3131  }
3132  }
3133  }
3134 
3135  //================================================ Done
3136  return ( ret );
3137 
3138 }
3139 
3150 proshade_signed ProSHADE_internal_maths::whichAxisUnique ( std::vector< proshade_double* >* CSymList, proshade_double* axis, proshade_double tolerance )
3151 {
3152  //================================================ Initialise variables
3153  proshade_signed ret = -1;
3154 
3155  //================================================ For each already detected member
3156  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
3157  {
3158  //============================================ Is fold the same?
3159  const FloatingPoint< proshade_double > lhs ( CSymList->at(grIt)[0] ), rhs ( axis[0] );
3160  if ( lhs.AlmostEquals ( rhs ) )
3161  {
3162  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], axis[1], axis[2], axis[3], tolerance ) )
3163  {
3164  ret = static_cast< proshade_signed > ( grIt );
3165  break;
3166  }
3167  }
3168  }
3169 
3170  //================================================ Done
3171  return ( ret );
3172 
3173 }
3174 
3186 proshade_signed ProSHADE_internal_maths::whichAxisUnique ( std::vector< proshade_double* >* CSymList, proshade_double X, proshade_double Y, proshade_double Z, proshade_double fold, proshade_double tolerance )
3187 {
3188  //================================================ Initialise variables
3189  proshade_signed ret = -1;
3190 
3191  //================================================ For each already detected member
3192  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
3193  {
3194  const FloatingPoint< proshade_double > lhs ( fold ), rhs ( CSymList->at(grIt)[0] );
3195  if ( lhs.AlmostEquals ( rhs ) )
3196  {
3197  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], X, Y, Z, tolerance ) )
3198  {
3199  ret = static_cast< proshade_signed > ( grIt );
3200  break;
3201  }
3202  }
3203  }
3204 
3205  //================================================ Done
3206  return ( ret );
3207 
3208 }
3209 
3218 std::vector< proshade_unsign > ProSHADE_internal_maths::findAllPrimes ( proshade_unsign upTo )
3219 {
3220  //================================================ Initialise variables
3221  std::vector< proshade_unsign > ret;
3222  std::vector< std::pair< proshade_unsign, bool > > sieveOfEratosthenesArray;
3223 
3224  //================================================ Sanity check
3225  if ( upTo < 2 ) { return ( ret ); }
3226 
3227  //================================================ Initialise the sieve array up to the required number
3228  for ( proshade_unsign iter = 2; iter <= upTo; iter++ ) { sieveOfEratosthenesArray.emplace_back ( std::pair< proshade_unsign, bool > ( iter, true ) ); }
3229 
3230  //================================================ For each entry in the array
3231  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); iter++ )
3232  {
3233  //============================================ If this entry is still true
3234  if ( sieveOfEratosthenesArray.at(iter).second )
3235  {
3236  //======================================== Set all entries with the position x * [this entry value] to false
3237  for ( proshade_unsign it = iter + sieveOfEratosthenesArray.at(iter).first; it < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); it += sieveOfEratosthenesArray.at(iter).first )
3238  {
3239  sieveOfEratosthenesArray.at(it).second = false;
3240  }
3241  }
3242  }
3243 
3244  //================================================ Copy passing results to return vector
3245  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); iter++ )
3246  {
3247  if ( sieveOfEratosthenesArray.at(iter).second ) { ProSHADE_internal_misc::addToUnsignVector ( &ret, sieveOfEratosthenesArray.at(iter).first ); }
3248  }
3249 
3250  //================================================ Done
3251  return ( ret );
3252 
3253 }
3254 
3259 bool ProSHADE_internal_maths::isPrime ( proshade_unsign toCheck )
3260 {
3261  //================================================ Initialise local variables
3262  bool ret = true;
3263 
3264  //================================================ Deal with exceptions
3265  if ( ( toCheck == 0 ) || ( toCheck == 1 ) ) { ret = false; return ( ret ); }
3266 
3267  //================================================ Naively test
3268  for ( proshade_unsign divider = 2; divider <= static_cast< proshade_unsign > ( std::round( toCheck / 2 ) ); divider++ )
3269  {
3270  if ( toCheck % divider == 0 ) { ret = false; break; }
3271  }
3272 
3273  //================================================ Done
3274  return ( ret );
3275 
3276 }
3277 
3286 proshade_double ProSHADE_internal_maths::computeGaussian ( proshade_double val, proshade_double sigma )
3287 {
3288  //================================================ Compute cumulative probability from Z-score
3289  proshade_double zScore = ( val / sigma );
3290  proshade_double cumulativeProbability = 0.5 * std::erfc ( zScore * M_SQRT1_2 );
3291 
3292  //================================================ Symmetrise
3293  if ( cumulativeProbability > 0.5 ) { cumulativeProbability = 1.0 - cumulativeProbability; }
3294 
3295  //================================================ Done
3296  return ( cumulativeProbability );
3297 
3298 }
3299 
3313 std::vector < proshade_double > ProSHADE_internal_maths::smoothen1D ( proshade_double step, proshade_signed windowSize, proshade_double sigma, std::vector< proshade_double > data, proshade_signed decRound )
3314 {
3315  //================================================ Initialise local variables
3316  proshade_signed windowHalf = ( windowSize - 1 ) / 2;
3317  proshade_signed totSize = static_cast< proshade_signed > ( ( 1.0 / step ) + 1 );
3318  std::vector< proshade_double > smoothened ( static_cast< size_t > ( totSize - ( windowSize - 1 ) ), 0.0 );
3319  std::vector< proshade_double > winWeights ( static_cast< size_t > ( windowSize ), 0.0 );
3320 
3321  //================================================ Prepare window weights
3322  for ( proshade_double winIt = 0.0; winIt < static_cast< proshade_double > ( windowSize ); winIt += 1.0 ) { winWeights.at( static_cast< proshade_unsign > ( winIt ) ) = ProSHADE_internal_maths::computeGaussian ( ( winIt - static_cast< proshade_double > ( windowHalf ) ) * step, sigma ); }
3323 
3324  //================================================ Compute smoothened data
3325  for ( proshade_unsign it = 0; it < static_cast< proshade_unsign > ( smoothened.size() ); it++ )
3326  {
3327  //============================================ Compute window weighted average
3328  for ( proshade_signed winIt = 0; winIt < windowSize; winIt++ )
3329  {
3330  smoothened.at(it) += winWeights.at( static_cast< size_t > ( winIt ) ) * data.at( static_cast< size_t > ( static_cast< proshade_signed > ( it ) + winIt ) );
3331  }
3332  }
3333 
3334  //================================================ Round as requested
3335  if ( decRound >= 0 )
3336  {
3337  proshade_double zeroMultip = std::pow ( 10.0, decRound );
3338  for ( proshade_unsign it = 0; it < static_cast< proshade_unsign > ( smoothened.size() ); it++ )
3339  {
3340  smoothened.at(it) = std::round ( smoothened.at(it) * zeroMultip ) / zeroMultip;
3341  }
3342  }
3343 
3344  //================================================ Done
3345  return ( smoothened );
3346 
3347 }
3348 
3359 proshade_single ProSHADE_internal_maths::getResolutionOfReflection ( proshade_single h, proshade_single k, proshade_single l, proshade_single xDim, proshade_single yDim, proshade_single zDim )
3360 {
3361  //================================================ Compute volume and proportions
3362  proshade_single vol = ( xDim * yDim * zDim );
3363  proshade_single sa = ( yDim * zDim ) / vol;
3364  proshade_single sb = ( xDim * zDim ) / vol;
3365  proshade_single sc = ( xDim * yDim ) / vol;
3366 
3367  //================================================ Compute distance
3368  proshade_single s2 = ( std::pow ( h * sa, 2.0f ) +
3369  std::pow ( k * sb, 2.0f ) +
3370  std::pow ( l * sc, 2.0f ) ) / 4.0f;
3371 
3372  //================================================ Deal with F000
3373  if ( s2 == 0.0f ) { s2 = 0.0000000001f; }
3374 
3375  //================================================ Done
3376  return ( 1.0f / ( 2.0f * std::sqrt ( s2 ) ) );
3377 
3378 }
3379 
3397 void ProSHADE_internal_maths::binReciprocalSpaceReflections ( proshade_unsign xInds, proshade_unsign yInds, proshade_unsign zInds, proshade_single xSize, proshade_single ySize, proshade_single zSize, proshade_signed* noBin, proshade_signed*& binIndexing, std::vector< proshade_single >*& resArray )
3398 {
3399  //================================================ Allocate output bin indexing memory and set to -100
3400  binIndexing = new proshade_signed [xInds * yInds * zInds];
3401  ProSHADE_internal_misc::checkMemoryAllocation ( binIndexing, __FILE__, __LINE__, __func__ );
3402  for ( size_t iter = 0; iter < static_cast< size_t > ( xInds * yInds * zInds ); iter++ ) { binIndexing[iter] = -100; }
3403  proshade_single xIndsF = static_cast< proshade_single > ( xInds ), yIndsF = static_cast< proshade_single > ( yInds ), zIndsF = static_cast< proshade_single > ( zInds );
3404 
3405  //================================================ Allocate local memory
3406  proshade_single *mins = new proshade_single[3];
3407  proshade_single *maxs = new proshade_single[3];
3408  proshade_single *hkl = new proshade_single[3];
3409  proshade_single *resMins = new proshade_single[3];
3410  proshade_signed *resMinLoc = new proshade_signed[3];
3411  proshade_single *steps = new proshade_single[3];
3412 
3413  //================================================ Check local memory
3414  ProSHADE_internal_misc::checkMemoryAllocation ( mins, __FILE__, __LINE__, __func__ );
3415  ProSHADE_internal_misc::checkMemoryAllocation ( maxs, __FILE__, __LINE__, __func__ );
3416  ProSHADE_internal_misc::checkMemoryAllocation ( hkl, __FILE__, __LINE__, __func__ );
3417  ProSHADE_internal_misc::checkMemoryAllocation ( resMins, __FILE__, __LINE__, __func__ );
3418  ProSHADE_internal_misc::checkMemoryAllocation ( resMinLoc, __FILE__, __LINE__, __func__ );
3419  ProSHADE_internal_misc::checkMemoryAllocation ( steps, __FILE__, __LINE__, __func__ );
3420 
3421  //================================================ Initialise local variables
3422  proshade_single resVal = 0.0, binVal = 0.0, tmpVal = 0.0, tmpMinVal = 0.0;
3423  proshade_signed reciX, reciY, reciZ, arrPos = 0, binLoc = 0, minLoc = 0;
3424  *noBin = 0;
3425 
3426  //================================================ Determine reciprocal space indexing
3427  mins[0] = std::floor ( xIndsF / -2.0f );
3428  mins[1] = std::floor ( yIndsF / -2.0f );
3429  mins[2] = std::floor ( zIndsF / -2.0f );
3430 
3431  maxs[0] = -(mins[0] + 1);
3432  maxs[1] = -(mins[1] + 1);
3433  maxs[2] = 0.0;
3434 
3435  //================================================ Get minimum resolution based on dims for each dimension
3436  resMins[0] = ProSHADE_internal_maths::getResolutionOfReflection ( maxs[0], 0.0f, 0.0f, xSize, ySize, zSize );
3437  resMins[1] = ProSHADE_internal_maths::getResolutionOfReflection ( 0.0f, maxs[1], 0.0f, xSize, ySize, zSize );
3438  resMins[2] = ProSHADE_internal_maths::getResolutionOfReflection ( 0.0f, 0.0f, maxs[2], xSize, ySize, zSize );
3439 
3440  //================================================ Decide which dimension to work with (the one with the lowest resolution)
3441  resMinLoc[0] = 0; resMinLoc[1] = 0; resMinLoc[2] = 0;
3442  const FloatingPoint< proshade_single > lhs1 ( resMins[0] ), lhs2 ( resMins[1] ), lhs3 ( resMins[2] ), rhs1 ( std::min( resMins[0], std::min( resMins[1], resMins[2] ) ) );
3443  if ( lhs1.AlmostEquals ( rhs1 ) ) { resMinLoc[0] = 1; minLoc = 0; }
3444  else if ( lhs2.AlmostEquals ( rhs1 ) ) { resMinLoc[1] = 1; minLoc = 1; }
3445  else if ( lhs3.AlmostEquals ( rhs1 ) ) { resMinLoc[2] = 1; minLoc = 2; }
3446 
3447  for ( size_t it = 0; it < 3; it++ ) { hkl[it] = 0.0; if ( static_cast<size_t> ( minLoc ) == it ) { hkl[it] = 1.0; } }
3448 
3449  //================================================ Find the bins and corresponding cut-offs
3450  resArray = new std::vector< proshade_single > ( static_cast< size_t > ( maxs[minLoc] ), 0.0f );
3451  ProSHADE_internal_misc::checkMemoryAllocation ( resArray, __FILE__, __LINE__, __func__ );
3452  for ( proshade_signed dimIt = 0; dimIt < static_cast< proshade_signed > ( maxs[minLoc] ); dimIt++ )
3453  {
3454  //============================================ Prepare steps
3455  steps[0] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[0] ) * hkl[0];
3456  steps[1] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[1] ) * hkl[1];
3457  steps[2] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[2] ) * hkl[2];
3458 
3459  //============================================ Find resolution
3460  resVal = ProSHADE_internal_maths::getResolutionOfReflection ( steps[0], steps[1], steps[2], xSize, ySize, zSize );
3461 
3462  //============================================ Assign to arrays
3463  resArray->at(static_cast< size_t > ( dimIt )) = resVal;
3464  *noBin = dimIt + 1;
3465  }
3466 
3467  //================================================ Determine resolution limits
3468  proshade_single highResLimit = resArray->at ( static_cast< size_t > ( *noBin - 1 ) );
3469  proshade_single lowResLimit = ProSHADE_internal_maths::getResolutionOfReflection ( 0.0f, 0.0f, 0.0f, xSize, ySize, zSize );
3470 
3471  const FloatingPoint< proshade_single > minX ( mins[0] ), minY ( mins[1] ), minZ ( mins[2] );
3472 
3473  //================================================ Assign reflections to bins
3474  for ( proshade_single xIt = static_cast< proshade_single > ( mins[0] ); xIt <= static_cast< proshade_single > ( maxs[0] ); xIt += 1.0f )
3475  {
3476  for ( proshade_single yIt = static_cast< proshade_single > ( mins[1] ); yIt <= static_cast< proshade_single > ( maxs[1] ); yIt += 1.0f )
3477  {
3478  for ( proshade_single zIt = static_cast< proshade_single > ( mins[2] ); zIt <= 0.0f; zIt += 1.0f )
3479  {
3480  //==================================== Find resoltion of this spot
3481  resVal = ProSHADE_internal_maths::getResolutionOfReflection ( xIt, yIt, zIt, xSize, ySize, zSize );
3482 
3483  //==================================== Is it in range?
3484  if ( ( resVal < highResLimit ) || ( resVal > lowResLimit ) ) { continue; }
3485 
3486  //==================================== For each bin, check if this reflection belongs to it
3487  for ( proshade_signed binIt = 0; binIt < (*noBin); binIt++ )
3488  {
3489  //================================ Find bin resolution
3490  binVal = std::sqrt ( std::pow ( resArray->at( static_cast< size_t > ( binIt ) ) - resVal, 2.0f ) );
3491 
3492  //================================ Is this the closest bin to the spot resolution?
3493  if ( binIt == 0 )
3494  {
3495  tmpVal = binVal;
3496  tmpMinVal = binVal;
3497  binLoc = binIt;
3498  }
3499  else
3500  {
3501  tmpVal = binVal;
3502  if ( tmpVal < tmpMinVal )
3503  {
3504  tmpMinVal = binVal;
3505  binLoc = binIt;
3506  }
3507  }
3508  }
3509 
3510  //==================================== Save bin index
3511  reciX = static_cast< proshade_signed > ( xIt - mins[0] );
3512  reciY = static_cast< proshade_signed > ( yIt - mins[1] );
3513  reciZ = static_cast< proshade_signed > ( zIt - mins[2] );
3514 
3515  arrPos = reciZ + static_cast< proshade_signed > ( zInds ) * ( reciY + static_cast< proshade_signed > ( yInds ) * reciX );
3516  binIndexing[ static_cast< size_t > ( arrPos ) ] = binLoc;
3517 
3518  //==================================== If applicable, use Friedel's Law
3519  const FloatingPoint< proshade_single > itX ( xIt ), itY ( yIt ), itZ ( zIt );
3520  if ( minX.AlmostEquals ( itX ) || minY.AlmostEquals ( itY ) || minZ.AlmostEquals ( itZ ) ) { continue; }
3521 
3522  reciX = static_cast< proshade_signed > ( -xIt - mins[0] );
3523  reciY = static_cast< proshade_signed > ( -yIt - mins[1] );
3524  reciZ = static_cast< proshade_signed > ( -zIt - mins[2] );
3525 
3526  arrPos = reciZ + static_cast< proshade_signed > ( zInds ) * ( reciY + static_cast< proshade_signed > ( yInds ) * reciX );
3527  binIndexing[ static_cast< size_t > ( arrPos ) ] = binLoc;
3528  }
3529  }
3530  }
3531 
3532  //================================================ Release memory
3533  delete[] mins;
3534  delete[] maxs;
3535  delete[] hkl;
3536  delete[] resMins;
3537  delete[] resMinLoc;
3538  delete[] steps;
3539 
3540  //================================================ Done
3541  return ;
3542 
3543 }
3544 
3563 void ProSHADE_internal_maths::cutIndicesToResolution ( proshade_signed xInds, proshade_signed yInds, proshade_signed zInds, proshade_single resolution, proshade_signed* binIndexing, std::vector< proshade_single >* resArray, proshade_signed* cutXDim, proshade_signed* cutYDim, proshade_signed* cutZDim, proshade_signed*& cutBinIndices, proshade_signed*& noBins )
3564 {
3565  //================================================ Initialise local variables
3566  proshade_single resCut = resolution;
3567  proshade_single minVal = std::numeric_limits < proshade_single >::infinity();
3568  *noBins = 0;
3569  std::vector< proshade_single > resDists;
3570 
3571  //================================================ Find the maximum bin to be used
3572  for ( size_t iter = 0; iter < resArray->size(); iter++ ) { ProSHADE_internal_misc::addToSingleVector ( &resDists, std::sqrt ( std::pow ( resArray->at(iter) - resCut, 2.0f ) ) ); }
3573  for ( size_t iter = 0; iter < resDists.size(); iter++ ) { if ( resDists.at(iter) < minVal ) { minVal = resDists.at(iter); (*noBins) = static_cast< proshade_signed > ( iter ); } }
3574 
3575  //================================================ Compute new map dimensions
3576  proshade_signed newXFrom = static_cast< proshade_signed > ( std::round ( ( static_cast< proshade_signed > ( xInds ) - 2 * (*noBins) ) / 2 ) );
3577  proshade_signed newYFrom = static_cast< proshade_signed > ( std::round ( ( static_cast< proshade_signed > ( yInds ) - 2 * (*noBins) ) / 2 ) );
3578  proshade_signed newZFrom = static_cast< proshade_signed > ( std::round ( ( static_cast< proshade_signed > ( zInds ) - 2 * (*noBins) ) / 2 ) );
3579  proshade_signed newXTo = static_cast< proshade_signed > ( std::round ( newXFrom + 2 * (*noBins) ) );
3580  proshade_signed newYTo = static_cast< proshade_signed > ( std::round ( newYFrom + 2 * (*noBins) ) );
3581  proshade_signed newZTo = static_cast< proshade_signed > ( std::round ( newZFrom + 2 * (*noBins) ) );
3582  *cutXDim = ( newXTo - newXFrom );
3583  *cutYDim = ( newYTo - newYFrom );
3584  *cutZDim = ( newZTo - newZFrom );
3585 
3586  //================================================ Create new binIndexing within only the new dimensions
3587  cutBinIndices = new proshade_signed[(*cutXDim) * (*cutYDim) * (*cutZDim)];
3588  ProSHADE_internal_misc::checkMemoryAllocation ( cutBinIndices, __FILE__, __LINE__, __func__ );
3589  for ( size_t iter = 0; iter < static_cast< size_t > ( (*cutXDim) * (*cutYDim) * (*cutZDim) ); iter++ ) { cutBinIndices[iter] = 0; }
3590 
3591  proshade_signed newArrPos = 0, origArrPos = 0;
3592  for ( proshade_signed xIt = newXFrom; xIt < newXTo; xIt++ )
3593  {
3594  for ( proshade_signed yIt = newYFrom; yIt < newYTo; yIt++ )
3595  {
3596  for ( proshade_signed zIt = newZFrom; zIt < newZTo; zIt++ )
3597  {
3598  //==================================== Skip if outside of box
3599  if ( ( xIt < 0 ) || ( yIt < 0 ) || ( zIt < 0 ) ) { continue; }
3600  if ( ( xIt >= xInds ) || ( yIt >= yInds ) || ( zIt >= zInds ) ) { continue; }
3601 
3602  //==================================== Find positions
3603  newArrPos = (zIt-newZFrom) + (*cutZDim) * ( (yIt-newYFrom) + (*cutYDim) * (xIt-newXFrom) );
3604  origArrPos = zIt + static_cast< proshade_signed > ( zInds ) * ( yIt + static_cast< proshade_signed > ( yInds ) * xIt );
3605 
3606  //==================================== Copy value
3607  cutBinIndices[newArrPos] = binIndexing[origArrPos];
3608  }
3609  }
3610  }
3611 
3612  //================================================ Done
3613  return ;
3614 
3615 }
3616 
3628 void ProSHADE_internal_maths::cutArrayToResolution ( proshade_signed xInds, proshade_signed yInds, proshade_signed zInds, proshade_signed noBins, fftw_complex* inputMap, fftw_complex*& cutMap )
3629 {
3630  //================================================ Compute new map dimensions
3631  proshade_signed newXFrom = static_cast< proshade_signed > ( std::round ( ( static_cast< proshade_signed > ( xInds ) - 2 * noBins ) / 2 ) );
3632  proshade_signed newYFrom = static_cast< proshade_signed > ( std::round ( ( static_cast< proshade_signed > ( yInds ) - 2 * noBins ) / 2 ) );
3633  proshade_signed newZFrom = static_cast< proshade_signed > ( std::round ( ( static_cast< proshade_signed > ( zInds ) - 2 * noBins ) / 2 ) );
3634  proshade_signed newXTo = static_cast< proshade_signed > ( std::round ( newXFrom + 2 * noBins ) );
3635  proshade_signed newYTo = static_cast< proshade_signed > ( std::round ( newYFrom + 2 * noBins ) );
3636  proshade_signed newZTo = static_cast< proshade_signed > ( std::round ( newZFrom + 2 * noBins ) );
3637  proshade_signed cutXDim = ( newXTo - newXFrom );
3638  proshade_signed cutYDim = ( newYTo - newYFrom );
3639  proshade_signed cutZDim = ( newZTo - newZFrom );
3640 
3641  //================================================ Create new coefficients array within only the new dimensions
3642  cutMap = reinterpret_cast< fftw_complex* > ( fftw_malloc ( sizeof ( fftw_complex ) * static_cast< proshade_unsign > ( cutXDim * cutYDim * cutZDim ) ) );
3643  ProSHADE_internal_misc::checkMemoryAllocation ( cutMap, __FILE__, __LINE__, __func__ );
3644  for ( size_t iter = 0; iter < static_cast< size_t > ( cutXDim * cutYDim * cutZDim ); iter++ ) { cutMap[iter][0] = 0.0; cutMap[iter][1] = 0.0; }
3645 
3646  proshade_signed newArrPos = 0, origArrPos = 0;
3647  for ( proshade_signed xIt = newXFrom; xIt < newXTo; xIt++ )
3648  {
3649  for ( proshade_signed yIt = newYFrom; yIt < newYTo; yIt++ )
3650  {
3651  for ( proshade_signed zIt = newZFrom; zIt < newZTo; zIt++ )
3652  {
3653  //==================================== Skip if outside of box
3654  if ( ( xIt < 0 ) || ( yIt < 0 ) || ( zIt < 0 ) ) { continue; }
3655  if ( ( xIt >= xInds ) || ( yIt >= yInds ) || ( zIt >= zInds ) ) { continue; }
3656 
3657  //==================================== Find positions
3658  newArrPos = (zIt-newZFrom) + cutZDim * ( (yIt-newYFrom) + cutYDim * (xIt-newXFrom) );
3659  origArrPos = zIt + static_cast< proshade_signed > ( zInds ) * ( yIt + static_cast< proshade_signed > ( yInds ) * xIt );
3660 
3661  //==================================== Copy value
3662  cutMap[newArrPos][0] = inputMap[origArrPos][0];
3663  cutMap[newArrPos][1] = inputMap[origArrPos][1];
3664  }
3665  }
3666  }
3667 
3668  //================================================ Done
3669  return ;
3670 
3671 }
3672 
3693 proshade_double ProSHADE_internal_maths::computeFSC ( fftw_complex *fCoeffs1, fftw_complex *fCoeffs2, proshade_signed xInds, proshade_signed yInds, proshade_signed zInds, proshade_signed noBins, proshade_signed* binIndexing, proshade_double**& binData, proshade_signed*& binCounts, proshade_double*& fscByBin, bool averageByBinSize )
3694 {
3695  //================================================ Initialise local variables
3696  proshade_double realOrig, realRot, imagOrig, imagRot, fsc = 0.0;;
3697  proshade_signed indx, arrPos;
3698  std::vector< proshade_double > covarByBin ( static_cast< size_t > ( noBins ), 0.0 );
3699 
3700  //================================================ Clean FSC computation memory
3701  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ ) { for ( size_t valIt = 0; valIt < 12; valIt++ ) { binData[binIt][valIt] = 0.0; } }
3702  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ ) { binCounts[binIt] = 0; }
3703 
3704  //================================================ Compute bin sums
3705  for ( proshade_signed xIt = 0; xIt < xInds; xIt++ )
3706  {
3707  for ( proshade_signed yIt = 0; yIt < yInds; yIt++ )
3708  {
3709  for ( proshade_signed zIt = 0; zIt < ( zInds / 2 ); zIt++ )
3710  {
3711  //==================================== Find array position
3712  arrPos = zIt + static_cast< proshade_signed > ( zInds ) * ( yIt + static_cast< proshade_signed > ( yInds ) * xIt );
3713 
3714  //==================================== If no bin is associated, skip this reflection
3715  indx = binIndexing[ static_cast< size_t > ( arrPos ) ];
3716  if ( ( indx < 0 ) || ( indx >= noBins ) ) { continue; }
3717 
3718  //==================================== Calculate the sums
3719  realOrig = fCoeffs1[arrPos][0];
3720  imagOrig = fCoeffs1[arrPos][1];
3721  realRot = fCoeffs2[arrPos][0];
3722  imagRot = fCoeffs2[arrPos][1];
3723 
3724  binData[indx][0] += realOrig;
3725  binData[indx][1] += imagOrig;
3726  binData[indx][2] += realRot;
3727  binData[indx][3] += imagRot;
3728  binData[indx][4] += realOrig * realRot;
3729  binData[indx][5] += imagOrig * imagRot;
3730  binData[indx][6] += std::pow ( realOrig, 2.0 );
3731  binData[indx][7] += std::pow ( imagOrig, 2.0 );
3732  binData[indx][8] += std::pow ( realRot, 2.0 );
3733  binData[indx][9] += std::pow ( imagRot, 2.0 );
3734 
3735  //==================================== Update bin counts
3736  binCounts[indx] += 1;
3737  }
3738  }
3739  }
3740 
3741  //================================================ Compute covariance by bin
3742  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3743  {
3744  covarByBin.at(binIt) = ( ( binData[binIt][4] + binData[binIt][5] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3745  ( ( binData[binIt][0] / static_cast< proshade_double > ( binCounts[binIt] ) *
3746  binData[binIt][2] / static_cast< proshade_double > ( binCounts[binIt] ) ) +
3747  ( binData[binIt][1] / static_cast< proshade_double > ( binCounts[binIt] ) *
3748  binData[binIt][3] / static_cast< proshade_double > ( binCounts[binIt] ) ) ) );
3749  }
3750 
3751  //================================================ Get FSC by bin
3752  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3753  {
3754  binData[binIt][10] = ( binData[binIt][6] + binData[binIt][7] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3755  ( std::pow ( binData[binIt][0] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) +
3756  std::pow ( binData[binIt][1] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) );
3757  binData[binIt][11] = ( binData[binIt][8] + binData[binIt][9] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3758  ( std::pow ( binData[binIt][2] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) +
3759  std::pow ( binData[binIt][3] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) );
3760  fscByBin[binIt] = covarByBin.at(binIt) / ( std::sqrt ( binData[binIt][10] ) * std::sqrt ( binData[binIt][11] ) );
3761  }
3762 
3763  //================================================ Get average FSC over all bins
3764  proshade_double binSizeSum = 0.0;
3765  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3766  {
3767  if ( averageByBinSize )
3768  {
3769  fsc += fscByBin[binIt] * static_cast< proshade_double > ( binCounts[binIt] );
3770  binSizeSum += static_cast< proshade_double > ( binCounts[binIt] );
3771  }
3772  else
3773  {
3774  fsc += fscByBin[binIt];
3775  binSizeSum += 1;
3776  }
3777  }
3778  fsc /= static_cast< proshade_double > ( binSizeSum );
3779 
3780  //================================================ Done
3781  return ( fsc );
3782 
3783 }
3784 
3800 void ProSHADE_internal_maths::computeFSCWeightByBin ( proshade_double*& weights1, proshade_double*& weights2, proshade_signed* binIndexing, proshade_double* fscByBin, proshade_signed noBins, proshade_signed xDim, proshade_signed yDim, proshade_signed zDim )
3801 {
3802  //================================================ Initialise local variables
3803  proshade_signed indx, arrPos, reciX, reciY, reciZ;
3804 
3805  //================================================ Allocate memmory
3806  weights1 = new proshade_double[xDim * yDim * zDim];
3807  weights2 = new proshade_double[xDim * yDim * zDim];
3808  proshade_single *mins = new proshade_single[3];
3809  proshade_single *maxs = new proshade_single[3];
3810 
3811  //================================================ Check memory allocation
3812  ProSHADE_internal_misc::checkMemoryAllocation ( weights1, __FILE__, __LINE__, __func__ );
3813  ProSHADE_internal_misc::checkMemoryAllocation ( weights2, __FILE__, __LINE__, __func__ );
3814  ProSHADE_internal_misc::checkMemoryAllocation ( mins, __FILE__, __LINE__, __func__ );
3815  ProSHADE_internal_misc::checkMemoryAllocation ( maxs, __FILE__, __LINE__, __func__ );
3816 
3817  //================================================ Assign values to the memory
3818  for ( size_t iter = 0; iter < static_cast< size_t > ( xDim * yDim * zDim ); iter++ ) { weights1[iter] = -100.0; weights2[iter] = -100.0; }
3819 
3820  //================================================ Determine reciprocal space indexing ranges
3821  mins[0] = std::floor ( static_cast< proshade_single > ( xDim ) / -2.0f );
3822  mins[1] = std::floor ( static_cast< proshade_single > ( yDim ) / -2.0f );
3823  mins[2] = std::floor ( static_cast< proshade_single > ( zDim ) / -2.0f );
3824 
3825  maxs[0] = -mins[0];
3826  maxs[1] = -mins[1];
3827  maxs[2] = -mins[2];
3828 
3829  if ( xDim % 2 == 0 ) { mins[0] += 1.0f; }
3830  if ( yDim % 2 == 0 ) { mins[1] += 1.0f; }
3831  if ( zDim % 2 == 0 ) { mins[2] += 1.0f; }
3832 
3833  //================================================ For each reflection
3834  for ( proshade_signed xIt = 0; xIt < xDim; xIt++ )
3835  {
3836  for ( proshade_signed yIt = 0; yIt < yDim; yIt++ )
3837  {
3838  for ( proshade_signed zIt = 0; zIt < ( ( zDim / 2 ) + 1 ); zIt++ )
3839  {
3840  //==================================== Deal with reciprocal indices ordering
3841  reciX = xIt; if ( reciX > static_cast< proshade_signed > ( maxs[0] ) ) { reciX -= static_cast< proshade_signed > ( xDim ); }
3842  reciY = yIt; if ( reciY > static_cast< proshade_signed > ( maxs[1] ) ) { reciY -= static_cast< proshade_signed > ( yDim ); }
3843  reciZ = zIt; if ( reciZ > static_cast< proshade_signed > ( maxs[2] ) ) { reciZ -= static_cast< proshade_signed > ( zDim ); }
3844 
3845  //==================================== Find array position and bin index
3846  arrPos = zIt + zDim * ( yIt + yDim * xIt );
3847  indx = binIndexing[ static_cast< size_t > ( arrPos ) ];
3848 
3849  //==================================== Ignore unassigned bin reflections
3850  if ( ( indx < 0 ) || ( indx > noBins ) ) { continue; }
3851 
3852  //==================================== Set weights using the bin FSC
3853  weights1[arrPos] = fscByBin[indx];
3854  weights2[arrPos] = std::pow ( fscByBin[indx], 2.0 );
3855 
3856  //==================================== If one of the uneven ends, do not use Friedel's Law
3857  if ( reciX == static_cast< proshade_signed > ( mins[0] ) || -reciX == static_cast< proshade_signed > ( mins[0] ) ) { break; }
3858  if ( reciY == static_cast< proshade_signed > ( mins[1] ) || -reciY == static_cast< proshade_signed > ( mins[1] ) ) { break; }
3859  if ( reciZ == static_cast< proshade_signed > ( mins[2] ) || -reciZ == static_cast< proshade_signed > ( mins[2] ) ) { break; }
3860 
3861  //==================================== Use Friedel's Law to find the second index (this is why we can use zDim / 2)
3862  reciX *= -1; if ( reciX < 0 ) { reciX += xDim; }
3863  reciY *= -1; if ( reciY < 0 ) { reciY += yDim; }
3864  reciZ *= -1; if ( reciZ < 0 ) { reciZ += zDim; }
3865 
3866  //==================================== Apply Friedel's Law
3867  arrPos = reciZ + zDim * ( reciY + yDim * reciX );
3868  weights1[arrPos] = fscByBin[indx];
3869  weights2[arrPos] = std::pow ( fscByBin[indx], 2.0 );
3870  }
3871  }
3872  }
3873 
3874  //================================================ Release memory
3875  delete[] mins;
3876  delete[] maxs;
3877 
3878  //================================================ Done
3879  return ;
3880 
3881 }
3882 
3892 proshade_double ProSHADE_internal_maths::computeTheFValue ( proshade_complex* fCoeffs, proshade_double* weights, proshade_signed xDim, proshade_signed yDim, proshade_signed zDim )
3893 {
3894  //================================================ Initialise local variables
3895  proshade_double sum = 0.0;
3896  proshade_signed arrPos;
3897 
3898  //================================================ For each reflection
3899  for ( proshade_signed xIt = 0; xIt < xDim; xIt++ )
3900  {
3901  for ( proshade_signed yIt = 0; yIt < yDim; yIt++ )
3902  {
3903  for ( proshade_signed zIt = 0; zIt < ( ( zDim / 2 ) + 1 ); zIt++ )
3904  {
3905  //==================================== Find array position and bin index
3906  arrPos = zIt + zDim * ( yIt + yDim * xIt );
3907 
3908  //==================================== Sum real parts if weight exists
3909  if ( weights[arrPos] > -2.0 ) { sum += fCoeffs[arrPos][0]; }
3910  }
3911  }
3912  }
3913 
3914  //================================================ Done
3915  return ( sum );
3916 
3917 }
3918 
3930 void ProSHADE_internal_maths::computeTrFunDerivatives ( proshade_complex* fCoeffs, proshade_double* weights1, proshade_double* weights2, proshade_signed xDim, proshade_signed yDim, proshade_signed zDim, proshade_double*& firstDers, proshade_double*& secondDers )
3931 {
3932  //================================================ Allocate memmory
3933  firstDers = new proshade_double[3];
3934  secondDers = new proshade_double[9];
3935  proshade_single *mins = new proshade_single[3];
3936  proshade_single *maxs = new proshade_single[3];
3937 
3938  //================================================ Check memory allocation
3939  ProSHADE_internal_misc::checkMemoryAllocation ( firstDers, __FILE__, __LINE__, __func__ );
3940  ProSHADE_internal_misc::checkMemoryAllocation ( secondDers, __FILE__, __LINE__, __func__ );
3941  ProSHADE_internal_misc::checkMemoryAllocation ( mins, __FILE__, __LINE__, __func__ );
3942  ProSHADE_internal_misc::checkMemoryAllocation ( maxs, __FILE__, __LINE__, __func__ );
3943 
3944  //================================================ Initialise variables
3945  std::complex< proshade_double > piConstFirst ( 2.0 * M_PI, 1.0 );
3946  proshade_double piConstSecond = std::pow ( 2.0 * M_PI, 2.0 );
3947  for ( size_t iter = 0; iter < 3; iter++ ) { firstDers[iter] = 0.0; }
3948  for ( size_t iter = 0; iter < 9; iter++ ) { secondDers[iter] = 0.0; }
3949  proshade_signed reciX, reciY, reciZ, arrPos;
3950 
3951  //================================================ Determine reciprocal space indexing ranges
3952  mins[0] = std::floor ( static_cast< proshade_single > ( xDim ) / -2.0f );
3953  mins[1] = std::floor ( static_cast< proshade_single > ( yDim ) / -2.0f );
3954  mins[2] = std::floor ( static_cast< proshade_single > ( zDim ) / -2.0f );
3955 
3956  maxs[0] = -mins[0];
3957  maxs[1] = -mins[1];
3958  maxs[2] = -mins[2];
3959 
3960  if ( xDim % 2 == 0 ) { mins[0] += 1.0f; }
3961  if ( yDim % 2 == 0 ) { mins[1] += 1.0f; }
3962  if ( zDim % 2 == 0 ) { mins[2] += 1.0f; }
3963 
3964  //================================================ For each reflection
3965  for ( proshade_signed xIt = 0; xIt < xDim; xIt++ )
3966  {
3967  for ( proshade_signed yIt = 0; yIt < yDim; yIt++ )
3968  {
3969  for ( proshade_signed zIt = 0; zIt < ( ( zDim / 2 ) + 1 ); zIt++ )
3970  {
3971  //==================================== Deal with reciprocal indices ordering
3972  reciX = xIt; if ( reciX > static_cast< proshade_signed > ( maxs[0] ) ) { reciX -= static_cast< proshade_signed > ( xDim ); }
3973  reciY = yIt; if ( reciY > static_cast< proshade_signed > ( maxs[1] ) ) { reciY -= static_cast< proshade_signed > ( yDim ); }
3974  reciZ = zIt; if ( reciZ > static_cast< proshade_signed > ( maxs[2] ) ) { reciZ -= static_cast< proshade_signed > ( zDim ); }
3975 
3976  //==================================== Find array position and bin index
3977  arrPos = zIt + zDim * ( yIt + yDim * xIt );
3978 
3979  //==================================== Ignore if outside of weights
3980  if ( weights1[arrPos] < -2.0 ) { continue; }
3981 
3982  //==================================== Add to the first derivatives sum
3983  firstDers[0] += ( weights1[arrPos] * fCoeffs[arrPos][0] * std::conj( fCoeffs[arrPos][1] * piConstFirst * static_cast< proshade_double > ( reciX ) ) ).real();
3984  firstDers[1] += ( weights1[arrPos] * fCoeffs[arrPos][0] * std::conj( fCoeffs[arrPos][1] * piConstFirst * static_cast< proshade_double > ( reciY ) ) ).real();
3985  firstDers[2] += ( weights1[arrPos] * fCoeffs[arrPos][0] * std::conj( fCoeffs[arrPos][1] * piConstFirst * static_cast< proshade_double > ( reciZ ) ) ).real();
3986 
3987  //==================================== Add to the second derivatives sum
3988  secondDers[0] += weights2[arrPos] * static_cast< proshade_double > ( reciX * reciX );
3989  secondDers[1] += weights2[arrPos] * static_cast< proshade_double > ( reciX * reciY );
3990  secondDers[2] += weights2[arrPos] * static_cast< proshade_double > ( reciX * reciZ );
3991  secondDers[4] += weights2[arrPos] * static_cast< proshade_double > ( reciY * reciY );
3992  secondDers[5] += weights2[arrPos] * static_cast< proshade_double > ( reciY * reciZ );
3993  secondDers[8] += weights2[arrPos] * static_cast< proshade_double > ( reciZ * reciZ );
3994  }
3995  }
3996  }
3997 
3998  //================================================ Complete second darivatives matrix
3999  secondDers[3] = secondDers[1];
4000  secondDers[6] = secondDers[2];
4001  secondDers[7] = secondDers[5];
4002  for ( size_t iter = 0; iter < 9; iter++ ) { secondDers[iter] *= -piConstSecond; }
4003 
4004  //================================================ Release memory
4005  delete[] mins;
4006  delete[] maxs;
4007 
4008  //================================================ Done
4009  return ;
4010 
4011 }
4012 
4019 proshade_double* ProSHADE_internal_maths::computeTrFunStep ( proshade_double* firstDers, proshade_double* secondDers )
4020 {
4021  //================================================ Change format of second derivatives and add I matrix (the inversion function will subtract it)
4022  std::vector < proshade_double > tmpMap ( 9, 0.0 );
4023  for ( size_t iter = 0; iter < 9; iter++ ) { tmpMap.at(iter) = secondDers[iter]; }
4024  tmpMap.at(0) += 1.0; tmpMap.at(4) += 1.0; tmpMap.at(8) += 1.0;
4025 
4026  //================================================ Compute matrix inversion for the second derivatives matrix
4027  proshade_double* secondInv = compute3x3MoorePenrosePseudoInverseOfIMinusMat ( &tmpMap, -1 );
4028 
4029  //================================================ Compute dot product between the inverted matrix and the first derivatives vector
4030  proshade_double* stepArr = compute3x3MatrixVectorMultiplication ( secondInv, -firstDers[0], -firstDers[1], -firstDers[2] );
4031 
4032  //================================================ Release memory
4033  delete[] secondInv;
4034 
4035  //================================================ Done
4036  return ( stepArr );
4037 
4038 }
4039 
4047 std::vector< proshade_signed > ProSHADE_internal_maths::findPeaks1D ( std::vector< proshade_double > data )
4048 {
4049  //================================================ Initialise local variables
4050  std::vector< proshade_signed > ret;
4051  bool sameValStreak = false;
4052 
4053  //================================================ Peak is simply any position with both neighbours having lower position (with special care for borders)
4054  for ( proshade_signed index = static_cast< proshade_signed > ( data.size() ) - 1; index > 0; index-- )
4055  {
4056  //============================================ End border?
4057  if ( index == ( static_cast< proshade_signed > ( data.size() ) - 1 ) )
4058  {
4059  if ( data.size() > 1 ) { if ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index - 1 ) ) ) { ProSHADE_internal_misc::addToSignedVector ( &ret, index ); } }
4060  continue;
4061  }
4062 
4063  //============================================ Start border?
4064  if ( index == 0 )
4065  {
4066  if ( data.at( 0 ) > data.at( 1 ) ) { ProSHADE_internal_misc::addToSignedVector ( &ret, index ); }
4067  continue;
4068  }
4069 
4070  //============================================ Is this a peak?
4071  if ( ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index ) - 1 ) ) &&
4072  ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index ) + 1 ) ) ) { ProSHADE_internal_misc::addToSignedVector ( &ret, index ); continue; }
4073 
4074  //============================================ Deal with equally sized values
4075  if ( sameValStreak && ( index >= 1 ) && ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index - 1 ) ) ) ) { sameValStreak = false; ProSHADE_internal_misc::addToSignedVector ( &ret, index ); continue; }
4076  if ( sameValStreak && ( index == 0 ) ) { sameValStreak = false; ProSHADE_internal_misc::addToSignedVector ( &ret, index ); continue; }
4077  const FloatingPoint< proshade_double > lhs ( data.at( static_cast< size_t > ( index ) ) ), rhs ( 0.0 );
4078  if ( lhs.AlmostEquals ( rhs ) ) { continue; }
4079  if ( ( index > 1 ) && !sameValStreak )
4080  {
4081  if ( data.at( static_cast< size_t > ( index ) ) >= data.at( static_cast< size_t > ( index - 1 ) ) )
4082  {
4083  if ( data.at( static_cast< size_t > ( index ) ) >= data.at( static_cast< size_t > ( index + 1 ) ) )
4084  {
4085  sameValStreak = true;
4086  }
4087  }
4088  }
4089  }
4090 
4091  //================================================ Sort peaks
4092  std::sort ( ret.begin(), ret.end() );
4093 
4094  //================================================ Done
4095  return ( ret );
4096 
4097 }
4098 
4113 proshade_double ProSHADE_internal_maths::findTopGroupSmooth ( std::vector< proshade_double* >* CSym, size_t peakPos, proshade_double step, proshade_double sigma, proshade_signed windowSize, proshade_double maxLim )
4114 {
4115  //================================================ Initialise local variables
4116  proshade_double threshold = 0.0;
4117  proshade_signed totSize = static_cast< proshade_signed > ( ( 1.0 / step ) + 1 );
4118  std::vector< std::pair < proshade_double, proshade_unsign > > vals;
4119  std::vector< proshade_double > hist ( static_cast< unsigned long int > ( totSize ), 0.0 );
4120  proshade_unsign histPos = 0;
4121 
4122  //================================================ Make sure window size is odd
4123  if ( windowSize % 2 == 0 ) { windowSize += 1; }
4124 
4125  //================================================ Get vector of pairs of peak heights and indices in CSym array
4126  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( CSym->size() ); symIt++ ) { if ( !std::isinf( CSym->at(symIt)[peakPos] ) ) { vals.emplace_back ( std::pair < proshade_double, proshade_unsign > ( CSym->at(symIt)[peakPos], symIt ) ); } }
4127 
4128  //================================================ Bump all top peaks together - we do not want single high peak overshadowing many good peaks
4129  for ( proshade_unsign vIt = 0; vIt < static_cast< proshade_unsign > ( vals.size() ); vIt++ ) { if ( vals.at(vIt).first > maxLim ) { vals.at(vIt).first = maxLim; } }
4130 
4131  //================================================ Convert all found heights to histogram from 0.0 to 1.0 by step
4132  for ( proshade_double it = 0.0; it <= 1.0; it = it + step )
4133  {
4134  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( vals.size() ); symIt++ )
4135  {
4136  //======================================== Is this height in the range?
4137  if ( ( vals.at(symIt).first > it ) && ( vals.at(symIt).first <= ( it + step ) ) ) { hist.at(histPos) += 1.0; }
4138  }
4139 
4140  //============================================ Update counter and continue
4141  histPos += 1;
4142  }
4143 
4144  //================================================ Smoothen the distribution
4145  std::vector< proshade_double > smoothened = ProSHADE_internal_maths::smoothen1D ( step, windowSize, sigma, hist );
4146 
4147  //================================================ Find peaks in smoothened data
4148  std::vector< proshade_signed > peaks = ProSHADE_internal_maths::findPeaks1D ( smoothened );
4149 
4150  //================================================ Determine threshold from the peaks
4151  size_t bestHistPos;
4152  if ( peaks.size() > 0 ) { bestHistPos = hist.size() - ( ( smoothened.size() - static_cast< size_t > ( peaks.at(peaks.size()-1) ) ) + ( ( static_cast< size_t > ( windowSize ) + 1 ) / 2 ) ); }
4153  else { bestHistPos = 0; }
4154  threshold = ( static_cast< proshade_double > ( bestHistPos ) * step );
4155 
4156  //================================================ Check that the threshold is not higher than the highest value
4157  proshade_double maxVal = 0.0;
4158  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( CSym->size() ); symIt++ ) { if ( maxVal < CSym->at(symIt)[peakPos] ) { maxVal = CSym->at(symIt)[peakPos]; } }
4159  if ( maxVal < threshold ) { threshold = maxVal - step; }
4160 
4161  //================================================ Done
4162  return ( threshold );
4163 
4164 }
4165 
4180 proshade_double ProSHADE_internal_maths::findTopGroupSmooth ( std::vector< std::vector< proshade_double > >* CSym, size_t peakPos, proshade_double step, proshade_double sigma, proshade_signed windowSize, proshade_double maxLim )
4181 {
4182  //================================================ Initialise local variables
4183  proshade_double threshold = 0.0;
4184  proshade_signed totSize = static_cast< proshade_signed > ( ( 1.0 / step ) + 1 );
4185  std::vector< std::pair < proshade_double, proshade_unsign > > vals;
4186  std::vector< proshade_double > hist ( static_cast< unsigned long int > ( totSize ), 0.0 );
4187  proshade_unsign histPos = 0;
4188 
4189  //================================================ Make sure window size is odd
4190  if ( windowSize % 2 == 0 ) { windowSize += 1; }
4191 
4192  //================================================ Get vector of pairs of peak heights and indices in CSym array
4193  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( CSym->size() ); symIt++ ) { if ( !std::isinf( CSym->at(symIt).at(peakPos) ) ) { vals.emplace_back ( std::pair < proshade_double, proshade_unsign > ( CSym->at(symIt).at(peakPos), symIt ) ); } }
4194 
4195  //================================================ Bump all top peaks together - we do not want single high peak overshadowing many good peaks
4196  for ( proshade_unsign vIt = 0; vIt < static_cast< proshade_unsign > ( vals.size() ); vIt++ ) { if ( vals.at(vIt).first > maxLim ) { vals.at(vIt).first = maxLim; } }
4197 
4198  //================================================ Convert all found heights to histogram from 0.0 to 1.0 by step
4199  for ( proshade_double it = 0.0; it <= 1.0; it = it + step )
4200  {
4201  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( vals.size() ); symIt++ )
4202  {
4203  //======================================== Is this height in the range?
4204  if ( ( vals.at(symIt).first > it ) && ( vals.at(symIt).first <= ( it + step ) ) ) { hist.at(histPos) += 1.0; }
4205  }
4206 
4207  //============================================ Update counter and continue
4208  histPos += 1;
4209  }
4210 
4211  //================================================ Smoothen the distribution
4212  std::vector< proshade_double > smoothened = ProSHADE_internal_maths::smoothen1D ( step, windowSize, sigma, hist );
4213 
4214  //================================================ Find peaks in smoothened data
4215  std::vector< proshade_signed > peaks = ProSHADE_internal_maths::findPeaks1D ( smoothened );
4216 
4217  //================================================ Determine threshold from the peaks
4218  size_t bestHistPos;
4219  if ( peaks.size() > 0 ) { bestHistPos = hist.size() - ( ( smoothened.size() - static_cast< size_t > ( peaks.at(peaks.size()-1) ) ) + ( ( static_cast< size_t > ( windowSize ) + 1 ) / 2 ) ); }
4220  else { bestHistPos = 0; }
4221  threshold = ( static_cast< proshade_double > ( bestHistPos ) * step );
4222 
4223  //================================================ Check that the threshold is not higher than the highest value
4224  proshade_double maxVal = 0.0;
4225  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( CSym->size() ); symIt++ ) { if ( maxVal < CSym->at(symIt).at(peakPos) ) { maxVal = CSym->at(symIt).at(peakPos); } }
4226  if ( maxVal < threshold ) { threshold = maxVal - step; }
4227 
4228  //================================================ Done
4229  return ( threshold );
4230 
4231 }
4232 
4242 void ProSHADE_internal_maths::combineFourierForTranslation ( fftw_complex* tmpOut1, fftw_complex* tmpOut2, fftw_complex*& resOut, proshade_unsign xD, proshade_unsign yD, proshade_unsign zD )
4243 {
4244  //================================================ Initialise local variables
4245  double normFactor = static_cast<double> ( xD * yD * zD );
4246  proshade_signed arrPos;
4247 
4248  //================================================ Combine the coefficients
4249  for ( proshade_signed xIt = 0; xIt < static_cast< proshade_signed > ( xD ); xIt++ )
4250  {
4251  for ( proshade_signed yIt = 0; yIt < static_cast< proshade_signed > ( yD ); yIt++ )
4252  {
4253  for ( proshade_signed zIt = 0; zIt < static_cast< proshade_signed > ( zD ); zIt++ )
4254  {
4255  //==================================== Find indices
4256  arrPos = zIt + static_cast< proshade_signed > ( zD ) * ( yIt + static_cast< proshade_signed > ( yD ) * xIt );
4257 
4258  //==================================== Combine
4260  &tmpOut1[arrPos][1],
4261  &tmpOut2[arrPos][0],
4262  &tmpOut2[arrPos][1],
4263  &resOut[arrPos][0],
4264  &resOut[arrPos][1] );
4265 
4266  //==================================== Save
4267  resOut[arrPos][0] /= normFactor;
4268  resOut[arrPos][1] /= normFactor;
4269  }
4270  }
4271  }
4272 
4273  //================================================ Done
4274  return ;
4275 
4276 }
4277 
4289 void ProSHADE_internal_maths::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 )
4290 {
4291  //================================================ Initialise variables
4292  proshade_signed arrPos;
4293  *mapPeak = 0.0;
4294 
4295  //================================================ Search the map
4296  for ( proshade_signed uIt = 0; uIt < static_cast<proshade_signed> ( xD ); uIt++ )
4297  {
4298  for ( proshade_signed vIt = 0; vIt < static_cast<proshade_signed> ( yD ); vIt++ )
4299  {
4300  for ( proshade_signed wIt = 0; wIt < static_cast<proshade_signed> ( zD ); wIt++ )
4301  {
4302  arrPos = wIt + static_cast< proshade_signed > ( zD ) * ( vIt + static_cast< proshade_signed > ( yD ) * uIt );
4303  if ( resIn[arrPos][0] > *mapPeak )
4304  {
4305  *mapPeak = resIn[arrPos][0];
4306  *trsX = static_cast< proshade_double > ( uIt );
4307  *trsY = static_cast< proshade_double > ( vIt );
4308  *trsZ = static_cast< proshade_double > ( wIt );
4309  }
4310  }
4311  }
4312  }
4313 
4314  //================================================ Done
4315  return ;
4316 
4317 }
ProSHADE_internal_maths::getSOFTPositionFromEulerZYZ
void getSOFTPositionFromEulerZYZ(proshade_signed band, proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double *x, proshade_double *y, proshade_double *z)
Function to find the index position in the inverse SOFT map from given Euler angles (ZYZ convention).
Definition: ProSHADE_maths.cpp:991
ProSHADE_internal_maths::gaussLegendreIntegration
void gaussLegendreIntegration(proshade_complex *vals, proshade_unsign valsSize, proshade_unsign order, proshade_double *abscissas, proshade_double *weights, proshade_double integralOverRange, proshade_double maxSphereDists, proshade_double *retReal, proshade_double *retImag)
Function to compute the complete complex Gauss-Legendre integration over spherical harmonic values in...
Definition: ProSHADE_maths.cpp:714
ProSHADE_internal_maths::findVectorFromThreeVAndThreeD
std::vector< proshade_double > findVectorFromThreeVAndThreeD(proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2, proshade_double x3, proshade_double y3, proshade_double z3, proshade_double dot1, proshade_double dot2, proshade_double dot3)
Function for finding a vector which would have a given three dot products to three other vectors.
Definition: ProSHADE_maths.cpp:2479
ProSHADE_internal_maths::getEulerZYZFromSOFTPosition
void getEulerZYZFromSOFTPosition(proshade_signed band, proshade_signed x, proshade_signed y, proshade_signed z, proshade_double *eulerAlpha, proshade_double *eulerBeta, proshade_double *eulerGamma)
Function to find Euler angles (ZYZ convention) from index position in the inverse SOFT map.
Definition: ProSHADE_maths.cpp:966
ProSHADE_internal_maths::computeTrFunStep
proshade_double * computeTrFunStep(proshade_double *firstDers, proshade_double *secondDers)
This function computes the step sizes for translation function optimisation from the first and second...
Definition: ProSHADE_maths.cpp:4019
ProSHADE_internal_maths::gaussLegendreIntegrationReal
proshade_double gaussLegendreIntegrationReal(proshade_double *vals, proshade_unsign valsSize, proshade_unsign order, proshade_double *abscissas, proshade_double *weights, proshade_double integralOverRange, proshade_double maxSphereDists)
Function to compute real part of the Gauss-Legendre integration over spherical harmonic values in dif...
Definition: ProSHADE_maths.cpp:624
ProSHADE_internal_maths::vectorMeanAndSD
void vectorMeanAndSD(std::vector< proshade_double > *vec, proshade_double *&ret)
Function to get vector mean and standard deviation.
Definition: ProSHADE_maths.cpp:121
ProSHADE_internal_maths::prepareBiCubicInterpolatorsMinusPlus
void prepareBiCubicInterpolatorsMinusPlus(proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
This function prepares the interpolation objects for the bi-cubic interpolation.
Definition: ProSHADE_maths.cpp:2899
ProSHADE_internal_maths::isPrime
bool isPrime(proshade_unsign toCheck)
This function check is the supplied number is prime or not.
Definition: ProSHADE_maths.cpp:3259
ProSHADE_internal_maths::whichAxisUnique
proshade_signed whichAxisUnique(std::vector< proshade_double * > *CSymList, proshade_double *axis, proshade_double tolerance)
This function checks if new axis is unique, or already detected and returns the position of match or ...
Definition: ProSHADE_maths.cpp:3150
ProSHADE_internal_maths::computeTheFValue
proshade_double computeTheFValue(proshade_complex *fCoeffs, proshade_double *weights, proshade_signed xDim, proshade_signed yDim, proshade_signed zDim)
This function computes the real part of the sum of all coefficients except where the weight is less t...
Definition: ProSHADE_maths.cpp:3892
ProSHADE_internal_maths::rotationMatrixSimilarityValue
proshade_double rotationMatrixSimilarityValue(std::vector< proshade_double > *mat1, std::vector< proshade_double > *mat2)
This function computes the distance between two rotation matrices and returns it.
Definition: ProSHADE_maths.cpp:2624
ProSHADE_internal_maths::computeCrossProduct
proshade_double * computeCrossProduct(proshade_double *x1, proshade_double *y1, proshade_double *z1, proshade_double *x2, proshade_double *y2, proshade_double *z2)
Simple 3D vector cross product computation.
Definition: ProSHADE_maths.cpp:1817
ProSHADE_internal_maths::computeFSC
proshade_double computeFSC(fftw_complex *fCoeffs1, fftw_complex *fCoeffs2, proshade_signed xInds, proshade_signed yInds, proshade_signed zInds, proshade_signed noBins, proshade_signed *binIndexing, proshade_double **&binData, proshade_signed *&binCounts, proshade_double *&fscByBin, bool averageByBinSize=false)
This function computes the FSC.
Definition: ProSHADE_maths.cpp:3693
ProSHADE_exception
This class is the representation of ProSHADE exception.
Definition: ProSHADE_exceptions.hpp:37
ProSHADE_internal_maths::normalDistributionValue
proshade_double normalDistributionValue(proshade_double mean, proshade_double standardDev, proshade_double value)
Function to the heiht of normal distribution given by mean and standard deviation for a given value.
Definition: ProSHADE_maths.cpp:1768
ProSHADE_internal_maths::prepareBiCubicInterpolatorsPlusMinus
void prepareBiCubicInterpolatorsPlusMinus(proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
This function prepares the interpolation objects for the bi-cubic interpolation.
Definition: ProSHADE_maths.cpp:2954
ProSHADE_internal_maths::getGLFirstRealRoot
void getGLFirstRealRoot(proshade_double polyAtZero, proshade_unsign order, proshade_double *abscAtZero, proshade_double *weighAtZero, proshade_unsign taylorSeriesCap)
This function finds the first root for Legendre polynomials of odd order.
Definition: ProSHADE_maths.cpp:386
ProSHADE_internal_maths::getRotationMatrixFromEulerZYZAngles
void getRotationMatrixFromEulerZYZAngles(proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double *matrix)
Function to find the rotation matrix from Euler angles (ZYZ convention).
Definition: ProSHADE_maths.cpp:1019
ProSHADE_internal_maths::build3x3MatrixFromDiag
proshade_double * build3x3MatrixFromDiag(proshade_double *diag)
Function for building a 3x3 matrix from diagonal (and assuming zero padding).
Definition: ProSHADE_maths.cpp:2028
ProSHADE_maths.hpp
This header file declares all the functions required for computing various information from the ProSH...
ProSHADE_internal_maths::advanceGLPolyValue
proshade_double advanceGLPolyValue(proshade_double from, proshade_double to, proshade_double valAtFrom, proshade_unsign order, proshade_unsign noSteps)
This function finds the next value of a Legendre polynomial using the Runge-Kutta method.
Definition: ProSHADE_maths.cpp:480
ProSHADE_internal_maths::complexMultiplication
void complexMultiplication(proshade_double *r1, proshade_double *i1, proshade_double *r2, proshade_double *i2, proshade_double *retReal, proshade_double *retImag)
Function to multiply two complex numbers.
Definition: ProSHADE_maths.cpp:38
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_internal_maths::optimiseAxisBiCubicInterpolation
void optimiseAxisBiCubicInterpolation(proshade_double *bestLattitude, proshade_double *bestLongitude, proshade_double *bestSum, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun, proshade_double step=0.05)
This function provides axis optimisation given starting lattitude and longitude indices.
Definition: ProSHADE_maths.cpp:2744
ProSHADE_internal_maths::vectorOrientationSimilarity
bool vectorOrientationSimilarity(proshade_double a1, proshade_double a2, proshade_double a3, proshade_double b1, proshade_double b2, proshade_double b3, proshade_double tolerance=0.1)
This function compares two vectors using cosine distance and decides if they are similar using tolera...
Definition: ProSHADE_maths.cpp:2680
ProSHADE_internal_maths::complexMatrixSVDSigmasOnly
void complexMatrixSVDSigmasOnly(proshade_complex **mat, int dim, double *&singularValues)
Function to compute the complete complex matrix SVD and return only the sigmas.
Definition: ProSHADE_maths.cpp:807
ProSHADE_internal_maths::prepareBiCubicInterpolatorsMinusMinus
void prepareBiCubicInterpolatorsMinusMinus(proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
This function prepares the interpolation objects for the bi-cubic interpolation.
Definition: ProSHADE_maths.cpp:2844
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_maths::vectorOrientationSimilaritySameDirection
bool vectorOrientationSimilaritySameDirection(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:2714
ProSHADE_internal_maths::computeGaussian
proshade_double computeGaussian(proshade_double val, proshade_double sigma)
This function computes a Gaussian (normal) distribution value given distance from mean and sigma.
Definition: ProSHADE_maths.cpp:3286
ProSHADE_internal_maths::getEulerZYZFromRotMatrix
void getEulerZYZFromRotMatrix(proshade_double *rotMat, proshade_double *eA, proshade_double *eB, proshade_double *eG)
This function converts rotation matrix to the Euler ZYZ angles representation.
Definition: ProSHADE_maths.cpp:1561
ProSHADE_internal_maths::cutIndicesToResolution
void cutIndicesToResolution(proshade_signed xInds, proshade_signed yInds, proshade_signed zInds, proshade_single resolution, proshade_signed *binIndexing, std::vector< proshade_single > *resArray, proshade_signed *cutXDim, proshade_signed *cutYDim, proshade_signed *cutZDim, proshade_signed *&cutBinIndices, proshade_signed *&noBins)
This function cuts the bin assignment array into a smaller array containing all bins up to a given re...
Definition: ProSHADE_maths.cpp:3563
ProSHADE_internal_maths::pearsonCorrCoeff
proshade_double pearsonCorrCoeff(proshade_double *valSet1, proshade_double *valSet2, proshade_unsign length)
Function for computing the Pearson's correlation coefficient.
Definition: ProSHADE_maths.cpp:246
ProSHADE_internal_maths::computeDotProduct
proshade_double computeDotProduct(proshade_double *x1, proshade_double *y1, proshade_double *z1, proshade_double *x2, proshade_double *y2, proshade_double *z2)
Simple 3D vector dot product computation.
Definition: ProSHADE_maths.cpp:1785
ProSHADE_internal_misc::addToSignedVector
void addToSignedVector(std::vector< proshade_signed > *vecToAddTo, proshade_signed elementToAdd)
Adds the element to the vector.
Definition: ProSHADE_misc.cpp:121
ProSHADE_internal_maths::findPeaks1D
std::vector< proshade_signed > findPeaks1D(std::vector< proshade_double > data)
This function simply finds all the peaks in a 1D data array.
Definition: ProSHADE_maths.cpp:4047
ProSHADE_internal_maths::complexMultiplicationConjugRealOnly
proshade_double complexMultiplicationConjugRealOnly(proshade_double *r1, proshade_double *i1, proshade_double *r2, proshade_double *i2)
Function to conjuggate multiply two complex numbers and return the real part only.
Definition: ProSHADE_maths.cpp:103
ProSHADE_internal_maths::getRotationMatrixFromAngleAxis
void getRotationMatrixFromAngleAxis(proshade_double *rotMat, proshade_double x, proshade_double y, proshade_double z, proshade_double ang)
This function converts the axis-angle representation to the rotation matrix representation.
Definition: ProSHADE_maths.cpp:1458
ProSHADE_internal_maths::findHighestValueInMap
void findHighestValueInMap(fftw_complex *resIn, proshade_unsign xD, proshade_unsign yD, proshade_unsign zD, proshade_double *trsX, proshade_double *trsY, proshade_double *trsZ, proshade_double *mapPeak)
This function simply finds the highest value in fftw_complex map and returns its position and value.
Definition: ProSHADE_maths.cpp:4289
ProSHADE_internal_maths::getAxisAngleFromRotationMatrix
void getAxisAngleFromRotationMatrix(proshade_double *rotMat, proshade_double *x, proshade_double *y, proshade_double *z, proshade_double *ang, proshade_signed verbose=1)
This function converts rotation matrix to the axis-angle representation.
Definition: ProSHADE_maths.cpp:1083
ProSHADE_internal_maths::build3x3MatrixFromXYZRotations
proshade_double * build3x3MatrixFromXYZRotations(proshade_double xRot, proshade_double yRot, proshade_double zRot)
Function for building a 3x3 rotation matrix from the x, y and z rotations in degrees.
Definition: ProSHADE_maths.cpp:2057
ProSHADE_internal_maths::getEulerZYZFromAngleAxis
void getEulerZYZFromAngleAxis(proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double axAng, proshade_double *eA, proshade_double *eB, proshade_double *eG)
This function converts angle-axis representation to the Euler ZYZ angles representation.
Definition: ProSHADE_maths.cpp:1612
ProSHADE_internal_maths::realMatrixSVDUandVOnly
void realMatrixSVDUandVOnly(proshade_double *mat, int dim, proshade_double *uAndV, bool fail=true)
Function to compute the real matrix SVD and return the U and V matrices.
Definition: ProSHADE_maths.cpp:874
ProSHADE_internal_maths::combineFourierForTranslation
void combineFourierForTranslation(fftw_complex *tmpOut1, fftw_complex *tmpOut2, fftw_complex *&resOut, proshade_unsign xD, proshade_unsign yD, proshade_unsign zD)
This function combines Fourier coefficients of two structures in a way, so that inverse Fourier of th...
Definition: ProSHADE_maths.cpp:4242
ProSHADE_internal_maths::BicubicInterpolator
Definition: ProSHADE_maths.hpp:112
ProSHADE_internal_maths::primeFactorsDecomp
std::vector< proshade_signed > primeFactorsDecomp(proshade_signed number)
Function to find prime factors of an integer.
Definition: ProSHADE_maths.cpp:1719
ProSHADE_internal_maths::getGLPolyAtZero
void getGLPolyAtZero(proshade_unsign order, proshade_double *polyValue, proshade_double *deriValue)
This function obtains the Legendre polynomial values and its derivative at zero for any positive inte...
Definition: ProSHADE_maths.cpp:349
ProSHADE_internal_maths::isAxisUnique
bool isAxisUnique(std::vector< proshade_double * > *CSymList, proshade_double *axis, proshade_double tolerance=0.1, bool improve=false)
This function checks if new axis is unique, or already detected.
Definition: ProSHADE_maths.cpp:3064
ProSHADE_internal_maths::completeAbscissasAndWeights
void completeAbscissasAndWeights(proshade_unsign order, proshade_double *abscissa, proshade_double *weights, proshade_unsign noSteps)
This function completes the abscissas and weights series from the first roots computed beforehand.
Definition: ProSHADE_maths.cpp:524
ProSHADE_internal_maths::findRotMatMatchingVectors
proshade_double * findRotMatMatchingVectors(proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2)
Computation of rotation matrix rotating one vector onto the other.
Definition: ProSHADE_maths.cpp:2119
ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication
proshade_double * compute3x3MatrixVectorMultiplication(proshade_double *mat, proshade_double x, proshade_double y, proshade_double z)
Function for computing a 3x3 matrix to 3x1 vector multiplication.
Definition: ProSHADE_maths.cpp:1895
ProSHADE_internal_maths::compute3x3MoorePenrosePseudoInverseOfIMinusMat
proshade_double * compute3x3MoorePenrosePseudoInverseOfIMinusMat(std::vector< proshade_double > *rMat, proshade_signed verbose)
This function computes the Moore-Penrose pseudo-inverse of equation I - input matrix.
Definition: ProSHADE_maths.cpp:2186
ProSHADE_internal_maths::rotationMatrixSimilarity
bool rotationMatrixSimilarity(std::vector< proshade_double > *mat1, std::vector< proshade_double > *mat2, proshade_double tolerance=0.1)
This function compares the distance between two rotation matrices and decides if they are similar usi...
Definition: ProSHADE_maths.cpp:2576
ProSHADE_internal_misc::checkMemoryAllocation
void checkMemoryAllocation(chVar checkVar, std::string fileP, unsigned int lineP, std::string funcP, std::string infoP="This error may occurs when ProSHADE requests memory to be\n : allocated to it and this operation fails. This could\n : happen when not enough memory is available, either due to\n : other processes using a lot of memory, or when the machine\n : does not have sufficient memory available. Re-run to see\n : if this problem persists.")
Checks if memory was allocated properly.
Definition: ProSHADE_misc.hpp:73
ProSHADE_internal_maths::vectorMedianAndIQR
void vectorMedianAndIQR(std::vector< proshade_double > *vec, proshade_double *&ret)
Function to get vector median and inter-quartile range.
Definition: ProSHADE_maths.cpp:149
ProSHADE_internal_maths::computeTrFunDerivatives
void computeTrFunDerivatives(proshade_complex *fCoeffs, proshade_double *weights1, proshade_double *weights2, proshade_signed xDim, proshade_signed yDim, proshade_signed zDim, proshade_double *&firstDers, proshade_double *&secondDers)
This function computes the first and second derivatives of the translation function at coefficient [0...
Definition: ProSHADE_maths.cpp:3930
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_maths::cutArrayToResolution
void cutArrayToResolution(proshade_signed xInds, proshade_signed yInds, proshade_signed zInds, proshade_signed noBins, fftw_complex *inputMap, fftw_complex *&cutMap)
This function re-sizes data array to contain only values up to a particular resolution bin.
Definition: ProSHADE_maths.cpp:3628
ProSHADE_internal_maths::complexMultiplicationConjug
void complexMultiplicationConjug(proshade_double *r1, proshade_double *i1, proshade_double *r2, proshade_double *i2, proshade_double *retReal, proshade_double *retImag)
Function to multiply two complex numbers by using the second number's conjugate.
Definition: ProSHADE_maths.cpp:62
ProSHADE_internal_maths::smoothen1D
std::vector< proshade_double > smoothen1D(proshade_double step, proshade_signed windowSize, proshade_double sigma, std::vector< proshade_double > data, proshade_signed decRound=2)
This function takes a 1D vector and computes smoothened version based on the parameters.
Definition: ProSHADE_maths.cpp:3313
ProSHADE_internal_maths::getLegendreAbscAndWeights
void getLegendreAbscAndWeights(proshade_unsign order, proshade_double *abscissas, proshade_double *weights, proshade_unsign noSteps)
Function to prepare abscissas and weights for Gauss-Legendre integration using the Glaser-Liu-Rokhlin...
Definition: ProSHADE_maths.cpp:289
ProSHADE_internal_misc::addToSingleVector
void addToSingleVector(std::vector< proshade_single > *vecToAddTo, proshade_single elementToAdd)
Adds the element to the vector.
Definition: ProSHADE_misc.cpp:55
ProSHADE_internal_maths::findVectorFromTwoVAndTwoD
std::vector< proshade_double > findVectorFromTwoVAndTwoD(proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2, proshade_double dot1, proshade_double dot2)
Function for finding a vector which would have a given two dot products to two other vectors.
Definition: ProSHADE_maths.cpp:2333
ProSHADE_internal_maths::prepareBiCubicInterpolatorsPlusPlus
void prepareBiCubicInterpolatorsPlusPlus(proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
This function prepares the interpolation objects for the bi-cubic interpolation.
Definition: ProSHADE_maths.cpp:3009
ProSHADE_internal_maths::multiplyTwoSquareMatrices
void multiplyTwoSquareMatrices(proshade_double *A, proshade_double *B, proshade_double *res, proshade_unsign dim=3)
Function to compute matrix multiplication.
Definition: ProSHADE_maths.cpp:1693
ProSHADE_internal_maths::getResolutionOfReflection
proshade_single getResolutionOfReflection(proshade_single h, proshade_single k, proshade_single l, proshade_single xDim, proshade_single yDim, proshade_single zDim)
This function computes the resolution of a particular reflection.
Definition: ProSHADE_maths.cpp:3359
ProSHADE_internal_maths::computeFSCWeightByBin
void computeFSCWeightByBin(proshade_double *&weights1, proshade_double *&weights2, proshade_signed *binIndexing, proshade_double *fscByBin, proshade_signed noBins, proshade_signed xDim, proshade_signed yDim, proshade_signed zDim)
This function computes the weights for each reflection using its bin belonging.
Definition: ProSHADE_maths.cpp:3800
ProSHADE_internal_maths::findTopGroupSmooth
proshade_double findTopGroupSmooth(std::vector< proshade_double * > *CSym, size_t peakPos, proshade_double step, proshade_double sigma, proshade_signed windowSize, proshade_double maxLim=1.0)
This function finds a subgroup of axes with distinctly higher correlation value.
Definition: ProSHADE_maths.cpp:4113
ProSHADE_internal_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:3218
ProSHADE_internal_maths::compute3x3MatrixInverse
proshade_double * compute3x3MatrixInverse(proshade_double *mat)
Function for computing a 3x3 matrix inverse.
Definition: ProSHADE_maths.cpp:1940
ProSHADE_internal_maths::arrayMedianAndIQR
void arrayMedianAndIQR(proshade_double *vec, proshade_unsign vecSize, proshade_double *&ret)
Function to get array median and inter-quartile range.
Definition: ProSHADE_maths.cpp:200
ProSHADE_internal_maths::binReciprocalSpaceReflections
void binReciprocalSpaceReflections(proshade_unsign xInds, proshade_unsign yInds, proshade_unsign zInds, proshade_single xSize, proshade_single ySize, proshade_single zSize, proshade_signed *noBin, proshade_signed *&binIndexing, std::vector< proshade_single > *&resArray)
This function does binning of the reciprocal space reflections.
Definition: ProSHADE_maths.cpp:3397
ProSHADE_internal_maths::multiplyGroupElementMatrices
std::vector< proshade_double > multiplyGroupElementMatrices(std::vector< proshade_double > *el1, std::vector< proshade_double > *el2)
This function computes matrix multiplication using the ProSHADE group element matrix format as input ...
Definition: ProSHADE_maths.cpp:2523
ProSHADE_internal_maths::evaluateGLPolynomial
proshade_double evaluateGLPolynomial(proshade_double *series, proshade_double target, proshade_unsign terms)
This function evaluates the decomposed Legendre polynomial at a given position.
Definition: ProSHADE_maths.cpp:450
ProSHADE_internal_maths::transpose3x3MatrixInPlace
void transpose3x3MatrixInPlace(proshade_single *mat)
Transposes 3x3 matrix in place.
Definition: ProSHADE_maths.cpp:1973
ProSHADE_internal_maths::complexMultiplicationRealOnly
proshade_double complexMultiplicationRealOnly(proshade_double *r1, proshade_double *i1, proshade_double *r2, proshade_double *i2)
Function to multiply two complex numbers and return the real part only.
Definition: ProSHADE_maths.cpp:83
ProSHADE_internal_maths::compute3x3MatrixMultiplication
proshade_double * compute3x3MatrixMultiplication(proshade_double *mat1, proshade_double *mat2)
Function for computing a 3x3 matrix multiplication.
Definition: ProSHADE_maths.cpp:1865