ProSHADE  0.7.6.2 (DEC 2021)
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 taylorSeriesCap )
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 ...
308  if ( order % 2 == 1 )
309  {
310  abscissas[((order-1)/2)] = polyValue;
311  weights[((order-1)/2)] = deriValue;
312  }
313  else
314  {
315  // ... and if order is even, find the first root
316  getGLFirstEvenRoot ( polyValue, order, &abscissas[(order/2)], &weights[(order/2)], taylorSeriesCap );
317  }
318 
319  //================================================ Now, having computed the first roots, complete the series
320  completeLegendreSeries ( order, abscissas, weights, taylorSeriesCap );
321 
322  //================================================ Correct weights by anscissa 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 = 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::getGLFirstEvenRoot ( proshade_double polyAtZero, proshade_unsign order, proshade_double *abscAtZero, proshade_double *weighAtZero, proshade_unsign taylorSeriesCap )
387 {
388  //================================================ Sanity check
389  if ( taylorSeriesCap < 2 )
390  {
391  throw ProSHADE_exception ( "The Taylor series cap is too low.", "EI00020", __FILE__, __LINE__, __func__, "The Taylor series expansion 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  *abscAtZero = advanceGLPolyValue ( 0.0, -M_PI / 2.0, 0.0, order, taylorSeriesCap );
396  proshade_double hlp = 0.0;
397  proshade_double hlpVal = static_cast<proshade_double> ( order );
398  proshade_double *abscSteps;
399  proshade_double *weightSteps;
400 
401  //================================================ Allocate memory
402  abscSteps = new proshade_double [taylorSeriesCap+2];
403  weightSteps = new proshade_double [taylorSeriesCap+1];
404 
405  //================================================ Pre-set values
406  abscSteps[0] = 0.0;
407  abscSteps[1] = polyAtZero;
408  weightSteps[0] = 0.0;
409 
410  //================================================ Fill in abscissa and weight steps
411  for ( proshade_unsign iter = 0; iter <= taylorSeriesCap - 2; iter = iter + 2 )
412  {
413  hlp = static_cast<proshade_double> ( iter );
414 
415  abscSteps[iter+2] = 0.0;
416  abscSteps[iter+3] = ( hlp * ( hlp + 1.0 ) - hlpVal * ( hlpVal + 1.0 ) ) * abscSteps[iter+1] / (hlp + 1.0) / (hlp + 2.0 );
417 
418  weightSteps[iter+1] = 0.0;
419  weightSteps[iter+2] = ( hlp + 2.0 ) * abscSteps[iter+3];
420  }
421 
422  //================================================ Find abscissa and weights
423  for ( proshade_double iter = 0; iter < 5; iter++ )
424  {
425  *abscAtZero = *abscAtZero - evaluateGLSeries ( abscSteps, *abscAtZero, taylorSeriesCap ) / evaluateGLSeries ( weightSteps, *abscAtZero, taylorSeriesCap-1 );
426  }
427  *weighAtZero = evaluateGLSeries ( weightSteps, *abscAtZero, taylorSeriesCap-1 );
428 
429  //================================================ Free memory
430  delete abscSteps;
431  delete weightSteps;
432 
433  //================================================ Done
434  return ;
435 
436 }
437 
449 proshade_double ProSHADE_internal_maths::evaluateGLSeries ( proshade_double *series, proshade_double target, proshade_unsign terms )
450 {
451  //================================================ Initalise
452  proshade_double factorialValue = 1.0;
453  proshade_double value = 0.0;
454 
455  //================================================ Compute
456  for ( proshade_unsign iter = 1; iter <= terms; iter++ )
457  {
458  value = value + series[iter] * factorialValue;
459  factorialValue = factorialValue * target;
460  }
461 
462  //================================================ Done
463  return ( value );
464 
465 }
466 
479 proshade_double ProSHADE_internal_maths::advanceGLPolyValue ( proshade_double from, proshade_double to, proshade_double valAtFrom, proshade_unsign noSteps, proshade_unsign taylorSeriesCap )
480 {
481  //================================================ Initialise variables
482  proshade_double hlpVal = 0.0;
483  proshade_double stepSize = 0.0;
484  proshade_double valChange = 0.0;
485  proshade_double valSecChange = 0.0;
486  proshade_double squareSteps = 0.0;
487  proshade_double curVal = 0.0;
488 
489  //================================================ Set initial values
490  stepSize = ( to - from ) / static_cast<proshade_double> ( taylorSeriesCap );
491  squareSteps = sqrt ( static_cast<proshade_double> ( noSteps * ( noSteps + 1 ) ) );
492  curVal = from;
493 
494  //================================================ Go through the series and iteratively improve the estimate
495  for ( proshade_unsign iter = 0; iter < taylorSeriesCap; iter++ )
496  {
497  hlpVal = ( 1.0 - valAtFrom ) * ( 1.0 + valAtFrom );
498  valChange = - stepSize * hlpVal / ( squareSteps * sqrt ( hlpVal ) - 0.5 * valAtFrom * sin ( 2.0 * curVal ) );
499  valAtFrom = valAtFrom + valChange;
500 
501  curVal = curVal + stepSize;
502 
503  hlpVal = ( 1.0 - valAtFrom ) * ( 1.0 + valAtFrom );
504  valSecChange = - stepSize * hlpVal / ( squareSteps * sqrt ( hlpVal ) - 0.5 * valAtFrom * sin ( 2.0 * curVal ) );
505  valAtFrom = valAtFrom + 0.5 * ( valSecChange - valChange );
506  }
507 
508  //================================================ Done
509  return valAtFrom;
510 
511 }
512 
523 void ProSHADE_internal_maths::completeLegendreSeries ( proshade_unsign order, proshade_double* abscissas, proshade_double* weights, proshade_unsign taylorSeriesCap )
524 {
525  //================================================ Initialise internal variables
526  proshade_double hlpTaylorVal = 0.0;
527  proshade_double hlpOrderVal = static_cast<proshade_double> ( order );
528  proshade_double abscValueChange = 0.0;
529  proshade_double prevAbsc = 0.0;
530  proshade_double *hlpAbscSeries;
531  proshade_double *hlpWeightSeries;
532  proshade_unsign noSeriesElems = 0;
533  proshade_unsign oddEvenSwitch = 0;
534 
535  //================================================ Pre-set internal values
536  if ( order % 2 == 1 )
537  {
538  noSeriesElems = ( order - 1 ) / 2 - 1;
539  oddEvenSwitch = 1;
540  }
541  else
542  {
543  noSeriesElems = order / 2 - 1;
544  oddEvenSwitch = 0;
545  }
546 
547  //================================================ Allocate memory
548  hlpAbscSeries = new proshade_double[taylorSeriesCap+2];
549  hlpWeightSeries = new proshade_double[taylorSeriesCap+1];
550 
551  //================================================ For each series element
552  for ( proshade_unsign serIt = noSeriesElems + 1; serIt < order - 1; serIt++ )
553  {
554  //============================================ Init loop
555  prevAbsc = abscissas[serIt];
556  abscValueChange = advanceGLPolyValue ( M_PI/2.0, -M_PI/2.0, prevAbsc, order, taylorSeriesCap ) - prevAbsc;
557 
558  //============================================ Init abscissas
559  hlpAbscSeries[0] = 0.0;
560  hlpAbscSeries[1] = 0.0;
561  hlpAbscSeries[2] = weights[serIt];
562 
563  //============================================ Init weights
564  hlpWeightSeries[0] = 0.0;
565  hlpWeightSeries[1] = hlpAbscSeries[2];
566 
567  //============================================ Taylor expansion
568  for ( proshade_unsign tayIt = 0; tayIt <= taylorSeriesCap - 2; tayIt++ )
569  {
570  hlpTaylorVal = static_cast<proshade_double> ( tayIt );
571 
572  hlpAbscSeries[tayIt+3] = ( 2.0 * prevAbsc * ( hlpTaylorVal + 1.0 ) * hlpAbscSeries[tayIt+2] + ( hlpTaylorVal * ( hlpTaylorVal + 1.0 ) - hlpOrderVal *
573  ( hlpOrderVal + 1.0 ) ) * hlpAbscSeries[tayIt+1] / ( hlpTaylorVal + 1.0 ) ) / ( 1.0 - prevAbsc ) / ( 1.0 + prevAbsc ) /
574  ( hlpTaylorVal + 2.0 );
575 
576  hlpWeightSeries[tayIt+2] = ( hlpTaylorVal + 2.0 ) * hlpAbscSeries[tayIt+3];
577  }
578 
579  //============================================ Sum over results
580  for ( proshade_unsign iter = 0; iter < 5; iter++ )
581  {
582  abscValueChange = abscValueChange - evaluateGLSeries ( hlpAbscSeries, abscValueChange, taylorSeriesCap ) /
583  evaluateGLSeries ( hlpWeightSeries, abscValueChange, taylorSeriesCap-1 );
584  }
585 
586  //============================================ Save results
587  abscissas[serIt+1] = prevAbsc + abscValueChange;
588  weights[serIt+1] = evaluateGLSeries ( hlpWeightSeries, abscValueChange, taylorSeriesCap - 1 );
589  }
590 
591  for ( proshade_unsign serIt = 0; serIt <= noSeriesElems + oddEvenSwitch; serIt++ )
592  {
593  abscissas[serIt] = -abscissas[order-serIt-1];
594  weights[serIt] = weights[order-serIt-1];
595  }
596 
597  //================================================ Free memory
598  delete hlpAbscSeries;
599  delete hlpWeightSeries;
600 
601  //================================================ Done
602  return ;
603 
604 }
605 
621 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 )
622 {
623  //================================================ Initialise local variables
624  proshade_double ret = 0.0;
625  proshade_complex* intData = new proshade_complex[order];
626  ProSHADE_internal_misc::checkMemoryAllocation ( intData, __FILE__, __LINE__, __func__ );
627  proshade_complex posVals;
628  proshade_unsign lesserPos = 0;
629  proshade_unsign upperPos = 0;
630  proshade_double lesserWeight = 0.0;
631  proshade_double upperWeight = 0.0;
632 
633  //================================================ Rescale to <order> points
634  for ( proshade_unsign absIter = 0; absIter < order; absIter++ )
635  {
636  //============================================ Init loop
637  posVals[0] = 0.0;
638  posVals[1] = 0.0;
639 
640  //============================================ Find real position of abscissas
641  posVals[0] = ( ( abscissas[absIter] + 1.0 ) / 2.0 ) * integralOverRange;
642 
643 
644  //============================================ Find lesser and upper bounds
645  for ( proshade_unsign valIt = 0; valIt < valsSize; valIt++ )
646  {
647  if ( ( ( static_cast< proshade_double > ( valIt ) * maxSphereDists ) <= posVals[0] ) && ( ( ( static_cast< proshade_double > ( valIt ) + 1.0 ) * maxSphereDists ) > posVals[0] ) )
648  {
649  lesserPos = static_cast<proshade_unsign> ( valIt );
650  upperPos = static_cast<proshade_unsign> ( valIt + 1 );
651  break;
652  }
653  }
654 
655  //============================================ Linear Interpolation
656  lesserWeight = 0.0;
657  upperWeight = 0.0;
658  if ( lesserPos != 0 )
659  {
660  //======================================== 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 ...
661  lesserWeight = static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists );
662  upperWeight = 1.0 - lesserWeight;
663 
664  posVals[1] = ( lesserWeight * vals[lesserPos-1] ) + ( upperWeight * vals[upperPos-1] );
665  }
666  else
667  {
668  //======================================== ... 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:
669  upperWeight = 1.0 - ( static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists ) );
670 
671  posVals[1] = ( upperWeight * vals[upperPos-1] );
672  }
673 
674  intData[absIter][0] = posVals[0];
675  intData[absIter][1] = posVals[1];
676  }
677 
678  //================================================ Integrate
679  for ( proshade_unsign absPoint = 0; absPoint < order; absPoint++ )
680  {
681  ret += ( weights[absPoint] * intData[absPoint][1] );
682  }
683 
684  //================================================ Normalise
685  ret *= ( integralOverRange / 2.0 );
686 
687  //================================================ Release memory
688  delete[] intData;
689 
690  //================================================ Done
691  return ( ret );
692 
693 }
694 
711 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 )
712 {
713  //================================================ Initialise local variables
714  proshade_triplet* intData = new proshade_triplet [order];
715  ProSHADE_internal_misc::checkMemoryAllocation ( intData, __FILE__, __LINE__, __func__ );
716  proshade_triplet posVals;
717  proshade_unsign lesserPos = 0;
718  proshade_unsign upperPos = 0;
719  proshade_double lesserWeight = 0.0;
720  proshade_double upperWeight = 0.0;
721 
722  //================================================ Rescale to <order> points
723  for ( proshade_unsign absIter = 0; absIter < order; absIter++ )
724  {
725  //============================================ Init loop
726  posVals[0] = 0.0;
727  posVals[1] = 0.0;
728  posVals[2] = 0.0;
729 
730  //============================================ Find real position of abscissas
731  posVals[0] = ( ( abscissas[absIter] + 1.0 ) / 2.0 ) * integralOverRange;
732 
733 
734  //============================================ Find lesser and upper bounds
735  for ( proshade_unsign valIt = 0; valIt < valsSize; valIt++ )
736  {
737  if ( ( ( static_cast< proshade_double > ( valIt ) * maxSphereDists ) <= posVals[0] ) && ( ( ( static_cast< proshade_double > ( valIt ) + 1.0 ) * maxSphereDists ) > posVals[0] ) )
738  {
739  lesserPos = static_cast<proshade_unsign> ( valIt );
740  upperPos = static_cast<proshade_unsign> ( valIt + 1 );
741  break;
742  }
743  }
744 
745  //============================================ Linear Interpolation
746  lesserWeight = 0.0;
747  upperWeight = 0.0;
748  if ( lesserPos != 0 )
749  {
750  //======================================== 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 ...
751  lesserWeight = static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists );
752  upperWeight = 1.0 - lesserWeight;
753 
754  posVals[1] = ( lesserWeight * vals[lesserPos-1][0] ) + ( upperWeight * vals[upperPos-1][0] );
755  posVals[2] = ( lesserWeight * vals[lesserPos-1][1] ) + ( upperWeight * vals[upperPos-1][1] );
756  }
757  else
758  {
759  //======================================== ... 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:
760  upperWeight = 1.0 - ( static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists ) );
761 
762  posVals[1] = ( upperWeight * vals[upperPos-1][0] );
763  posVals[2] = ( upperWeight * vals[upperPos-1][1] );
764  }
765 
766  intData[absIter][0] = posVals[0];
767  intData[absIter][1] = posVals[1];
768  intData[absIter][2] = posVals[2];
769  }
770 
771  //================================================ Integrate
772  *retReal = 0.0;
773  *retImag = 0.0;
774  for ( proshade_unsign absPoint = 0; absPoint < order; absPoint++ )
775  {
776  *retReal += ( weights[absPoint] * intData[absPoint][1] );
777  *retImag += ( weights[absPoint] * intData[absPoint][2] );
778  }
779 
780  //================================================ Normalise
781  *retReal *= ( integralOverRange / 2.0 );
782  *retImag *= ( integralOverRange / 2.0 );
783 
784  //================================================ Release memory
785  delete[] intData;
786 
787  //================================================ Done
788  return ;
789 
790 }
791 
804 void ProSHADE_internal_maths::complexMatrixSVDSigmasOnly ( proshade_complex** mat, int dim, double*& singularValues )
805 {
806  //================================================ Initialise local variables
807  char job = 'N'; // Save computation of parts of U and V matrices, they are not needed here
808  std::complex<double> *rotMatU = new std::complex<double> [dim*dim]; // The U matrix space
809  std::complex<double> *rotMatV = new std::complex<double> [dim*dim]; // The V^T matrix space
810  std::complex<double> *work = new std::complex<double> [( 4 * dim)]; // Workspace, minimum required is 3*dim, using more for performance
811  int workDim = ( 4 * dim); // Formalism stating just that
812  double* rwork = new double[(7 * dim)]; // Required by LAPACK, from 3.7 requires 7 * dim
813  int* iwork = new int[(8 * dim)]; // Required by LAPACK
814  int returnValue = 0; // This will tell if operation succeeded
815 
816  //================================================ Check memory allocation
817  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatU, __FILE__, __LINE__, __func__ );
818  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatV, __FILE__, __LINE__, __func__ );
819  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
820  ProSHADE_internal_misc::checkMemoryAllocation ( rwork, __FILE__, __LINE__, __func__ );
821  ProSHADE_internal_misc::checkMemoryAllocation ( iwork, __FILE__, __LINE__, __func__ );
822 
823  //================================================ Load input data into array in column-major order
824  std::complex<double> *matrixToDecompose = new std::complex<double>[dim*dim];
825  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
826  for ( int rowIt = 0; rowIt < dim; rowIt++ )
827  {
828  for ( int colIt = 0; colIt < dim; colIt++ )
829  {
830  matrixToDecompose[(colIt*dim)+rowIt] = std::complex<double> ( mat[rowIt][colIt][0], mat[rowIt][colIt][1] );
831  }
832  }
833 
834  //================================================ Run LAPACK ZGESDD
835  zgesdd_ ( &job, &dim, &dim, matrixToDecompose, &dim, singularValues, rotMatU, &dim, rotMatV, &dim,
836  work, &workDim, rwork, iwork, &returnValue );
837 
838  //================================================ Free memory
839  delete[] rotMatU;
840  delete[] rotMatV;
841  delete[] work;
842  delete[] rwork;
843  delete[] iwork;
844  delete[] matrixToDecompose;
845 
846  //================================================ Check result
847  if ( returnValue != 0 )
848  {
849  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." );
850  }
851 
852  //================================================ Done
853  return ;
854 
855 }
856 
871 void ProSHADE_internal_maths::realMatrixSVDUandVOnly ( proshade_double* mat, int dim, proshade_double* uAndV, bool fail )
872 {
873  //================================================ Initialise local variables
874  char job = 'A'; // Save computation of parts of U and V matrices, they are not needed here
875  double* singularValues = new double[dim]; // The array of singular values
876  double *rotMatU = new double [dim*dim]; // The U matrix space
877  double *rotMatV = new double [dim*dim]; // The V^T matrix space
878  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
879  int workDim = static_cast< int > ( 2 * ( ( 4 * dim * dim ) + ( 7 * dim ) ) ); // Formalism stating just that
880  double* rwork = new double[static_cast<proshade_unsign>((5 * dim) + 5 * pow(dim,2))]; // Required by LAPACK
881  int* iwork = new int[(8 * dim)]; // Required by LAPACK
882  int returnValue = 0; // This will tell if operation succeeded
883  ProSHADE_internal_misc::checkMemoryAllocation ( singularValues, __FILE__, __LINE__, __func__ );
884  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatU, __FILE__, __LINE__, __func__ );
885  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatV, __FILE__, __LINE__, __func__ );
886  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
887  ProSHADE_internal_misc::checkMemoryAllocation ( rwork, __FILE__, __LINE__, __func__ );
888  ProSHADE_internal_misc::checkMemoryAllocation ( iwork, __FILE__, __LINE__, __func__ );
889 
890  //================================================ Load input data into array in column-major order
891  double *matrixToDecompose = new double[dim*dim];
892  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
893  for ( int rowIt = 0; rowIt < dim; rowIt++ )
894  {
895  for ( int colIt = 0; colIt < dim; colIt++ )
896  {
897  matrixToDecompose[(colIt*dim)+rowIt] = mat[(rowIt*dim)+colIt];
898  }
899  }
900 
901  //================================================ Run LAPACK ZGESDD
902  dgesdd_ ( &job, &dim, &dim, matrixToDecompose, &dim, singularValues, rotMatU, &dim, rotMatV, &dim,
903  work, &workDim, rwork, iwork, &returnValue );
904 
905  //================================================ Free memory
906  delete[] work;
907  delete[] rwork;
908  delete[] iwork;
909  delete[] matrixToDecompose;
910  delete[] singularValues;
911 
912  //================================================ Check result
913  if ( ( returnValue != 0 ) && ( fail ) )
914  {
915  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." );
916  }
917  if ( ( returnValue != 0 ) && ( !fail ) )
918  {
919  uAndV[0] = -777.7;
920  return ;
921  }
922 
923  //================================================ Save U
924  for ( proshade_signed rowIt = 0; rowIt < dim; rowIt++ )
925  {
926  for ( proshade_signed colIt = 0; colIt < dim; colIt++ )
927  {
928  uAndV[(rowIt*3)+colIt] = rotMatU[( rowIt * 3 ) + colIt];
929  }
930  }
931 
932  //================================================ Save V
933  for ( proshade_signed rowIt = 0; rowIt < dim; rowIt++ )
934  {
935  for ( proshade_signed colIt = 0; colIt < dim; colIt++ )
936  {
937  uAndV[(rowIt*3)+colIt+9] = rotMatV[( rowIt * 3 ) + colIt];
938  }
939  }
940 
941  //================================================ Release the rest of the memory
942  delete[] rotMatU;
943  delete[] rotMatV;
944 
945  //================================================ Done
946  return ;
947 
948 }
949 
963 void ProSHADE_internal_maths::getEulerZXZFromSOFTPosition ( proshade_signed band, proshade_signed x, proshade_signed y, proshade_signed z, proshade_double* eulerAlpha, proshade_double* eulerBeta, proshade_double* eulerGamma )
964 {
965  //================================================ Convert index to Euler angles
966  *eulerAlpha = M_PI * static_cast<proshade_double> ( y ) / ( static_cast<proshade_double> ( band ) ) ;
967  *eulerBeta = M_PI * ( 2.0 * static_cast<proshade_double> ( x ) ) / ( 4.0 * static_cast<proshade_double> ( band ) ) ;
968  *eulerGamma = M_PI * static_cast<proshade_double> ( z ) / ( static_cast<proshade_double> ( band ) ) ;
969 
970  //================================================ Done
971  return ;
972 
973 }
974 
988 void ProSHADE_internal_maths::getSOFTPositionFromEulerZXZ ( proshade_signed band, proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double* x, proshade_double* y, proshade_double* z )
989 {
990  //================================================ Convert Euler angles to indices
991  *x = ( eulerBeta * static_cast<proshade_double> ( band ) * 2.0 ) / M_PI;
992  *y = ( eulerGamma * static_cast<proshade_double> ( band ) ) / M_PI;
993  *z = ( eulerAlpha * static_cast<proshade_double> ( band ) ) / M_PI;
994 
995  //================================================ Deal with singularities
996  if ( eulerBeta > ( M_PI - 0.05 ) )
997  {
998  //============================================ Rotation is 180 deg
999  *z = ( ( eulerAlpha - eulerGamma ) * static_cast<proshade_double> ( band ) ) / M_PI;
1000  *y = 0;
1001  }
1002 
1003  //================================================ Keep value within boundaries, but do not repeat over them!
1004  if ( *x >= ( 2 * band ) ) { *x = ( 2 * band ) - 1; }
1005  if ( *y >= ( 2 * band ) ) { *y = ( 2 * band ) - 1; }
1006  if ( *z >= ( 2 * band ) ) { *z = ( 2 * band ) - 1; }
1007 
1008  //================================================ Done
1009  return ;
1010 
1011 }
1012 
1020 void ProSHADE_internal_maths::getRotationMatrixFromEulerZXZAngles ( proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double* matrix )
1021 {
1022  //================================================ First row
1023  matrix[0] = cos ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) - sin ( eulerAlpha ) * sin ( eulerGamma );
1024  matrix[1] = sin ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) + cos ( eulerAlpha ) * sin ( eulerGamma );
1025  matrix[2] = -sin ( eulerBeta ) * cos ( eulerGamma );
1026 
1027  //================================================ Second row
1028  matrix[3] = -cos ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) - sin ( eulerAlpha ) * cos ( eulerGamma );
1029  matrix[4] = -sin ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) + cos ( eulerAlpha ) * cos ( eulerGamma );
1030  matrix[5] = sin ( eulerBeta ) * sin ( eulerGamma );
1031 
1032  //================================================ Third row
1033  matrix[6] = cos ( eulerAlpha ) * sin ( eulerBeta );
1034  matrix[7] = sin ( eulerAlpha ) * sin ( eulerBeta );
1035  matrix[8] = cos ( eulerBeta );
1036 
1037  //================================================ Done
1038  return ;
1039 
1040 }
1041 
1049 void ProSHADE_internal_maths::getRotationMatrixFromEulerZXZAngles ( proshade_single eulerAlpha, proshade_single eulerBeta, proshade_single eulerGamma, proshade_single* matrix )
1050 {
1051  //================================================ First row
1052  matrix[0] = cos ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) - sin ( eulerAlpha ) * sin ( eulerGamma );
1053  matrix[1] = sin ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) + cos ( eulerAlpha ) * sin ( eulerGamma );
1054  matrix[2] = -sin ( eulerBeta ) * cos ( eulerGamma );
1055 
1056  //================================================ Second row
1057  matrix[3] = -cos ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) - sin ( eulerAlpha ) * cos ( eulerGamma );
1058  matrix[4] = -sin ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) + cos ( eulerAlpha ) * cos ( eulerGamma );
1059  matrix[5] = sin ( eulerBeta ) * sin ( eulerGamma );
1060 
1061  //================================================ Third row
1062  matrix[6] = cos ( eulerAlpha ) * sin ( eulerBeta );
1063  matrix[7] = sin ( eulerAlpha ) * sin ( eulerBeta );
1064  matrix[8] = cos ( eulerBeta );
1065 
1066  //================================================ Done
1067  return ;
1068 
1069 }
1070 
1084  void ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( proshade_double* rotMat, proshade_double* x, proshade_double* y, proshade_double* z, proshade_double* ang, proshade_signed verbose )
1085 {
1086  //================================================ Initialise
1087  proshade_double angleTolerance = 0.01;
1088  proshade_double closeToZero = 0.0000001;
1089 
1090  //================================================ Find the angle
1091  *ang = std::acos ( ( std::max ( -1.0, std::min ( 3.0, rotMat[0] + rotMat[4] + rotMat[8] ) ) - 1.0 ) / 2.0 );
1092 
1093  //================================================ Any singularity?
1094  if ( std::abs ( std::sin ( *ang ) ) < angleTolerance )
1095  {
1096  //============================================ Initialise local variables
1097  char jobLeftEigs = 'N'; // This tells LAPACK not to compute left eigenvectors.
1098  char jobRightEigs = 'V'; // This tells LAPACK to compute right eigenvectors.
1099  int dim = 3; // The order of the matrix
1100  double* eigValReal = new double[dim]; // Real parts of the eigenvalues
1101  double* eigValImag = new double[dim]; // Imaginary parts of the eigenvalues
1102  double* leftEigVectors = new double[dim*dim*2]; // Left eigenvectors containing matrix
1103  double* rightEigVectors = new double[dim*dim*2]; // Right eigenvectors containing matrix
1104  double* work = new double[10*4*dim]; // Workspace. 4 * dim should be minimum, but more is better
1105  int workSize = 10*4*dim; // Saving the work array size for passing.
1106  int returnValue = 0; // This will tell if operation succeeded
1107 
1108  //============================================ Check memory allocation
1109  ProSHADE_internal_misc::checkMemoryAllocation ( eigValReal, __FILE__, __LINE__, __func__ );
1110  ProSHADE_internal_misc::checkMemoryAllocation ( eigValImag, __FILE__, __LINE__, __func__ );
1111  ProSHADE_internal_misc::checkMemoryAllocation ( leftEigVectors, __FILE__, __LINE__, __func__ );
1112  ProSHADE_internal_misc::checkMemoryAllocation ( rightEigVectors, __FILE__, __LINE__, __func__ );
1113  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
1114 
1115  //============================================ Load input data into array in column-major order
1116  double* matrixToDecompose = new double[dim*dim];
1117  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
1118  for ( int rowIt = 0; rowIt < dim; rowIt++ )
1119  {
1120  for ( int colIt = 0; colIt < dim; colIt++ )
1121  {
1122  matrixToDecompose[(colIt*dim)+rowIt] = static_cast< double > ( rotMat[(rowIt*dim)+colIt] );
1123  }
1124  }
1125 
1126  //============================================ Run LAPACK ZGESDD
1127  dgeev_ ( &jobLeftEigs, &jobRightEigs, &dim, matrixToDecompose, &dim, eigValReal, eigValImag, leftEigVectors, &dim,
1128  rightEigVectors, &dim, work, &workSize, &returnValue );
1129 
1130  //============================================ Check for errors
1131  if ( returnValue != 0 )
1132  {
1133  //======================================== Report error and return zero values
1134  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! Eigenval/Eigenvector algorithm did not converge.", "WS00069" );
1135  *x = 0.0;
1136  *y = 0.0;
1137  *z = 0.0;
1138 
1139  //======================================== Release memory
1140  delete[] eigValReal;
1141  delete[] eigValImag;
1142  delete[] leftEigVectors;
1143  delete[] rightEigVectors;
1144  delete[] work;
1145  delete[] matrixToDecompose;
1146 
1147  //======================================== Done
1148  return ;
1149  }
1150 
1151  //============================================ If values are close to zero, just set them to zero
1152  for ( int i = 0; i < 9; i++ ) { if ( std::abs(rightEigVectors[i]) < closeToZero ) { rightEigVectors[i] = 0.0; } }
1153  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; } }
1154 
1155  //============================================ Find which eigenvalue is close to 1 and has imaginary part close to zero
1156  proshade_signed eigIt = -1;
1157  for ( size_t it = 0; it < 3; it++ )
1158  {
1159  if ( ( eigValReal[it] > ( 1.0 - closeToZero ) ) && ( eigValReal[it] < ( 1.0 + closeToZero ) ) )
1160  {
1161  if ( ( eigValImag[it] > ( 0.0 - closeToZero ) ) && ( eigValImag[it] < ( 0.0 + closeToZero ) ) )
1162  {
1163  eigIt = static_cast< proshade_signed > ( it );
1164  break;
1165  }
1166  }
1167  }
1168 
1169  //============================================ Any axis found?
1170  if ( eigIt == -1 )
1171  {
1172  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! Failed to find eigenvalue with value 1 for this rotation matrix. Is this a rotation matrix?", "WS00072" );
1173  *x = 0.0;
1174  *y = 0.0;
1175  *z = 0.0;
1176  }
1177  else
1178  {
1179  //======================================== Parse LAPACK eigenvectors matrix
1180  int colIt;
1181  for( int rowIt = 0; rowIt < dim; rowIt++ )
1182  {
1183  colIt = 0;
1184  while( colIt < dim )
1185  {
1186  if( std::abs ( eigValImag[colIt] ) < closeToZero )
1187  {
1188  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]; } }
1189  colIt++;
1190  }
1191  else
1192  {
1193 // In order to access the
1194 // std::cout << " ( " << rightEigVectors[rowIt+colIt*dim] << " + " << rightEigVectors[rowIt+(colIt+1)*dim] << " i )";
1195 // other eigenvectors, use this:
1196 // std::cout << " ( " << rightEigVectors[rowIt+colIt*dim] << " + " << -rightEigVectors[rowIt+(colIt+1)*dim] << " i )";
1197  colIt += 2;
1198  }
1199  }
1200  }
1201  }
1202 
1203  //============================================ Normalise axis length
1204  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1205  *x /= normFactor;
1206  *y /= normFactor;
1207  *z /= normFactor;
1208 
1209 
1210  //============================================ Free memory
1211  delete[] eigValReal;
1212  delete[] eigValImag;
1213  delete[] leftEigVectors;
1214  delete[] rightEigVectors;
1215  delete[] work;
1216  delete[] matrixToDecompose;
1217  }
1218  else
1219  {
1220  //============================================= Axis
1221  *x = rotMat[7] - rotMat[5];
1222  *y = rotMat[2] - rotMat[6];
1223  *z = rotMat[3] - rotMat[1];
1224 
1225  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1226  *x /= normFactor;
1227  *y /= normFactor;
1228  *z /= normFactor;
1229 
1230  //============================================= Make sure largest axis is positive
1231  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1232  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1233  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1234  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1235  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1236  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1237  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1238  {
1239  *x *= -1.0;
1240  *y *= -1.0;
1241  *z *= -1.0;
1242  *ang *= -1.0;
1243  }
1244  }
1245 
1246  //================================================ Standardise angle to range 0 to 2pi
1247  if ( *ang < 0.0 ) { *ang = ( 2.0 * M_PI ) + *ang; }
1248 
1249  //================================================ Done
1250  return ;
1251 
1252 }
1253 
1267  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 )
1268 {
1269  //================================================ Initialise
1270  proshade_double angleTolerance = 0.01;
1271  proshade_double closeToZero = 0.0000001;
1272 
1273  //================================================ Find the angle
1274  *ang = std::acos ( ( std::max ( -1.0, std::min ( 3.0, rotMat->at(0) + rotMat->at(4) + rotMat->at(8) ) ) - 1.0 ) / 2.0 );
1275 
1276  //================================================ Any singularity?
1277  if ( std::abs ( std::sin ( *ang ) ) < angleTolerance )
1278  {
1279  //============================================ Initialise local variables
1280  char jobLeftEigs = 'N'; // This tells LAPACK not to compute left eigenvectors.
1281  char jobRightEigs = 'V'; // This tells LAPACK to compute right eigenvectors.
1282  int dim = 3; // The order of the matrix
1283  double* eigValReal = new double[dim]; // Real parts of the eigenvalues
1284  double* eigValImag = new double[dim]; // Imaginary parts of the eigenvalues
1285  double* leftEigVectors = new double[dim*dim*2]; // Left eigenvectors containing matrix
1286  double* rightEigVectors = new double[dim*dim*2]; // Right eigenvectors containing matrix
1287  double* work = new double[10*4*dim]; // Workspace. 4 * dim should be minimum, but more is better
1288  int workSize = 10*4*dim; // Saving the work array size for passing.
1289  int returnValue = 0; // This will tell if operation succeeded
1290 
1291  //============================================ Check memory allocation
1292  ProSHADE_internal_misc::checkMemoryAllocation ( eigValReal, __FILE__, __LINE__, __func__ );
1293  ProSHADE_internal_misc::checkMemoryAllocation ( eigValImag, __FILE__, __LINE__, __func__ );
1294  ProSHADE_internal_misc::checkMemoryAllocation ( leftEigVectors, __FILE__, __LINE__, __func__ );
1295  ProSHADE_internal_misc::checkMemoryAllocation ( rightEigVectors, __FILE__, __LINE__, __func__ );
1296  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
1297 
1298  //============================================ Load input data into array in column-major order
1299  double* matrixToDecompose = new double[dim*dim];
1300  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
1301  for ( int rowIt = 0; rowIt < dim; rowIt++ )
1302  {
1303  for ( int colIt = 0; colIt < dim; colIt++ )
1304  {
1305  matrixToDecompose[(colIt*dim)+rowIt] = static_cast< double > ( rotMat->at( static_cast< size_t > ( ( rowIt * dim ) + colIt ) ) );
1306  }
1307  }
1308 
1309  //============================================ Run LAPACK ZGESDD
1310  dgeev_ ( &jobLeftEigs, &jobRightEigs, &dim, matrixToDecompose, &dim, eigValReal, eigValImag, leftEigVectors, &dim,
1311  rightEigVectors, &dim, work, &workSize, &returnValue );
1312 
1313  //============================================ Check for errors
1314  if ( returnValue != 0 )
1315  {
1316  //======================================== Report error and return zero values
1317  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! Eigenval/Eigenvector algorithm did not converge.", "WS00069" );
1318  *x = 0.0;
1319  *y = 0.0;
1320  *z = 0.0;
1321 
1322  //======================================== Release memory
1323  delete[] eigValReal;
1324  delete[] eigValImag;
1325  delete[] leftEigVectors;
1326  delete[] rightEigVectors;
1327  delete[] work;
1328  delete[] matrixToDecompose;
1329 
1330  //======================================== Done
1331  return ;
1332  }
1333 
1334  //============================================ If values are close to zero, just set them to zero
1335  for ( int i = 0; i < 9; i++ ) { if ( std::abs(rightEigVectors[i]) < closeToZero ) { rightEigVectors[i] = 0.0; } }
1336  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; } }
1337 
1338  //============================================ Find which eigenvalue is close to 1 and has imaginary part close to zero
1339  proshade_signed eigIt = -1;
1340  for ( size_t it = 0; it < 3; it++ )
1341  {
1342  if ( ( eigValReal[it] > ( 1.0 - closeToZero ) ) && ( eigValReal[it] < ( 1.0 + closeToZero ) ) )
1343  {
1344  if ( ( eigValImag[it] > ( 0.0 - closeToZero ) ) && ( eigValImag[it] < ( 0.0 + closeToZero ) ) )
1345  {
1346  eigIt = static_cast< proshade_signed > ( it );
1347  break;
1348  }
1349  }
1350  }
1351 
1352  //============================================ Any axis found?
1353  if ( eigIt == -1 )
1354  {
1355  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! Failed to find eigenvalue with value 1 for this rotation matrix. Is this a rotation matrix?", "WS00072" );
1356  *x = 0.0;
1357  *y = 0.0;
1358  *z = 0.0;
1359  }
1360  else
1361  {
1362  //======================================== Parse LAPACK eigenvectors matrix
1363  int colIt;
1364  for( int rowIt = 0; rowIt < dim; rowIt++ )
1365  {
1366  colIt = 0;
1367  while( colIt < dim )
1368  {
1369  if( std::abs ( eigValImag[colIt] ) < closeToZero )
1370  {
1371  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]; } }
1372  colIt++;
1373  }
1374  else
1375  {
1376 // In order to access the
1377 // std::cout << " ( " << rightEigVectors[rowIt+colIt*dim] << " + " << rightEigVectors[rowIt+(colIt+1)*dim] << " i )";
1378 // other eigenvectors, use this:
1379 // std::cout << " ( " << rightEigVectors[rowIt+colIt*dim] << " + " << -rightEigVectors[rowIt+(colIt+1)*dim] << " i )";
1380  colIt += 2;
1381  }
1382  }
1383  }
1384  }
1385 
1386  //============================================ Normalise axis length
1387  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1388  *x /= normFactor;
1389  *y /= normFactor;
1390  *z /= normFactor;
1391 
1392  //============================================= Make sure largest axis is positive
1393  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1394  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1395  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1396  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1397  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1398  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1399  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1400  {
1401  *x *= -1.0;
1402  *y *= -1.0;
1403  *z *= -1.0;
1404  *ang *= -1.0;
1405  }
1406 
1407  //================================================ Free memory
1408  delete[] eigValReal;
1409  delete[] eigValImag;
1410  delete[] leftEigVectors;
1411  delete[] rightEigVectors;
1412  delete[] work;
1413  delete[] matrixToDecompose;
1414  }
1415  else
1416  {
1417  //============================================= Axis
1418  *x = rotMat->at(7) - rotMat->at(5);
1419  *y = rotMat->at(2) - rotMat->at(6);
1420  *z = rotMat->at(3) - rotMat->at(1);
1421 
1422  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1423  *x /= normFactor;
1424  *y /= normFactor;
1425  *z /= normFactor;
1426 
1427  //============================================= Make sure largest axis is positive
1428  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1429  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1430  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1431  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1432  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1433  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1434  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1435  {
1436  *x *= -1.0;
1437  *y *= -1.0;
1438  *z *= -1.0;
1439  *ang *= -1.0;
1440  }
1441  }
1442 
1443  //================================================ Standardise angle to range 0 to 2pi
1444  if ( *ang < 0.0 ) { *ang = ( 2.0 * M_PI ) + *ang; }
1445 
1446  //================================================ Done
1447  return ;
1448 
1449 }
1450 
1459 void ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( proshade_double* rotMat, proshade_double x, proshade_double y, proshade_double z, proshade_double ang )
1460 {
1461  //================================================ If angle is 0 or infinity (anything divided by 0), return identity matrix
1462  if ( ( ang == 0.0 ) || ( std::isinf ( ang ) ) )
1463  {
1464  //============================================ Create identity
1465  for ( proshade_unsign i = 0; i < 9; i++ ) { rotMat[i] = 0.0; }
1466  rotMat[0] = 1.0;
1467  rotMat[4] = 1.0;
1468  rotMat[8] = 1.0;
1469 
1470  //============================================ Done
1471  return ;
1472  }
1473 
1474  //================================================ Compute the matrix
1475  proshade_double cAng = cos ( ang );
1476  proshade_double sAng = sin ( ang );
1477  proshade_double tAng = 1.0 - cAng;
1478 
1479  rotMat[0] = cAng + x * x * tAng;
1480  rotMat[4] = cAng + y * y * tAng;
1481  rotMat[8] = cAng + z * z * tAng;
1482 
1483  proshade_double tmp1 = x * y * tAng;
1484  proshade_double tmp2 = z * sAng;
1485  rotMat[3] = tmp1 + tmp2;
1486  rotMat[1] = tmp1 - tmp2;
1487 
1488  tmp1 = x * z * tAng;
1489  tmp2 = y * sAng;
1490  rotMat[6] = tmp1 - tmp2;
1491  rotMat[2] = tmp1 + tmp2;
1492 
1493  tmp1 = y * z * tAng;
1494  tmp2 = x * sAng;
1495  rotMat[7] = tmp1 + tmp2;
1496  rotMat[5] = tmp1 - tmp2;
1497 
1498  //================================================ Done
1499  return ;
1500 
1501 }
1502 
1511 void ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( proshade_single* rotMat, proshade_double x, proshade_double y, proshade_double z, proshade_double ang )
1512 {
1513  //================================================ If angle is 0 or infinity (anything divided by 0), return identity matrix
1514  if ( ( ang == 0.0 ) || ( std::isinf ( ang ) ) )
1515  {
1516  //============================================ Create identity
1517  for ( size_t i = 0; i < 9; i++ ) { rotMat[i] = 0.0f; }
1518  rotMat[0] = 1.0f;
1519  rotMat[4] = 1.0f;
1520  rotMat[8] = 1.0f;
1521 
1522  //============================================ Done
1523  return ;
1524  }
1525 
1526  //================================================ Compute the matrix
1527  proshade_single cAng = cos ( static_cast< proshade_single > ( ang ) );
1528  proshade_single sAng = sin ( static_cast< proshade_single > ( ang ) );
1529  proshade_single tAng = 1.0f - cAng;
1530 
1531  rotMat[0] = cAng + static_cast< proshade_single > ( x ) * static_cast< proshade_single > ( x ) * tAng;
1532  rotMat[4] = cAng + static_cast< proshade_single > ( y ) * static_cast< proshade_single > ( y ) * tAng;
1533  rotMat[8] = cAng + static_cast< proshade_single > ( z ) * static_cast< proshade_single > ( z ) * tAng;
1534 
1535  proshade_single tmp1 = static_cast< proshade_single > ( x ) * static_cast< proshade_single > ( y ) * tAng;
1536  proshade_single tmp2 = static_cast< proshade_single > ( z ) * sAng;
1537  rotMat[3] = tmp1 + tmp2;
1538  rotMat[1] = tmp1 - tmp2;
1539 
1540  tmp1 = static_cast< proshade_single > ( x ) * static_cast< proshade_single > ( z ) * tAng;
1541  tmp2 = static_cast< proshade_single > ( y ) * sAng;
1542  rotMat[6] = tmp1 - tmp2;
1543  rotMat[2] = tmp1 + tmp2;
1544 
1545  tmp1 = static_cast< proshade_single > ( y ) * static_cast< proshade_single > ( z ) * tAng;
1546  tmp2 = static_cast< proshade_single > ( x ) * sAng;
1547  rotMat[7] = tmp1 + tmp2;
1548  rotMat[5] = tmp1 - tmp2;
1549 
1550  //================================================ Done
1551  return ;
1552 
1553 }
1554 
1562 void ProSHADE_internal_maths::getEulerZXZFromRotMatrix ( proshade_double* rotMat, proshade_double* eA, proshade_double* eB, proshade_double* eG )
1563 {
1564  //================================================ Convert to Eulers
1565  if ( std::abs( rotMat[8] ) < 0.99999 )
1566  {
1567  //============================================ This case occurs when there is no singularity in the rotation matrix (i.e. it does not have 0 or 180 degrees angle)
1568  *eA = std::atan2 ( rotMat[7], rotMat[6] );
1569  *eB = std::acos ( rotMat[8] );
1570  *eG = std::atan2 ( rotMat[5], -rotMat[2] );
1571  }
1572  else
1573  {
1574  //============================================ This case occurs when there is either 0 or 180 degrees rotation angle in the rotation matrix and therefore when beta is zero.
1575  if ( rotMat[8] >= 0.99999 )
1576  {
1577  //======================================== 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.
1578  *eA = std::atan2 ( rotMat[3], rotMat[0] );
1579  *eB = 0.0;
1580  *eG = 0.0;
1581  }
1582  if ( rotMat[8] <= -0.99999 )
1583  {
1584  //======================================== 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.
1585  *eA = std::atan2 ( rotMat[3], rotMat[0] );
1586  *eB = M_PI;
1587  *eG = 0.0;
1588  }
1589  }
1590 
1591  //================================================ Get the angles to proper range
1592  if ( *eA < 0.0 ) { *eA = 2.0 * M_PI + *eA; }
1593  if ( *eB < 0.0 ) { *eB = M_PI + *eB; }
1594  if ( *eG < 0.0 ) { *eG = 2.0 * M_PI + *eG; }
1595 
1596  //================================================ Done
1597  return ;
1598 
1599 }
1600 
1613 void ProSHADE_internal_maths::getEulerZXZFromAngleAxis ( proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double axAng, proshade_double* eA, proshade_double* eB, proshade_double* eG )
1614 {
1615  //================================================ If angle is 0 or infinity (anything divided by 0), return no rotation
1616  if ( ( axAng == 0.0 ) || ( std::isinf ( axAng ) ) )
1617  {
1618  //============================================ Return 0 ; 0 ; 0 for no angle
1619  *eA = 0.0;
1620  *eB = 0.0;
1621  *eG = 0.0;
1622 
1623  //============================================ Done
1624  return ;
1625  }
1626 
1627  //================================================ Compute required rotation matrix elements
1628  proshade_double cAng = std::cos ( axAng );
1629  proshade_double sAng = std::sin ( axAng );
1630  proshade_double tAng = 1.0 - cAng;
1631 
1632  proshade_double element22 = cAng + axZ * axZ * tAng;
1633 
1634  proshade_double tmp1 = axX * axZ * tAng;
1635  proshade_double tmp2 = axY * sAng;
1636  proshade_double element20 = tmp1 - tmp2;
1637  proshade_double element02 = tmp1 + tmp2;
1638 
1639  tmp1 = axY * axZ * tAng;
1640  tmp2 = axX * sAng;
1641  proshade_double element21 = tmp1 + tmp2;
1642  proshade_double element12 = tmp1 - tmp2;
1643 
1644  //================================================ Convert to Eulers
1645  if ( std::abs( element22 ) <= 0.99999 )
1646  {
1647  //============================================ This case occurs when there is no singularity in the rotation matrix (i.e. it does not have 0 or 180 degrees angle)
1648  *eA = std::atan2 ( element21, element20 );
1649  *eB = std::acos ( element22 );
1650  *eG = std::atan2 ( element12, -element02 );
1651  }
1652  else
1653  {
1654  //============================================ Compute some extra rotation matrix elements
1655  tmp1 = axX * axY * tAng;
1656  tmp2 = axZ * sAng;
1657  proshade_double element10 = tmp1 + tmp2;
1658  proshade_double element00 = cAng + axX * axX * tAng;
1659 
1660  //============================================ This case occurs when there is either 0 or 180 degrees rotation angle in the rotation matrix and therefore when beta is zero.
1661  if ( element22 >= 0.99999 )
1662  {
1663  //======================================== 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.
1664  *eA = std::atan2 ( element10, element00 );
1665  *eB = 0.0;
1666  *eG = 0.0;
1667  }
1668  if ( element22 <= -0.99999 )
1669  {
1670  //======================================== 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.
1671  *eA = std::atan2 ( element10, element00 );
1672  *eB = M_PI;
1673  *eG = 0.0;
1674  }
1675  }
1676 
1677  //================================================ Get the angles to proper range
1678  if ( *eA < 0.0 ) { *eA = 2.0 * M_PI + *eA; }
1679  if ( *eB < 0.0 ) { *eB = M_PI + *eB; }
1680  if ( *eG < 0.0 ) { *eG = 2.0 * M_PI + *eG; }
1681 
1682  //================================================ Done
1683  return ;
1684 
1685 }
1686 
1696 void ProSHADE_internal_maths::multiplyTwoSquareMatrices ( proshade_double* A, proshade_double* B, proshade_double* res, proshade_unsign dim )
1697 {
1698  //================================================ Set res to 0.0s
1699  for ( proshade_unsign iter = 0; iter < 9; iter++ ) { res[iter] = 0.0; }
1700 
1701  //================================================ Compute the matrix multiplication
1702  for ( proshade_unsign row = 0; row < dim; row++ )
1703  {
1704  for ( proshade_unsign col = 0; col < dim; col++ )
1705  {
1706  for ( proshade_unsign inner = 0; inner < dim; inner++ )
1707  {
1708  res[(row*dim)+col] += A[(inner*dim)+row] * B[(col*dim)+inner];
1709  }
1710  }
1711  }
1712 
1713  //================================================ Done
1714  return ;
1715 
1716 }
1717 
1722 std::vector < proshade_signed > ProSHADE_internal_maths::primeFactorsDecomp ( proshade_signed number )
1723 {
1724  //================================================ Initialise variables
1725  std::vector < proshade_signed > ret;
1726 
1727  //================================================ Deal with negative numbers
1728  bool changeSign = false;
1729  if ( number < 0 ) { changeSign = true; number = -number; }
1730 
1731  //================================================ Deal with zero and one
1732  if ( number == 0 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, 0 ); return ( ret ); }
1733  if ( number == 1 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, 1 ); return ( ret ); }
1734 
1735  //================================================ Divide by 2 as long as you can
1736  while ( number % 2 == 0 )
1737  {
1739  number = number / 2;
1740  }
1741 
1742  //================================================ Check all odd numbers up to the square root
1743  for ( proshade_double posDiv = 3; posDiv <= sqrt ( static_cast< proshade_double > ( number ) ); posDiv += 2.0 )
1744  {
1745  // If posDiv is a divisor of the number, save the result
1746  while ( number % static_cast< proshade_signed > ( posDiv ) == 0 )
1747  {
1748  ProSHADE_internal_misc::addToSignedVector ( &ret, static_cast< proshade_signed > ( posDiv ) );
1749  number = number / static_cast< proshade_signed > ( posDiv );
1750  }
1751  }
1752 
1753  //================================================ If the number was a large prime number, save it as it is
1754  if ( number > 2 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, number ); }
1755 
1756  //================================================ Finish dealing with negative numbers
1757  if ( changeSign ) { ret.at(0) = -ret.at(0); }
1758 
1759  //================================================ Done
1760  return ( ret );
1761 
1762 }
1763 
1771 proshade_double ProSHADE_internal_maths::normalDistributionValue ( proshade_double mean, proshade_double standardDev, proshade_double value )
1772 {
1773  //================================================ Compute and return
1774  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) ) );
1775 
1776 }
1777 
1788 proshade_double ProSHADE_internal_maths::computeDotProduct ( proshade_double* x1, proshade_double* y1, proshade_double* z1, proshade_double* x2, proshade_double* y2, proshade_double* z2 )
1789 {
1790  //================================================ Compute and return
1791  return ( (*x1 * *x2) + (*y1 * *y2) + (*z1 * *z2) );
1792 }
1793 
1804 proshade_double ProSHADE_internal_maths::computeDotProduct ( proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2 )
1805 {
1806  //================================================ Compute and return
1807  return ( (x1 * x2) + (y1 * y2) + (z1 * z2) );
1808 }
1809 
1820 proshade_double* ProSHADE_internal_maths::computeCrossProduct ( proshade_double* x1, proshade_double* y1, proshade_double* z1, proshade_double* x2, proshade_double* y2, proshade_double* z2 )
1821 {
1822  //================================================ Allocate memory
1823  proshade_double* crossProd = new proshade_double[3];
1824  ProSHADE_internal_misc::checkMemoryAllocation ( crossProd, __FILE__, __LINE__, __func__ );
1825 
1826  //================================================ Compute
1827  crossProd[0] = ( (*y1) * (*z2) ) - ( (*z1) * (*y2) );
1828  crossProd[1] = ( (*z1) * (*x2) ) - ( (*x1) * (*z2) );
1829  crossProd[2] = ( (*x1) * (*y2) ) - ( (*y1) * (*x2) );
1830 
1831  //================================================ Done
1832  return ( crossProd );
1833 
1834 }
1835 
1846 proshade_double* ProSHADE_internal_maths::computeCrossProduct ( proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2 )
1847 {
1848  //================================================ Allocate memory
1849  proshade_double* crossProd = new proshade_double[3];
1850  ProSHADE_internal_misc::checkMemoryAllocation ( crossProd, __FILE__, __LINE__, __func__ );
1851 
1852  //================================================ Compute
1853  crossProd[0] = ( y1 * z2 ) - ( z1 * y2 );
1854  crossProd[1] = ( z1 * x2 ) - ( x1 * z2 );
1855  crossProd[2] = ( x1 * y2 ) - ( y1 * x2 );
1856 
1857  //================================================ Done
1858  return ( crossProd );
1859 
1860 }
1861 
1868 proshade_double* ProSHADE_internal_maths::compute3x3MatrixMultiplication ( proshade_double* mat1, proshade_double* mat2 )
1869 {
1870  //================================================ Allocate memory
1871  proshade_double* ret = new proshade_double[9];
1872  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1873 
1874  //================================================ Multiply
1875  ret[0] = ( mat1[0] * mat2[0] ) + ( mat1[1] * mat2[3] ) + ( mat1[2] * mat2[6] );
1876  ret[1] = ( mat1[0] * mat2[1] ) + ( mat1[1] * mat2[4] ) + ( mat1[2] * mat2[7] );
1877  ret[2] = ( mat1[0] * mat2[2] ) + ( mat1[1] * mat2[5] ) + ( mat1[2] * mat2[8] );
1878  ret[3] = ( mat1[3] * mat2[0] ) + ( mat1[4] * mat2[3] ) + ( mat1[5] * mat2[6] );
1879  ret[4] = ( mat1[3] * mat2[1] ) + ( mat1[4] * mat2[4] ) + ( mat1[5] * mat2[7] );
1880  ret[5] = ( mat1[3] * mat2[2] ) + ( mat1[4] * mat2[5] ) + ( mat1[5] * mat2[8] );
1881  ret[6] = ( mat1[6] * mat2[0] ) + ( mat1[7] * mat2[3] ) + ( mat1[8] * mat2[6] );
1882  ret[7] = ( mat1[6] * mat2[1] ) + ( mat1[7] * mat2[4] ) + ( mat1[8] * mat2[7] );
1883  ret[8] = ( mat1[6] * mat2[2] ) + ( mat1[7] * mat2[5] ) + ( mat1[8] * mat2[8] );
1884 
1885  //================================================ Done
1886  return ( ret );
1887 
1888 }
1889 
1898 proshade_double* ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( proshade_double* mat, proshade_double x, proshade_double y, proshade_double z )
1899 {
1900  //================================================ Allocate memory
1901  proshade_double* ret = new proshade_double[3];
1902  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1903 
1904  //================================================ Compute the multiplication
1905  ret[0] = ( x * mat[0] ) + ( y * mat[1] ) + ( z * mat[2] );
1906  ret[1] = ( x * mat[3] ) + ( y * mat[4] ) + ( z * mat[5] );
1907  ret[2] = ( x * mat[6] ) + ( y * mat[7] ) + ( z * mat[8] );
1908 
1909  //================================================ Done
1910  return ( ret );
1911 
1912 }
1913 
1922 proshade_single* ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( proshade_single* mat, proshade_single x, proshade_single y, proshade_single z )
1923 {
1924  //================================================ Allocate memory
1925  proshade_single* ret = new proshade_single[3];
1926  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1927 
1928  //================================================ Compute the multiplication
1929  ret[0] = ( x * mat[0] ) + ( y * mat[1] ) + ( z * mat[2] );
1930  ret[1] = ( x * mat[3] ) + ( y * mat[4] ) + ( z * mat[5] );
1931  ret[2] = ( x * mat[6] ) + ( y * mat[7] ) + ( z * mat[8] );
1932 
1933  //================================================ Done
1934  return ( ret );
1935 
1936 }
1937 
1943 proshade_double* ProSHADE_internal_maths::compute3x3MatrixInverse ( proshade_double* mat )
1944 {
1945  //================================================ Allocate memory
1946  proshade_double* inverse = new proshade_double[9];
1947  ProSHADE_internal_misc::checkMemoryAllocation ( inverse, __FILE__, __LINE__, __func__ );
1948 
1949  //================================================ Compute determinant
1950  proshade_double matDet = ( mat[0] * mat[4] * mat[8] ) +
1951  ( mat[1] * mat[5] * mat[6] ) +
1952  ( mat[2] * mat[3] * mat[7] ) -
1953  ( mat[0] * mat[5] * mat[7] ) -
1954  ( mat[1] * mat[3] * mat[8] ) -
1955  ( mat[2] * mat[4] * mat[6] );
1956 
1957  //================================================ Compute inverse matrix
1958  inverse[0] = ( mat[4] * mat[8] - mat[5] * mat[7] ) / matDet;
1959  inverse[1] = ( mat[2] * mat[7] - mat[1] * mat[8] ) / matDet;
1960  inverse[2] = ( mat[1] * mat[5] - mat[2] * mat[4] ) / matDet;
1961  inverse[3] = ( mat[5] * mat[6] - mat[3] * mat[8] ) / matDet;
1962  inverse[4] = ( mat[0] * mat[8] - mat[2] * mat[6] ) / matDet;
1963  inverse[5] = ( mat[2] * mat[3] - mat[0] * mat[5] ) / matDet;
1964  inverse[6] = ( mat[3] * mat[7] - mat[4] * mat[6] ) / matDet;
1965  inverse[7] = ( mat[1] * mat[6] - mat[0] * mat[7] ) / matDet;
1966  inverse[8] = ( mat[0] * mat[4] - mat[1] * mat[3] ) / matDet;
1967 
1968  //================================================ Done
1969  return ( inverse );
1970 }
1971 
1977 {
1978  //================================================ Initialise variables
1979  proshade_double tmp;
1980 
1981  //================================================ Transpose the non-diagonal values
1982  tmp = mat[1];
1983  mat[1] = mat[3];
1984  mat[3] = tmp;
1985 
1986  tmp = mat[2];
1987  mat[2] = mat[6];
1988  mat[6] = tmp;
1989 
1990  tmp = mat[5];
1991  mat[5] = mat[7];
1992  mat[7] = tmp;
1993 
1994  //================================================ Done
1995  return ;
1996 
1997 }
1998 
2004 proshade_double* ProSHADE_internal_maths::build3x3MatrixFromDiag ( proshade_double* diag )
2005 {
2006  //================================================ Allocate memory
2007  proshade_double* ret = new proshade_double[9];
2008  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
2009 
2010  //================================================ Build
2011  ret[0] = diag[0];
2012  ret[1] = 0.0;
2013  ret[2] = 0.0;
2014  ret[3] = 0.0;
2015  ret[4] = diag[1];
2016  ret[5] = 0.0;
2017  ret[6] = 0.0;
2018  ret[7] = 0.0;
2019  ret[8] = diag[2];
2020 
2021  //================================================ Done
2022  return ( ret );
2023 
2024 }
2025 
2033 proshade_double* ProSHADE_internal_maths::build3x3MatrixFromXYZRotations ( proshade_double xRot, proshade_double yRot, proshade_double zRot )
2034 {
2035  //================================================ Allocate memory
2036  proshade_double* ret = new proshade_double[9];
2037  proshade_double* XRM = new proshade_double[9];
2038  proshade_double* YRM = new proshade_double[9];
2039  proshade_double* ZRM = new proshade_double[9];
2040  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
2041  ProSHADE_internal_misc::checkMemoryAllocation ( XRM, __FILE__, __LINE__, __func__ );
2042  ProSHADE_internal_misc::checkMemoryAllocation ( YRM, __FILE__, __LINE__, __func__ );
2043  ProSHADE_internal_misc::checkMemoryAllocation ( ZRM, __FILE__, __LINE__, __func__ );
2044 
2045  //================================================ Convert to radians
2046  proshade_double xRad = xRot * ( M_PI / 180.0 );
2047  proshade_double yRad = yRot * ( M_PI / 180.0 );
2048  proshade_double zRad = zRot * ( M_PI / 180.0 );
2049 
2050  //================================================ Build the X, Y and Z rotation matrices
2051  XRM[0] = 1.0; XRM[1] = 0.0; XRM[2] = 0.0;
2052  XRM[3] = 0.0; XRM[4] = std::cos ( xRad ); XRM[5] = -std::sin ( xRad );
2053  XRM[6] = 0.0; XRM[7] = std::sin ( xRad ); XRM[8] = std::cos ( xRad );
2054 
2055  YRM[0] = std::cos ( yRad ); YRM[1] = 0.0; YRM[2] = std::sin ( yRad );
2056  YRM[3] = 0.0; YRM[4] = 1.0; YRM[5] = 0.0;
2057  YRM[6] = -std::sin ( yRad ); YRM[7] = 0.0; YRM[8] = std::cos ( yRad );
2058 
2059  ZRM[0] = std::cos ( zRad ); ZRM[1] = -std::sin ( zRad ); ZRM[2] = 0.0;
2060  ZRM[3] = std::sin ( zRad ); ZRM[4] = std::cos ( zRad ); ZRM[5] = 0.0;
2061  ZRM[6] = 0.0; ZRM[7] = 0.0; ZRM[8] = 1.0;
2062 
2063  //================================================ Multiply in XYZ order
2064  proshade_double* tmpMat = compute3x3MatrixMultiplication ( XRM, YRM );
2065  ret = compute3x3MatrixMultiplication ( tmpMat, ZRM );
2066 
2067  //================================================ Release memory
2068  delete[] tmpMat;
2069  delete[] XRM;
2070  delete[] YRM;
2071  delete[] ZRM;
2072 
2073  //================================================ Done
2074  return ( ret );
2075 
2076 }
2077 
2095 proshade_double* ProSHADE_internal_maths::findRotMatMatchingVectors ( proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2 )
2096 {
2097  //================================================ Allocate required memory
2098  proshade_double* inPlaneRotation = new proshade_double[9];
2099  proshade_double* basisChangeMat = new proshade_double[9];
2100  ProSHADE_internal_misc::checkMemoryAllocation ( inPlaneRotation, __FILE__, __LINE__, __func__ );
2101  ProSHADE_internal_misc::checkMemoryAllocation ( basisChangeMat, __FILE__, __LINE__, __func__ );
2102 
2103  //================================================ Normalise inputs
2104  proshade_double normF = std::sqrt( std::pow( x1, 2.0 ) + std::pow ( y1, 2.0 ) + std::pow ( z1, 2.0 ) );
2105  x1 /= normF; y1 /= normF; z1 /= normF;
2106 
2107  normF = std::sqrt( std::pow( x2, 2.0 ) + std::pow ( y2, 2.0 ) + std::pow ( z2, 2.0 ) );
2108  x2 /= normF; y2 /= normF; z2 /= normF;
2109 
2110  //================================================ Compute cross product's magnitude
2111  proshade_double* crossProd = ProSHADE_internal_maths::computeCrossProduct( &x1, &y1, &z1, &x2, &y2, &z2 );
2112  proshade_double crossProdMag = std::sqrt( std::pow( crossProd[0], 2.0 ) + std::pow ( crossProd[1], 2.0 ) + std::pow ( crossProd[2], 2.0 ) );
2113  delete[] crossProd;
2114 
2115  //================================================ Compute dot product
2116  proshade_double dotProd = ProSHADE_internal_maths::computeDotProduct ( &x1, &y1, &z1, &x2, &y2, &z2 );
2117 
2118  //================================================ Construct the in-plane rotation matrix
2119  inPlaneRotation[0] = dotProd; inPlaneRotation[1] = -crossProdMag; inPlaneRotation[2] = 0.0;
2120  inPlaneRotation[3] = crossProdMag; inPlaneRotation[4] = dotProd; inPlaneRotation[5] = 0.0;
2121  inPlaneRotation[6] = 0.0; inPlaneRotation[7] = 0.0; inPlaneRotation[8] = 1.0;
2122 
2123  //================================================ Construct change of basis matrix
2124  crossProd = ProSHADE_internal_maths::computeCrossProduct( &x2, &y2, &z2, &x1, &y1, &z1 );
2125  normF = std::sqrt ( std::pow ( x2 - ( dotProd * x1 ), 2.0 ) + std::pow ( y2 - ( dotProd * y1 ), 2.0 ) + std::pow ( z2 - ( dotProd * z1 ), 2.0 ) );
2126 
2127  basisChangeMat[0] = x1; basisChangeMat[1] = ( x2 - ( dotProd * x1 ) ) / normF; basisChangeMat[2] = crossProd[0];
2128  basisChangeMat[3] = y1; basisChangeMat[4] = ( y2 - ( dotProd * y1 ) ) / normF; basisChangeMat[5] = crossProd[1];
2129  basisChangeMat[6] = z1; basisChangeMat[7] = ( z2 - ( dotProd * z1 ) ) / normF; basisChangeMat[8] = crossProd[2];
2130 
2131  //================================================ Invert the change of basis matrix
2132  proshade_double* basisChangeMatInverse = ProSHADE_internal_maths::compute3x3MatrixInverse ( basisChangeMat );
2133 
2134  //================================================ Multiply inverse of change of basis matrix with the in plane rotation matrix, then multiply the result with the inverse
2135  proshade_double* tmpMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( basisChangeMat, inPlaneRotation );
2136  proshade_double* rotMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( tmpMat, basisChangeMatInverse );
2137 
2138  //================================================ Release memory
2139  delete[] crossProd;
2140  delete[] inPlaneRotation;
2141  delete[] basisChangeMat;
2142  delete[] basisChangeMatInverse;
2143  delete[] tmpMat;
2144 
2145  //================================================ Done
2146  return ( rotMat );
2147 
2148 }
2149 
2162 proshade_double* ProSHADE_internal_maths::compute3x3MoorePenrosePseudoInverseOfIMinusMat ( std::vector < proshade_double >* rMat, proshade_signed verbose )
2163 {
2164  //================================================ Initialise local variables and allocate the memory
2165  int dim = 3; // Number of dimensions
2166  char job = 'A'; // Save computation of parts of U and V matrices, they are not needed here
2167  double *singularValues = new double[dim]; // The array of singular values
2168  double *rotMatU = new double [dim*dim]; // The U matrix space
2169  double *rotMatV = new double [dim*dim]; // The V^T matrix space
2170  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
2171  int workDim = static_cast< int > ( 2 * ( ( 4 * dim * dim ) + ( 7 * dim ) ) ); // Formalism stating just that
2172  double* rwork = new double[static_cast<proshade_unsign>((5 * dim) + 5 * pow(dim,2))]; // Required by LAPACK
2173  int* iwork = new int[(8 * dim)]; // Required by LAPACK
2174  int returnValue = 0; // This will tell if operation succeeded
2175  double *matrixToDecompose = new double[dim*dim];
2176 
2177  //================================================ Check the memory allocation
2178  ProSHADE_internal_misc::checkMemoryAllocation ( singularValues, __FILE__, __LINE__, __func__ );
2179  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatU, __FILE__, __LINE__, __func__ );
2180  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatV, __FILE__, __LINE__, __func__ );
2181  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
2182  ProSHADE_internal_misc::checkMemoryAllocation ( rwork, __FILE__, __LINE__, __func__ );
2183  ProSHADE_internal_misc::checkMemoryAllocation ( iwork, __FILE__, __LINE__, __func__ );
2184  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
2185 
2186  //================================================ Load input data into array in column-major order
2187  for ( int rowIt = 0; rowIt < dim; rowIt++ )
2188  {
2189  for ( int colIt = 0; colIt < dim; colIt++ )
2190  {
2191  if ( rowIt == colIt ) { matrixToDecompose[(colIt*dim)+rowIt] = 1.0 - rMat->at( static_cast< size_t > ( ( rowIt * dim ) + colIt ) ); }
2192  else { matrixToDecompose[(colIt*dim)+rowIt] = 0.0 - rMat->at( static_cast< size_t > ( ( rowIt * dim ) + colIt ) ); }
2193  }
2194  }
2195 
2196  //================================================ Run LAPACK ZGESDD
2197  dgesdd_ ( &job, &dim, &dim, matrixToDecompose, &dim, singularValues, rotMatU, &dim, rotMatV, &dim,
2198  work, &workDim, rwork, iwork, &returnValue );
2199 
2200  //================================================ Check the convergence
2201  if ( returnValue != 0 )
2202  {
2203  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! SVD algorithm did not converge.", "WS00069" );
2204  }
2205 
2206  //================================================ Determine positivity
2207  bool anyPositive = false;
2208  std::vector< bool > positivityTest;
2209  for ( proshade_unsign it = 0; it < static_cast< proshade_unsign > ( dim ); it++ )
2210  {
2211  positivityTest.push_back ( singularValues[it] > 0.001 );
2212  if ( positivityTest.at(it) ) { anyPositive = true; }
2213  }
2214 
2215  //================================================ Compute according to positivity
2216  proshade_double* pseudoInverseMat;
2217  if ( anyPositive )
2218  {
2219  //============================================ Set all non-positive singular values and appropriate matrix rows/columns to zero
2220  if ( !positivityTest.at(0) )
2221  {
2222  singularValues[0] = 0.0;
2223  rotMatU[0] = 0.0;
2224  rotMatU[1] = 0.0;
2225  rotMatU[2] = 0.0;
2226  rotMatV[0] = 0.0;
2227  rotMatV[3] = 0.0;
2228  rotMatV[6] = 0.0;
2229  }
2230  else { singularValues[0] = 1.0 / singularValues[0]; }
2231 
2232  if ( !positivityTest.at(1) )
2233  {
2234  singularValues[1] = 0.0;
2235  rotMatU[3] = 0.0;
2236  rotMatU[4] = 0.0;
2237  rotMatU[5] = 0.0;
2238  rotMatV[1] = 0.0;
2239  rotMatV[4] = 0.0;
2240  rotMatV[7] = 0.0;
2241  }
2242  else { singularValues[1] = 1.0 / singularValues[1]; }
2243 
2244  if ( !positivityTest.at(2) )
2245  {
2246  singularValues[2] = 0.0;
2247  rotMatU[6] = 0.0;
2248  rotMatU[7] = 0.0;
2249  rotMatU[8] = 0.0;
2250  rotMatV[2] = 0.0;
2251  rotMatV[5] = 0.0;
2252  rotMatV[8] = 0.0;
2253  }
2254  else { singularValues[2] = 1.0 / singularValues[2]; }
2255 
2256  //============================================ All positive values formula
2257  proshade_double* diagMat = ProSHADE_internal_maths::build3x3MatrixFromDiag ( singularValues );
2258  proshade_double* hlpMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( diagMat, rotMatU );
2259  pseudoInverseMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( rotMatV, hlpMat );
2260 
2261  //============================================ Release memory
2262  delete[] diagMat;
2263  delete[] hlpMat;
2264  }
2265  else
2266  {
2267  //============================================ No axis in matrix
2268  pseudoInverseMat = new proshade_double[9];
2269  ProSHADE_internal_misc::checkMemoryAllocation ( pseudoInverseMat, __FILE__, __LINE__, __func__ );
2270 
2271  for ( size_t mIt = 0; mIt < 9; mIt++ ) { pseudoInverseMat[mIt] = 0.0; }
2272  }
2273 
2274  //================================================ Free memory
2275  delete[] work;
2276  delete[] rwork;
2277  delete[] iwork;
2278  delete[] matrixToDecompose;
2279  delete[] singularValues;
2280  delete[] rotMatU;
2281  delete[] rotMatV;
2282 
2283  //================================================ Done
2284  return ( pseudoInverseMat );
2285 
2286 }
2287 
2309 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 )
2310 {
2311  //================================================ Initialise variables
2312  std::vector < proshade_double > ret;
2313 
2314  //================================================ Solution
2315  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 ) -
2316  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 ) ) *
2317  ( 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 ) ) ) -
2318  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 ) /
2319  ( 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 ) ) );
2320  proshade_double solY = ( ( dot2 * pow ( x2, 2.0 ) * pow ( z1, 3.0 ) ) /
2321  ( 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 ) -
2322  ( dot1 * pow ( x2, 2.0 ) * z2 * pow ( z1, 2.0 ) ) /
2323  ( 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 ) -
2324  ( 2.0 * x1 * dot2 * x2 * z2 * pow ( z1, 2.0 ) ) /
2325  ( 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 -
2326  ( 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 ) -
2327  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 ) *
2328  ( 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 ) /
2329  ( 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 ) ) +
2330  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) * z1 ) /
2331  ( 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 ) +
2332  ( x1 * dot1 * x2 * pow ( y2, 2.0 ) * z1 ) /
2333  ( 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 ) +
2334  ( pow ( x1, 2.0 ) * dot2 * pow ( z2, 2.0 ) * z1 ) /
2335  ( 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 ) +
2336  ( 2.0 * x1 * dot1 * x2 * pow ( z2, 2.0 ) * z1 ) /
2337  ( 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 ) -
2338  ( y1 * dot1 * pow ( x2, 2.0 ) * y2 * z1 ) /
2339  ( 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 ) -
2340  ( x1 * y1 * dot2 * x2 * y2 * z1 ) /
2341  ( 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 +
2342  ( 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 ) -
2343  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 ) *
2344  ( 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 ) ) ) /
2345  ( 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 ) ) -
2346  ( pow ( x1, 2.0 ) * dot1 * pow ( z2, 3.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  ( pow ( x1, 2.0 ) * dot1 * pow ( y2, 2.0 ) * z2 ) /
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 ) -
2350  ( x1 * pow ( y1, 2.0 ) * dot2 * x2 * z2 ) /
2351  ( 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 ( x1, 2.0 ) * y1 * dot2 * y2 * z2 ) /
2353  ( 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  ( x1 * y1 * dot1 * x2 * y2 * z2 ) /
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 ) ) / ( y1 * z2 - z1 * y2 );
2356  proshade_double solZ = ( - ( dot2 * pow ( x2, 2.0 ) * y2 * pow ( z1, 3.0 ) ) /
2357  ( ( 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 ) ) -
2358  ( dot2 * pow ( x2, 2.0 ) * pow ( z1, 2.0 ) ) /
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  ( dot1 * pow ( x2, 2.0 ) * y2 * z2 * pow ( z1, 2.0 ) ) /
2361  ( ( 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 ) ) +
2362  ( 2.0 * x1 * dot2 * x2 * y2 * z2 * pow ( z1, 2.0 ) ) /
2363  ( ( 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 ) ) +
2364  ( 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 ) -
2365  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 ) *
2366  ( 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 ) /
2367  ( 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 ) ) +
2368  ( dot2 * y2 * z1 ) / ( y1 * z2 - z1 * y2 ) +
2369  ( dot1 * pow ( x2, 2.0 ) * z2 * z1 ) /
2370  ( 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 ) +
2371  ( x1 * dot2 * x2 * z2 * z1 ) /
2372  ( 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 ) -
2373  ( x1 * dot1 * x2 * pow ( y2, 3.0 ) * z1 ) /
2374  ( ( 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 ) ) +
2375  ( y1 * dot1 * pow ( x2, 2.0 ) * pow ( y2, 2.0 ) * z1 ) /
2376  ( ( 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 ) ) +
2377  ( x1 * y1 * dot2 * x2 * pow ( y2, 2.0 ) * z1 ) /
2378  ( ( 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 ) ) -
2379  ( pow ( x1, 2.0 ) * dot2 * y2 * pow ( z2, 2.0 ) * z1 ) /
2380  ( ( 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 ) ) -
2381  ( 2.0 * x1 * dot1 * x2 * y2 * pow ( z2, 2.0 ) * z1 ) /
2382  ( ( 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 ) ) -
2383  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) * y2 * z1 ) /
2384  ( ( 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 +
2385  ( 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 ) -
2386  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 ) *
2387  ( 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 ) ) ) /
2388  ( 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 ) ) -
2389  ( 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 ) -
2390  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 ) *
2391  ( 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 ) ) ) /
2392  ( 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 ) ) -
2393  ( dot1 * y2 * z2 ) / ( y1 * z2 - z1 * y2 ) -
2394  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) ) /
2395  ( 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 ) -
2396  ( x1 * dot1 * x2 * pow ( y2, 2.0 ) ) /
2397  ( 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 ) -
2398  ( x1 * dot1 * x2 * pow ( z2, 2.0 ) ) /
2399  ( 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 ) +
2400  ( y1 * dot1 * pow ( x2, 2.0 ) * y2 ) /
2401  ( 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 ) +
2402  ( x1 * y1 * dot2 * x2 * y2 ) /
2403  ( 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 ) +
2404  ( pow ( x1, 2.0 ) * dot1 * y2 * pow ( z2, 3.0 ) ) /
2405  ( ( 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 ) ) +
2406  ( pow ( x1, 2.0 ) * dot1 * pow ( y2, 3.0 ) * z2 ) /
2407  ( ( 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 ) ) -
2408  ( pow ( x1, 2.0 ) * y1 * dot2 * pow ( y2, 2.0 ) * z2 ) /
2409  ( ( 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 ) ) -
2410  ( x1 * y1 * dot1 * x2 * pow ( y2, 2.0 ) * z2 ) /
2411  ( ( 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 ) ) +
2412  ( x1 * pow ( y1, 2.0 ) * dot2 * x2 * y2 * z2 ) /
2413  ( ( 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;
2414 
2415  //================================================ Set largest axis element to positive (ProSHADE standard)
2416  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) );
2417  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solX ) );
2418  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solY ) );
2419  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solZ ) );
2420  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( solX < 0.0 ) ) ||
2421  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( solY < 0.0 ) ) ||
2422  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( solZ < 0.0 ) ) ) { solX *= -1.0; solY *= -1.0; solZ *= -1.0; }
2423 
2424  //================================================ Save solutions
2428 
2429  //================================================ Done
2430  return ( ret );
2431 
2432 }
2433 
2455 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 )
2456 {
2457  //================================================ Initialise variables
2458  std::vector < proshade_double > ret;
2459 
2460  //================================================ Solution
2461  proshade_double solX = - ( y1 * dot2 * z3 - y1 * dot3 * z2 - z1 * dot2 * y3 + z1 * dot3 * y2 + dot1 * y3 * z2 - dot1 * z3 * y2 ) /
2462  ( -x1 * y3 * z2 + x1 * z3 * y2 + y1 * x3 * z2 - y1 * z3 * x2 - z1 * x3 * y2 + z1 * y3 * x2 );
2463  proshade_double solY = - ( x1 * dot2 * z3 - x1 * dot3 * z2 - z1 * dot2 * x3 + z1 * dot3 * x2 + dot1 * x3 * z2 - dot1 * z3 * x2 ) /
2464  ( x1 * y3 * z2 - x1 * z3 * y2 - y1 * x3 * z2 + y1 * z3 * x2 + z1 * x3 * y2 - z1 * y3 * x2 );
2465  proshade_double solZ = - ( x1 * dot2 * y3 - x1 * dot3 * y2 - y1 * dot2 * x3 + y1 * dot3 * x2 + dot1 * x3 * y2 - dot1 * y3 * x2 ) /
2466  ( -x1 * y3 * z2 + x1 * z3 * y2 + y1 * x3 * z2 - y1 * z3 * x2 - z1 * x3 * y2 + z1 * y3 * x2 );
2467 
2468  //================================================ Normalise the axis to magnitude 1
2469  proshade_double normFactor = sqrt ( pow ( solX, 2.0 ) + pow ( solY, 2.0 ) + pow ( solZ, 2.0 ) );
2470  solX /= normFactor;
2471  solY /= normFactor;
2472  solZ /= normFactor;
2473 
2474  //================================================ Set largest axis element to positive (ProSHADE standard)
2475  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) );
2476  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solX ) );
2477  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solY ) );
2478  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solZ ) );
2479  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( solX < 0.0 ) ) ||
2480  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( solY < 0.0 ) ) ||
2481  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( solZ < 0.0 ) ) ) { solX *= -1.0; solY *= -1.0; solZ *= -1.0; }
2482 
2483  //================================================ Save solutions
2487 
2488  //================================================ Done
2489  return ( ret );
2490 
2491 }
2492 
2499 std::vector< proshade_double > ProSHADE_internal_maths::multiplyGroupElementMatrices ( std::vector< proshade_double >* el1, std::vector< proshade_double >* el2 )
2500 {
2501  //================================================ Initialise variables
2502  std::vector< proshade_double > ret;
2503 
2504  //================================================ Compute
2505  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(0) ) +
2506  ( el1->at(1) * el2->at(3) ) +
2507  ( el1->at(2) * el2->at(6) ) );
2508  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(1) ) +
2509  ( el1->at(1) * el2->at(4) ) +
2510  ( el1->at(2) * el2->at(7) ) );
2511  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(2) ) +
2512  ( el1->at(1) * el2->at(5) ) +
2513  ( el1->at(2) * el2->at(8) ) );
2514 
2515  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(0) ) +
2516  ( el1->at(4) * el2->at(3) ) +
2517  ( el1->at(5) * el2->at(6) ) );
2518  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(1) ) +
2519  ( el1->at(4) * el2->at(4) ) +
2520  ( el1->at(5) * el2->at(7) ) );
2521  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(2) ) +
2522  ( el1->at(4) * el2->at(5) ) +
2523  ( el1->at(5) * el2->at(8) ) );
2524 
2525  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(0) ) +
2526  ( el1->at(7) * el2->at(3) ) +
2527  ( el1->at(8) * el2->at(6) ) );
2528  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(1) ) +
2529  ( el1->at(7) * el2->at(4) ) +
2530  ( el1->at(8) * el2->at(7) ) );
2531  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(2) ) +
2532  ( el1->at(7) * el2->at(5) ) +
2533  ( el1->at(8) * el2->at(8) ) );
2534 
2535  //================================================ Done
2536  return ( ret );
2537 
2538 }
2539 
2552 bool ProSHADE_internal_maths::rotationMatrixSimilarity ( std::vector< proshade_double >* mat1, std::vector< proshade_double >* mat2, proshade_double tolerance )
2553 {
2554  //================================================ Initialise variables
2555  bool ret = false;
2556 
2557  //================================================ Compute trace of mat1 * mat2^T
2558  proshade_double trace = ( mat1->at(0) * mat2->at(0) ) + ( mat1->at(1) * mat2->at(1) ) + ( mat1->at(2) * mat2->at(2) );
2559  trace += ( mat1->at(3) * mat2->at(3) ) + ( mat1->at(4) * mat2->at(4) ) + ( mat1->at(5) * mat2->at(5) );
2560  trace += ( mat1->at(6) * mat2->at(6) ) + ( mat1->at(7) * mat2->at(7) ) + ( mat1->at(8) * mat2->at(8) );
2561 
2562  //================================================ Subtract 3 (so that we would have 0 in case of idenity matrix)
2563  trace -= 3.0;
2564 
2565  //================================================ Compare to tolerance
2566  if ( tolerance > std::abs ( trace ) ) { ret = true; }
2567 
2568  //================================================ Done
2569  return ( ret );
2570 
2571 }
2572 
2589 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 )
2590 {
2591  //================================================ Initialise variables
2592  bool ret = false;
2593 
2594  //================================================ Cosine distance
2595  proshade_double cosDist = ( ( a1 * b1 ) + ( a2 * b2 ) + ( a3 * b3 ) ) /
2596  ( sqrt( pow( a1, 2.0 ) + pow( a2, 2.0 ) + pow( a3, 2.0 ) ) *
2597  sqrt( pow( b1, 2.0 ) + pow( b2, 2.0 ) + pow( b3, 2.0 ) ) );
2598 
2599  //================================================ Compare the absolute value of distance to 1.0 - tolerance
2600  if ( std::abs( cosDist ) > ( 1.0 - tolerance ) ) { ret = true; }
2601 
2602  //================================================ Done
2603  return ( ret );
2604 
2605 }
2606 
2623 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 )
2624 {
2625  //================================================ Initialise variables
2626  bool ret = false;
2627 
2628  //================================================ Cosine distance
2629  proshade_double cosDist = ( ( a1 * b1 ) + ( a2 * b2 ) + ( a3 * b3 ) ) /
2630  ( sqrt( pow( a1, 2.0 ) + pow( a2, 2.0 ) + pow( a3, 2.0 ) ) *
2631  sqrt( pow( b1, 2.0 ) + pow( b2, 2.0 ) + pow( b3, 2.0 ) ) );
2632 
2633  //================================================ Compare the absolute value of distance to 1.0 - tolerance
2634  if ( cosDist > ( 1.0 - tolerance ) ) { ret = true; }
2635 
2636  //================================================ Done
2637  return ( ret );
2638 
2639 }
2640 
2653 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 )
2654 {
2655  //================================================ Initialise variables
2656  proshade_double lonM, lonP, latM, latP, movSum;
2657  std::vector<proshade_double> latVals ( 3 );
2658  std::vector<proshade_double> lonVals ( 3 );
2659  proshade_double learningRate = 0.1;
2660  proshade_double prevVal = *bestSum;
2661  proshade_double valChange = 999.9;
2662  proshade_double origBestLat = std::round ( *bestLattitude );
2663  proshade_double origBestLon = std::round ( *bestLongitude );
2664  proshade_double tmpVal;
2665 
2666  //================================================ Initialise interpolators in all directions around the point of interest
2667  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsMinusMinus;
2668  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsMinusPlus;
2669  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsPlusMinus;
2670  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsPlusPlus;
2671  prepareBiCubicInterpolatorsMinusMinus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsMinusMinus, sphereMappedRotFun );
2672  prepareBiCubicInterpolatorsMinusPlus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsMinusPlus, sphereMappedRotFun );
2673  prepareBiCubicInterpolatorsPlusMinus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsPlusMinus, sphereMappedRotFun );
2674  prepareBiCubicInterpolatorsPlusPlus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsPlusPlus, sphereMappedRotFun );
2675 
2676  //================================================ Start the pseudo gradient ascent (while there is some change)
2677  while ( valChange > 0.0001 )
2678  {
2679  //============================================ Find the surrounding points to the currently best position
2680  lonM = *bestLongitude - step;
2681  lonP = *bestLongitude + step;
2682  latM = *bestLattitude - step;
2683  latP = *bestLattitude + step;
2684 
2685  //============================================ Deal with optimising outside of prepared range - recursion
2686  const FloatingPoint< proshade_double > lhs1 ( *bestLattitude ), rhs1 ( origBestLat - 1.0 );
2687  const FloatingPoint< proshade_double > lhs2 ( *bestLattitude ), rhs2 ( origBestLat + 1.0 );
2688  const FloatingPoint< proshade_double > lhs3 ( *bestLongitude ), rhs3 ( origBestLon - 1.0 );
2689  const FloatingPoint< proshade_double > lhs4 ( *bestLongitude ), rhs4 ( origBestLon + 1.0 );
2690  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; }
2691  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; }
2692  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; }
2693  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; }
2694 
2695  //============================================ Prepare vectors of tested positions
2696  latVals.at(0) = latM; latVals.at(1) = *bestLattitude; latVals.at(2) = latP;
2697  lonVals.at(0) = lonM; lonVals.at(1) = *bestLongitude; lonVals.at(2) = lonP;
2698 
2699  //============================================ Find the best change
2700  for ( proshade_unsign laIt = 0; laIt < static_cast<proshade_unsign> ( latVals.size() ); laIt++ )
2701  {
2702  for ( proshade_unsign loIt = 0; loIt < static_cast<proshade_unsign> ( lonVals.size() ); loIt++ )
2703  {
2704  //==================================== For this combination of lat and lon, find sum over spheres
2705  movSum = 1.0;
2706  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sphereList->size() ); iter++ )
2707  {
2708  //================================ Interpolate using correct interpolators
2709  if ( ( latVals.at(laIt) <= origBestLat ) && ( lonVals.at(loIt) <= origBestLon ) ) { movSum += interpolsMinusMinus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2710  if ( ( latVals.at(laIt) <= origBestLat ) && ( lonVals.at(loIt) > origBestLon ) ) { movSum += interpolsMinusPlus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2711  if ( ( latVals.at(laIt) > origBestLat ) && ( lonVals.at(loIt) <= origBestLon ) ) { movSum += interpolsPlusMinus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2712  if ( ( latVals.at(laIt) > origBestLat ) && ( lonVals.at(loIt) > origBestLon ) ) { movSum += interpolsPlusPlus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2713  }
2714 
2715  //==================================== If position has improved, save it
2716  if ( *bestSum < movSum )
2717  {
2718  *bestSum = movSum;
2719  *bestLongitude = lonVals.at(loIt);
2720  *bestLattitude = latVals.at(laIt);
2721  }
2722  }
2723  }
2724 
2725  //============================================ Prepare for next iteration
2726  valChange = std::floor ( 100000.0 * ( *bestSum - prevVal ) ) / 100000.0;
2727  prevVal = std::floor ( 100000.0 * ( *bestSum ) ) / 100000.0;
2728  step = std::max ( ( valChange / step ) * learningRate, 0.01 );
2729  if ( learningRate >= 0.02 ) { learningRate -= 0.01; }
2730 
2731  }
2732 
2733  //================================================ Release interpolators memory
2734  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsMinusMinus.size() ); intIt++ ) { delete interpolsMinusMinus.at(intIt); }
2735  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsMinusPlus.size() ); intIt++ ) { delete interpolsMinusPlus.at(intIt); }
2736  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsPlusMinus.size() ); intIt++ ) { delete interpolsPlusMinus.at(intIt); }
2737  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsPlusPlus.size() ); intIt++ ) { delete interpolsPlusPlus.at(intIt); }
2738 
2739  //================================================ Done
2740  return ;
2741 }
2742 
2754 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 )
2755 {
2756  //================================================ Initialise local variables
2757  proshade_signed latHlp, lonHlp;
2758  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2759 
2760  //================================================ Prepare the interpolator objects for interpolation around the position
2761  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2762  {
2763  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2764  proshade_double** interpGrid = new proshade_double*[4];
2765  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2766 
2767  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2768  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2769  {
2770  interpGrid[iter] = new proshade_double[4];
2771  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2772  }
2773 
2774  //============================================ Fill in the value grid on which the interpolation is to be done
2775  for ( proshade_signed latIt = 0; latIt < 4; latIt++ )
2776  {
2777  for ( proshade_signed lonIt = 0; lonIt < 4; lonIt++ )
2778  {
2779  latHlp = static_cast< proshade_signed > ( bestLattitude - 2.0 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2780  lonHlp = static_cast< proshade_signed > ( bestLongitude - 2.0 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2781  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2782  }
2783  }
2784 
2785  //============================================ Create the interpolators
2786  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude - 1.0, bestLongitude - 1.0 );
2787  interpols->emplace_back ( biCubInterp );
2788 
2789  //============================================ Release memory
2790  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2791  delete[] interpGrid;
2792  }
2793 
2794  //================================================ Done
2795  return ;
2796 }
2797 
2809 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 )
2810 {
2811  //================================================ Initialise local variables
2812  proshade_signed latHlp, lonHlp;
2813  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2814 
2815  //================================================ Prepare the interpolator objects for interpolation around the position
2816  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2817  {
2818  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2819  proshade_double** interpGrid = new proshade_double*[4];
2820  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2821 
2822  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2823  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2824  {
2825  interpGrid[iter] = new proshade_double[4];
2826  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2827  }
2828 
2829  //============================================ Fill in the value grid on which the interpolation is to be done
2830  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2831  {
2832  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2833  {
2834  latHlp = static_cast< proshade_signed > ( bestLattitude - 2 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2835  lonHlp = static_cast< proshade_signed > ( bestLongitude - 1 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2836  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ) , static_cast< proshade_unsign > ( lonHlp ) );
2837  }
2838  }
2839 
2840  //============================================ Create the interpolators
2841  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude - 1.0, bestLongitude );
2842  interpols->emplace_back ( biCubInterp );
2843 
2844  //============================================ Release memory
2845  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2846  delete[] interpGrid;
2847  }
2848 
2849  //================================================ Done
2850  return ;
2851 }
2852 
2864 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 )
2865 {
2866  //================================================ Initialise local variables
2867  proshade_signed latHlp, lonHlp;
2868  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2869 
2870  //================================================ Prepare the interpolator objects for interpolation around the position
2871  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2872  {
2873  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2874  proshade_double** interpGrid = new proshade_double*[4];
2875  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2876 
2877  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2878  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2879  {
2880  interpGrid[iter] = new proshade_double[4];
2881  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2882  }
2883 
2884  //============================================ Fill in the value grid on which the interpolation is to be done
2885  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2886  {
2887  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2888  {
2889  latHlp = static_cast< proshade_signed > ( bestLattitude - 1 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2890  lonHlp = static_cast< proshade_signed > ( bestLongitude - 2 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2891  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2892  }
2893  }
2894 
2895  //============================================ Create the interpolators
2896  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude, bestLongitude - 1.0 );
2897  interpols->emplace_back ( biCubInterp );
2898 
2899  //============================================ Release memory
2900  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2901  delete[] interpGrid;
2902  }
2903 
2904  //================================================ Done
2905  return ;
2906 }
2907 
2919 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 )
2920 {
2921  //================================================ Initialise local variables
2922  proshade_signed latHlp, lonHlp;
2923  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2924 
2925  //================================================ Prepare the interpolator objects for interpolation around the position
2926  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2927  {
2928  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2929  proshade_double** interpGrid = new proshade_double*[4];
2930  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2931 
2932  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2933  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2934  {
2935  interpGrid[iter] = new proshade_double[4];
2936  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2937  }
2938 
2939  //============================================ Fill in the value grid on which the interpolation is to be done
2940  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2941  {
2942  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2943  {
2944  latHlp = static_cast< proshade_signed > ( bestLattitude - 1 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2945  lonHlp = static_cast< proshade_signed > ( bestLongitude - 1 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2946  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2947  }
2948  }
2949 
2950  //============================================ Create the interpolators
2951  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude, bestLongitude );
2952  interpols->emplace_back ( biCubInterp );
2953 
2954  //============================================ Release memory
2955  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2956  delete[] interpGrid;
2957  }
2958 
2959  //================================================ Done
2960  return ;
2961 }
2962 
2974 bool ProSHADE_internal_maths::isAxisUnique ( std::vector< proshade_double* >* CSymList, proshade_double* axis, proshade_double tolerance, bool improve )
2975 {
2976  //================================================ Initialise variables
2977  bool ret = true;
2978  proshade_unsign whichImprove = 0;
2979 
2980  //================================================ For each already detected member
2981  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
2982  {
2983  //============================================ Is fold the same?
2984  const FloatingPoint< proshade_double > lhs ( CSymList->at(grIt)[0] ), rhs ( axis[0] );
2985  if ( lhs.AlmostEquals ( rhs ) )
2986  {
2987  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], axis[1], axis[2], axis[3], tolerance ) )
2988  {
2989  ret = false;
2990  whichImprove = grIt;
2991  break;
2992  }
2993  }
2994  }
2995 
2996  //================================================ Improve, if required
2997  if ( improve && !ret )
2998  {
2999  if ( axis[5] > CSymList->at(whichImprove)[5] )
3000  {
3001  CSymList->at(whichImprove)[1] = axis[1];
3002  CSymList->at(whichImprove)[2] = axis[2];
3003  CSymList->at(whichImprove)[3] = axis[3];
3004  CSymList->at(whichImprove)[4] = axis[4];
3005  CSymList->at(whichImprove)[5] = axis[5];
3006  }
3007  }
3008 
3009  //================================================ Done
3010  return ( ret );
3011 
3012 }
3013 
3026 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 )
3027 {
3028  //================================================ Initialise variables
3029  bool ret = true;
3030 
3031  //================================================ For each already detected member
3032  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
3033  {
3034  const FloatingPoint< proshade_double > lhs ( fold ), rhs ( CSymList->at(grIt)[0] );
3035  if ( lhs.AlmostEquals ( rhs ) )
3036  {
3037  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], X, Y, Z, tolerance ) )
3038  {
3039  ret = false;
3040  break;
3041  }
3042  }
3043  }
3044 
3045  //================================================ Done
3046  return ( ret );
3047 
3048 }
3049 
3058 std::vector< proshade_unsign > ProSHADE_internal_maths::findAllPrimes ( proshade_unsign upTo )
3059 {
3060  //================================================ Initialise variables
3061  std::vector< proshade_unsign > ret;
3062  std::vector< std::pair< proshade_unsign, bool > > sieveOfEratosthenesArray;
3063 
3064  //================================================ Sanity check
3065  if ( upTo < 2 ) { return ( ret ); }
3066 
3067  //================================================ Initialise the sieve array up to the required number
3068  for ( proshade_unsign iter = 2; iter <= upTo; iter++ ) { sieveOfEratosthenesArray.emplace_back ( std::pair< proshade_unsign, bool > ( iter, true ) ); }
3069 
3070  //================================================ For each entry in the array
3071  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); iter++ )
3072  {
3073  //============================================ If this entry is still true
3074  if ( sieveOfEratosthenesArray.at(iter).second )
3075  {
3076  //======================================== Set all entries with the position x * [this entry value] to false
3077  for ( proshade_unsign it = iter + sieveOfEratosthenesArray.at(iter).first; it < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); it += sieveOfEratosthenesArray.at(iter).first )
3078  {
3079  sieveOfEratosthenesArray.at(it).second = false;
3080  }
3081  }
3082  }
3083 
3084  //================================================ Copy passing results to return vector
3085  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); iter++ )
3086  {
3087  if ( sieveOfEratosthenesArray.at(iter).second ) { ProSHADE_internal_misc::addToUnsignVector ( &ret, sieveOfEratosthenesArray.at(iter).first ); }
3088  }
3089 
3090  //================================================ Done
3091  return ( ret );
3092 
3093 }
3094 
3103 proshade_double ProSHADE_internal_maths::computeGaussian ( proshade_double val, proshade_double sigma )
3104 {
3105  //================================================ Compute cumulative probability from Z-score
3106  proshade_double zScore = ( val / sigma );
3107  proshade_double cumulativeProbability = 0.5 * std::erfc ( zScore * M_SQRT1_2 );
3108 
3109  //================================================ Symmetrise
3110  if ( cumulativeProbability > 0.5 ) { cumulativeProbability = 1.0 - cumulativeProbability; }
3111 
3112  //================================================ Done
3113  return ( cumulativeProbability );
3114 
3115 }
3116 
3129 std::vector < proshade_double > ProSHADE_internal_maths::smoothen1D ( proshade_double step, proshade_signed windowSize, proshade_double sigma, std::vector< proshade_double > data )
3130 {
3131  //================================================ Initialise local variables
3132  proshade_signed windowHalf = ( windowSize - 1 ) / 2;
3133  proshade_signed totSize = static_cast< proshade_signed > ( ( 1.0 / step ) + 1 );
3134  std::vector< proshade_double > smoothened ( static_cast< size_t > ( totSize - ( windowSize - 1 ) ), 0.0 );
3135  std::vector< proshade_double > winWeights ( static_cast< size_t > ( windowSize ), 0.0 );
3136 
3137  //================================================ Prepare window weights
3138  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 ); }
3139 
3140  //================================================ Compute smoothened data
3141  for ( proshade_unsign it = 0; it < static_cast< proshade_unsign > ( smoothened.size() ); it++ )
3142  {
3143  //============================================ Compute window weighted average
3144  for ( proshade_signed winIt = 0; winIt < windowSize; winIt++ )
3145  {
3146  smoothened.at(it) += winWeights.at( static_cast< size_t > ( winIt ) ) * data.at( static_cast< size_t > ( static_cast< proshade_signed > ( it ) + winIt ) );
3147  }
3148  }
3149 
3150  //================================================ Done
3151  return ( smoothened );
3152 
3153 }
3154 
3165 proshade_single ProSHADE_internal_maths::getResolutionOfReflection ( proshade_single h, proshade_single k, proshade_single l, proshade_single xDim, proshade_single yDim, proshade_single zDim )
3166 {
3167  //================================================ Compute volume and proportions
3168  proshade_single vol = ( xDim * yDim * zDim );
3169  proshade_single sa = ( yDim * zDim ) / vol;
3170  proshade_single sb = ( xDim * zDim ) / vol;
3171  proshade_single sc = ( xDim * yDim ) / vol;
3172 
3173  //================================================ Compute distance
3174  proshade_single s2 = ( std::pow ( h * sa, 2.0f ) +
3175  std::pow ( k * sb, 2.0f ) +
3176  std::pow ( l * sc, 2.0f ) ) / 4.0f;
3177 
3178  //================================================ Deal with F000
3179  if ( s2 == 0.0f ) { s2 = 0.0000000001f; }
3180 
3181  //================================================ Done
3182  return ( 1.0f / ( 2.0f * std::sqrt ( s2 ) ) );
3183 
3184 }
3185 
3199 void ProSHADE_internal_maths::binReciprocalSpaceReflections ( proshade_unsign xInds, proshade_unsign yInds, proshade_unsign zInds, proshade_signed* noBin, proshade_signed*& binIndexing )
3200 {
3201  //================================================ Allocate output bin indexing memory and set to -100
3202  binIndexing = new proshade_signed [xInds * yInds * zInds];
3203  ProSHADE_internal_misc::checkMemoryAllocation ( binIndexing, __FILE__, __LINE__, __func__ );
3204  for ( size_t iter = 0; iter < static_cast< size_t > ( xInds * yInds * zInds ); iter++ ) { binIndexing[iter] = -100; }
3205  proshade_single xIndsF = static_cast< proshade_single > ( xInds ), yIndsF = static_cast< proshade_single > ( yInds ), zIndsF = static_cast< proshade_single > ( zInds );
3206 
3207  //================================================ Allocate local memory
3208  proshade_single *mins = new proshade_single[3];
3209  proshade_single *maxs = new proshade_single[3];
3210  proshade_single *resMins = new proshade_single[3];
3211  proshade_signed *resMinLoc = new proshade_signed[3];
3212  proshade_single *steps = new proshade_single[3];
3213 
3214  //================================================ Check local memory
3215  ProSHADE_internal_misc::checkMemoryAllocation ( mins, __FILE__, __LINE__, __func__ );
3216  ProSHADE_internal_misc::checkMemoryAllocation ( maxs, __FILE__, __LINE__, __func__ );
3217  ProSHADE_internal_misc::checkMemoryAllocation ( resMins, __FILE__, __LINE__, __func__ );
3218  ProSHADE_internal_misc::checkMemoryAllocation ( resMinLoc, __FILE__, __LINE__, __func__ );
3219  ProSHADE_internal_misc::checkMemoryAllocation ( steps, __FILE__, __LINE__, __func__ );
3220 
3221  //================================================ Initialise local variables
3222  proshade_single resol = 0.0f;
3223  proshade_signed reciX, reciY, reciZ, arrPos = 0, minLoc = -1;
3224  *noBin = 0;
3225 
3226  //================================================ Determine reciprocal space indexing
3227  mins[0] = std::floor ( xIndsF / -2.0f );
3228  mins[1] = std::floor ( yIndsF / -2.0f );
3229  mins[2] = std::floor ( zIndsF / -2.0f );
3230 
3231  maxs[0] = -mins[0];
3232  maxs[1] = -mins[1];
3233  maxs[2] = -mins[2];
3234 
3235  if ( xInds % 2 == 0 ) { mins[0] += 1.0f; }
3236  if ( yInds % 2 == 0 ) { mins[1] += 1.0f; }
3237  if ( zInds % 2 == 0 ) { mins[2] += 1.0f; }
3238 
3239  //================================================ Get minimum resolution based on dims for each dimension
3240  resMins[0] = ProSHADE_internal_maths::getResolutionOfReflection ( maxs[0], 0.0f, 0.0f, xIndsF, yIndsF, zIndsF );
3241  resMins[1] = ProSHADE_internal_maths::getResolutionOfReflection ( 0.0f, maxs[1], 0.0f, xIndsF, yIndsF, zIndsF );
3242  resMins[2] = ProSHADE_internal_maths::getResolutionOfReflection ( 0.0f, 0.0f, maxs[2], xIndsF, yIndsF, zIndsF );
3243 
3244  //================================================ Decide which dimension to work with (the one with the lowest resolution)
3245  resMinLoc[0] = 0; resMinLoc[1] = 0; resMinLoc[2] = 0;
3246  const FloatingPoint< proshade_single > lhs1 ( resMins[0] ), lhs2 ( resMins[1] ), lhs3 ( resMins[2] ), rhs1 ( std::min( resMins[0], std::min( resMins[1], resMins[2] ) ) );
3247  if ( lhs1.AlmostEquals ( rhs1 ) ) { resMinLoc[0] = 1; minLoc = 0; }
3248  if ( lhs2.AlmostEquals ( rhs1 ) ) { resMinLoc[1] = 1; minLoc = 1; }
3249  if ( lhs3.AlmostEquals ( rhs1 ) ) { resMinLoc[2] = 1; minLoc = 2; }
3250 
3251  //================================================ Find the bins and corresponding cut-offs
3252  std::vector< proshade_single > resArray ( static_cast< size_t > ( maxs[minLoc] - 1 ), 0.0f );
3253  std::vector< proshade_single > binArray ( static_cast< size_t > ( maxs[minLoc] - 1 ), 0.0f );
3254  for ( proshade_signed dimIt = 0; dimIt < static_cast< proshade_signed > ( maxs[minLoc] - 1 ); dimIt++ )
3255  {
3256  //============================================ Prepare steps
3257  steps[0] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[0] );
3258  steps[1] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[1] );
3259  steps[2] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[2] );
3260 
3261  //============================================ Find resolution
3262  resol = ProSHADE_internal_maths::getResolutionOfReflection ( steps[0], steps[1], steps[2], xIndsF, yIndsF, zIndsF );
3263 
3264  //============================================ Assign to arrays
3265  resArray.at( static_cast< size_t > ( dimIt ) ) = resol;
3266  binArray.at( static_cast< size_t > ( dimIt ) ) = static_cast< proshade_single > ( dimIt ) + 2.5f;
3267  *noBin = dimIt + 1;
3268  }
3269 
3270  //================================================ Assign reflections to bins
3271  for ( proshade_signed xIt = 0; xIt < static_cast< proshade_signed > ( xInds ); xIt++ )
3272  {
3273  for ( proshade_signed yIt = 0; yIt < static_cast< proshade_signed > ( yInds ); yIt++ )
3274  {
3275  for ( proshade_signed zIt = 0; zIt < static_cast< proshade_signed > ( zInds / 2 ) + 1; zIt++ )
3276  {
3277  //==================================== Deal with reciprocal indices ordering
3278  reciX = xIt; if ( reciX > static_cast< proshade_signed > ( maxs[0] ) ) { reciX -= static_cast< proshade_signed > ( xInds ); }
3279  reciY = yIt; if ( reciY > static_cast< proshade_signed > ( maxs[1] ) ) { reciY -= static_cast< proshade_signed > ( yInds ); }
3280  reciZ = zIt; if ( reciZ > static_cast< proshade_signed > ( maxs[2] ) ) { reciZ -= static_cast< proshade_signed > ( zInds ); }
3281 
3282  //==================================== For each bin, check if this reflection belongs to it
3283  for ( proshade_signed binIt = 0; binIt < (*noBin); binIt++ )
3284  {
3285  //================================ Check by comparing distances
3286  if ( std::sqrt ( std::pow ( static_cast< proshade_single > ( reciX ), 2.0f ) +
3287  std::pow ( static_cast< proshade_single > ( reciY ), 2.0f ) +
3288  std::pow ( static_cast< proshade_single > ( reciZ ), 2.0f ) ) <= binArray.at( static_cast< size_t > ( binIt ) ) )
3289  {
3290  //============================ This is the bin for this reflection. Assign it.
3291  arrPos = zIt + static_cast< proshade_signed > ( zInds ) * ( yIt + static_cast< proshade_signed > ( yInds ) * xIt );
3292  binIndexing[ static_cast< size_t > ( arrPos ) ] = binIt;
3293 
3294  //============================ If one of the uneven ends, do not use Friedel's Law
3295  if ( reciX == static_cast< proshade_signed > ( mins[0] ) || -reciX == static_cast< proshade_signed > ( mins[0] ) ) { break; }
3296  if ( reciY == static_cast< proshade_signed > ( mins[1] ) || -reciY == static_cast< proshade_signed > ( mins[1] ) ) { break; }
3297  if ( reciZ == static_cast< proshade_signed > ( mins[2] ) || -reciZ == static_cast< proshade_signed > ( mins[2] ) ) { break; }
3298 
3299  //============================ Use Friedel's Law to find the second index (this is why we can use zDim / 2)
3300  reciX *= -1; if ( reciX < 0 ) { reciX += static_cast< proshade_signed > ( xInds ); }
3301  reciY *= -1; if ( reciY < 0 ) { reciY += static_cast< proshade_signed > ( yInds ); }
3302  reciZ *= -1; if ( reciZ < 0 ) { reciZ += static_cast< proshade_signed > ( zInds ); }
3303 
3304  //============================ Apply Friedel's Law
3305  arrPos = reciZ + static_cast< proshade_signed > ( zInds ) * ( reciY + static_cast< proshade_signed > ( yInds ) * reciX );
3306  binIndexing[ static_cast< size_t > ( arrPos ) ] = binIt;
3307 
3308  //============================ Done, exit bins loop
3309  break;
3310  }
3311  }
3312  }
3313  }
3314  }
3315 
3316  //================================================ Release memory
3317  delete[] mins;
3318  delete[] maxs;
3319  delete[] resMins;
3320  delete[] resMinLoc;
3321  delete[] steps;
3322 
3323  //================================================ Done
3324  return ;
3325 
3326 }
3327 
3347 proshade_double ProSHADE_internal_maths::computeFSC ( fftw_complex *fCoeffs1, fftw_complex *fCoeffs2, proshade_unsign xInds, proshade_unsign yInds, proshade_unsign zInds, proshade_signed noBins, proshade_signed* binIndexing, proshade_double**& binData, proshade_signed*& binCounts, proshade_double*& fscByBin )
3348 {
3349  //================================================ Initialise local variables
3350  proshade_double realOrig, realRot, imagOrig, imagRot, fsc = 0.0;;
3351  proshade_signed indx, arrPos;
3352  std::vector< proshade_double > covarByBin ( static_cast< size_t > ( noBins ), 0.0 );
3353 
3354  //================================================ Clean FSC computation memory
3355  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; } }
3356  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ ) { binCounts[binIt] = 0; }
3357 
3358  //================================================ Compute bin sums
3359  for ( proshade_signed xIt = 0; xIt < static_cast< proshade_signed > ( xInds ); xIt++ )
3360  {
3361  for ( proshade_signed yIt = 0; yIt < static_cast< proshade_signed > ( yInds ); yIt++ )
3362  {
3363  for ( proshade_signed zIt = 0; zIt < static_cast< proshade_signed > ( zInds ); zIt++ )
3364  {
3365  //==================================== Find array position
3366  arrPos = zIt + static_cast< proshade_signed > ( zInds ) * ( yIt + static_cast< proshade_signed > ( yInds ) * xIt );
3367 
3368  //==================================== If no bin is associated, skip this reflection
3369  indx = binIndexing[ static_cast< size_t > ( arrPos ) ];
3370  if ( ( indx < 0 ) || ( indx > noBins ) ) { continue; }
3371 
3372  //==================================== Calculate the sums
3373  realOrig = fCoeffs1[arrPos][0];
3374  imagOrig = fCoeffs1[arrPos][1];
3375  realRot = fCoeffs2[arrPos][0];
3376  imagRot = fCoeffs2[arrPos][1];
3377 
3378  binData[indx][0] += realOrig;
3379  binData[indx][1] += imagOrig;
3380  binData[indx][2] += realRot;
3381  binData[indx][3] += imagRot;
3382  binData[indx][4] += realOrig * realRot;
3383  binData[indx][5] += imagOrig * imagRot;
3384  binData[indx][6] += std::pow ( realOrig, 2.0 );
3385  binData[indx][7] += std::pow ( imagOrig, 2.0 );
3386  binData[indx][8] += std::pow ( realRot, 2.0 );
3387  binData[indx][9] += std::pow ( imagRot, 2.0 );
3388 
3389  //==================================== Update bin counts
3390  binCounts[indx] += 1;
3391  }
3392  }
3393  }
3394 
3395  //================================================ Compute covariance by bin
3396  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3397  {
3398  covarByBin.at(binIt) = ( ( binData[binIt][4] + binData[binIt][5] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3399  ( ( binData[binIt][0] / static_cast< proshade_double > ( binCounts[binIt] ) *
3400  binData[binIt][2] / static_cast< proshade_double > ( binCounts[binIt] ) ) +
3401  ( binData[binIt][1] / static_cast< proshade_double > ( binCounts[binIt] ) *
3402  binData[binIt][3] / static_cast< proshade_double > ( binCounts[binIt] ) ) ) );
3403  }
3404 
3405  //================================================ Get FSC by bin
3406  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3407  {
3408  binData[binIt][10] = ( binData[binIt][6] + binData[binIt][7] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3409  ( std::pow ( binData[binIt][0] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) +
3410  std::pow ( binData[binIt][1] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) );
3411  binData[binIt][11] = ( binData[binIt][8] + binData[binIt][9] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3412  ( std::pow ( binData[binIt][2] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) +
3413  std::pow ( binData[binIt][3] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) );
3414  fscByBin[binIt] = covarByBin.at(binIt) / ( std::sqrt ( binData[binIt][10] ) * std::sqrt ( binData[binIt][11] ) );
3415  }
3416 
3417  //================================================ Get average FSC over all bins
3418  proshade_double binSizeSum = 0.0;
3419  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3420  {
3421  fsc += fscByBin[binIt] * static_cast< proshade_double > ( binCounts[binIt] );
3422  binSizeSum += static_cast< proshade_double > ( binCounts[binIt] );
3423  }
3424  fsc /= static_cast< proshade_double > ( binSizeSum );
3425 
3426  //================================================ Done
3427  return ( fsc );
3428 
3429 }
3430 
3446 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 )
3447 {
3448  //================================================ Initialise local variables
3449  proshade_signed indx, arrPos, reciX, reciY, reciZ;
3450 
3451  //================================================ Allocate memmory
3452  weights1 = new proshade_double[xDim * yDim * zDim];
3453  weights2 = new proshade_double[xDim * yDim * zDim];
3454  proshade_single *mins = new proshade_single[3];
3455  proshade_single *maxs = new proshade_single[3];
3456 
3457  //================================================ Check memory allocation
3458  ProSHADE_internal_misc::checkMemoryAllocation ( weights1, __FILE__, __LINE__, __func__ );
3459  ProSHADE_internal_misc::checkMemoryAllocation ( weights2, __FILE__, __LINE__, __func__ );
3460  ProSHADE_internal_misc::checkMemoryAllocation ( mins, __FILE__, __LINE__, __func__ );
3461  ProSHADE_internal_misc::checkMemoryAllocation ( maxs, __FILE__, __LINE__, __func__ );
3462 
3463  //================================================ Assign values to the memory
3464  for ( size_t iter = 0; iter < static_cast< size_t > ( xDim * yDim * zDim ); iter++ ) { weights1[iter] = -100.0; weights2[iter] = -100.0; }
3465 
3466  //================================================ Determine reciprocal space indexing ranges
3467  mins[0] = std::floor ( static_cast< proshade_single > ( xDim ) / -2.0f );
3468  mins[1] = std::floor ( static_cast< proshade_single > ( yDim ) / -2.0f );
3469  mins[2] = std::floor ( static_cast< proshade_single > ( zDim ) / -2.0f );
3470 
3471  maxs[0] = -mins[0];
3472  maxs[1] = -mins[1];
3473  maxs[2] = -mins[2];
3474 
3475  if ( xDim % 2 == 0 ) { mins[0] += 1.0f; }
3476  if ( yDim % 2 == 0 ) { mins[1] += 1.0f; }
3477  if ( zDim % 2 == 0 ) { mins[2] += 1.0f; }
3478 
3479  //================================================ For each reflection
3480  for ( proshade_signed xIt = 0; xIt < xDim; xIt++ )
3481  {
3482  for ( proshade_signed yIt = 0; yIt < yDim; yIt++ )
3483  {
3484  for ( proshade_signed zIt = 0; zIt < ( ( zDim / 2 ) + 1 ); zIt++ )
3485  {
3486  //==================================== Deal with reciprocal indices ordering
3487  reciX = xIt; if ( reciX > static_cast< proshade_signed > ( maxs[0] ) ) { reciX -= static_cast< proshade_signed > ( xDim ); }
3488  reciY = yIt; if ( reciY > static_cast< proshade_signed > ( maxs[1] ) ) { reciY -= static_cast< proshade_signed > ( yDim ); }
3489  reciZ = zIt; if ( reciZ > static_cast< proshade_signed > ( maxs[2] ) ) { reciZ -= static_cast< proshade_signed > ( zDim ); }
3490 
3491  //==================================== Find array position and bin index
3492  arrPos = zIt + zDim * ( yIt + yDim * xIt );
3493  indx = binIndexing[ static_cast< size_t > ( arrPos ) ];
3494 
3495  //==================================== Ignore unassigned bin reflections
3496  if ( ( indx < 0 ) || ( indx > noBins ) ) { continue; }
3497 
3498  //==================================== Set weights using the bin FSC
3499  weights1[arrPos] = fscByBin[indx];
3500  weights2[arrPos] = std::pow ( fscByBin[indx], 2.0 );
3501 
3502  //==================================== If one of the uneven ends, do not use Friedel's Law
3503  if ( reciX == static_cast< proshade_signed > ( mins[0] ) || -reciX == static_cast< proshade_signed > ( mins[0] ) ) { break; }
3504  if ( reciY == static_cast< proshade_signed > ( mins[1] ) || -reciY == static_cast< proshade_signed > ( mins[1] ) ) { break; }
3505  if ( reciZ == static_cast< proshade_signed > ( mins[2] ) || -reciZ == static_cast< proshade_signed > ( mins[2] ) ) { break; }
3506 
3507  //==================================== Use Friedel's Law to find the second index (this is why we can use zDim / 2)
3508  reciX *= -1; if ( reciX < 0 ) { reciX += xDim; }
3509  reciY *= -1; if ( reciY < 0 ) { reciY += yDim; }
3510  reciZ *= -1; if ( reciZ < 0 ) { reciZ += zDim; }
3511 
3512  //==================================== Apply Friedel's Law
3513  arrPos = reciZ + zDim * ( reciY + yDim * reciX );
3514  weights1[arrPos] = fscByBin[indx];
3515  weights2[arrPos] = std::pow ( fscByBin[indx], 2.0 );
3516  }
3517  }
3518  }
3519 
3520  //================================================ Release memory
3521  delete[] mins;
3522  delete[] maxs;
3523 
3524  //================================================ Done
3525  return ;
3526 
3527 }
3528 
3538 proshade_double ProSHADE_internal_maths::computeTheFValue ( proshade_complex* fCoeffs, proshade_double* weights, proshade_signed xDim, proshade_signed yDim, proshade_signed zDim )
3539 {
3540  //================================================ Initialise local variables
3541  proshade_double sum = 0.0;
3542  proshade_signed arrPos;
3543 
3544  //================================================ For each reflection
3545  for ( proshade_signed xIt = 0; xIt < xDim; xIt++ )
3546  {
3547  for ( proshade_signed yIt = 0; yIt < yDim; yIt++ )
3548  {
3549  for ( proshade_signed zIt = 0; zIt < ( ( zDim / 2 ) + 1 ); zIt++ )
3550  {
3551  //==================================== Find array position and bin index
3552  arrPos = zIt + zDim * ( yIt + yDim * xIt );
3553 
3554  //==================================== Sum real parts if weight exists
3555  if ( weights[arrPos] > -2.0 ) { sum += fCoeffs[arrPos][0]; }
3556  }
3557  }
3558  }
3559 
3560  //================================================ Done
3561  return ( sum );
3562 
3563 }
3564 
3576 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 )
3577 {
3578  //================================================ Allocate memmory
3579  firstDers = new proshade_double[3];
3580  secondDers = new proshade_double[9];
3581  proshade_single *mins = new proshade_single[3];
3582  proshade_single *maxs = new proshade_single[3];
3583 
3584  //================================================ Check memory allocation
3585  ProSHADE_internal_misc::checkMemoryAllocation ( firstDers, __FILE__, __LINE__, __func__ );
3586  ProSHADE_internal_misc::checkMemoryAllocation ( secondDers, __FILE__, __LINE__, __func__ );
3587  ProSHADE_internal_misc::checkMemoryAllocation ( mins, __FILE__, __LINE__, __func__ );
3588  ProSHADE_internal_misc::checkMemoryAllocation ( maxs, __FILE__, __LINE__, __func__ );
3589 
3590  //================================================ Initialise variables
3591  std::complex< proshade_double > piConstFirst ( 2.0 * M_PI, 1.0 );
3592  proshade_double piConstSecond = std::pow ( 2.0 * M_PI, 2.0 );
3593  for ( size_t iter = 0; iter < 3; iter++ ) { firstDers[iter] = 0.0; }
3594  for ( size_t iter = 0; iter < 9; iter++ ) { secondDers[iter] = 0.0; }
3595  proshade_signed reciX, reciY, reciZ, arrPos;
3596 
3597  //================================================ Determine reciprocal space indexing ranges
3598  mins[0] = std::floor ( static_cast< proshade_single > ( xDim ) / -2.0f );
3599  mins[1] = std::floor ( static_cast< proshade_single > ( yDim ) / -2.0f );
3600  mins[2] = std::floor ( static_cast< proshade_single > ( zDim ) / -2.0f );
3601 
3602  maxs[0] = -mins[0];
3603  maxs[1] = -mins[1];
3604  maxs[2] = -mins[2];
3605 
3606  if ( xDim % 2 == 0 ) { mins[0] += 1.0f; }
3607  if ( yDim % 2 == 0 ) { mins[1] += 1.0f; }
3608  if ( zDim % 2 == 0 ) { mins[2] += 1.0f; }
3609 
3610  //================================================ For each reflection
3611  for ( proshade_signed xIt = 0; xIt < xDim; xIt++ )
3612  {
3613  for ( proshade_signed yIt = 0; yIt < yDim; yIt++ )
3614  {
3615  for ( proshade_signed zIt = 0; zIt < ( ( zDim / 2 ) + 1 ); zIt++ )
3616  {
3617  //==================================== Deal with reciprocal indices ordering
3618  reciX = xIt; if ( reciX > static_cast< proshade_signed > ( maxs[0] ) ) { reciX -= static_cast< proshade_signed > ( xDim ); }
3619  reciY = yIt; if ( reciY > static_cast< proshade_signed > ( maxs[1] ) ) { reciY -= static_cast< proshade_signed > ( yDim ); }
3620  reciZ = zIt; if ( reciZ > static_cast< proshade_signed > ( maxs[2] ) ) { reciZ -= static_cast< proshade_signed > ( zDim ); }
3621 
3622  //==================================== Find array position and bin index
3623  arrPos = zIt + zDim * ( yIt + yDim * xIt );
3624 
3625  //==================================== Ignore if outside of weights
3626  if ( weights1[arrPos] < -2.0 ) { continue; }
3627 
3628  //==================================== Add to the first derivatives sum
3629  firstDers[0] += ( weights1[arrPos] * fCoeffs[arrPos][0] * std::conj( fCoeffs[arrPos][1] * piConstFirst * static_cast< proshade_double > ( reciX ) ) ).real();
3630  firstDers[1] += ( weights1[arrPos] * fCoeffs[arrPos][0] * std::conj( fCoeffs[arrPos][1] * piConstFirst * static_cast< proshade_double > ( reciY ) ) ).real();
3631  firstDers[2] += ( weights1[arrPos] * fCoeffs[arrPos][0] * std::conj( fCoeffs[arrPos][1] * piConstFirst * static_cast< proshade_double > ( reciZ ) ) ).real();
3632 
3633  //==================================== Add to the second derivatives sum
3634  secondDers[0] += weights2[arrPos] * reciX * reciX;
3635  secondDers[1] += weights2[arrPos] * reciX * reciY;
3636  secondDers[2] += weights2[arrPos] * reciX * reciZ;
3637  secondDers[4] += weights2[arrPos] * reciY * reciY;
3638  secondDers[5] += weights2[arrPos] * reciY * reciZ;
3639  secondDers[8] += weights2[arrPos] * reciZ * reciZ;
3640  }
3641  }
3642  }
3643 
3644  //================================================ Complete second darivatives matrix
3645  secondDers[3] = secondDers[1];
3646  secondDers[6] = secondDers[2];
3647  secondDers[7] = secondDers[5];
3648  for ( size_t iter = 0; iter < 9; iter++ ) { secondDers[iter] *= -piConstSecond; }
3649 
3650  //================================================ Release memory
3651  delete[] mins;
3652  delete[] maxs;
3653 
3654  //================================================ Done
3655  return ;
3656 
3657 }
3658 
3665 proshade_double* ProSHADE_internal_maths::computeTrFunStep ( proshade_double* firstDers, proshade_double* secondDers )
3666 {
3667  //================================================ Change format of second derivatives and add I matrix (the inversion function will subtract it)
3668  std::vector < proshade_double > tmpMap ( 9, 0.0 );
3669  for ( size_t iter = 0; iter < 9; iter++ ) { tmpMap.at(iter) = secondDers[iter]; }
3670  tmpMap.at(0) += 1.0; tmpMap.at(4) += 1.0; tmpMap.at(8) += 1.0;
3671 
3672  //================================================ Compute matrix inversion for the second derivatives matrix
3673  proshade_double* secondInv = compute3x3MoorePenrosePseudoInverseOfIMinusMat ( &tmpMap, -1 );
3674 
3675  //================================================ Compute dot product between the inverted matrix and the first derivatives vector
3676  proshade_double* stepArr = compute3x3MatrixVectorMultiplication ( secondInv, -firstDers[0], -firstDers[1], -firstDers[2] );
3677 
3678  //================================================ Release memory
3679  delete[] secondInv;
3680 
3681  //================================================ Done
3682  return ( stepArr );
3683 
3684 }
3685 
3693 std::vector< proshade_signed > ProSHADE_internal_maths::findPeaks1D ( std::vector< proshade_double > data )
3694 {
3695  //================================================ Initialise local variables
3696  std::vector< proshade_signed > ret;
3697 
3698  //================================================ Peak is simply any position with both neighbours having lower position (with special care for borders)
3699  for ( proshade_signed index = 0; index < static_cast< proshade_signed > ( data.size() ); index++ )
3700  {
3701  //============================================ Starting border?
3702  if ( index == 0 )
3703  {
3704  if ( data.size() > 1 ) { if ( data.at(0) > data.at(1) ) { ProSHADE_internal_misc::addToSignedVector ( &ret, index ); } }
3705  continue;
3706  }
3707 
3708  //============================================ End border?
3709  if ( index == static_cast< proshade_signed > ( data.size() - 1 ) )
3710  {
3711  if ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index ) - 1 ) ) { ProSHADE_internal_misc::addToSignedVector ( &ret, index ); }
3712  continue;
3713  }
3714 
3715  //============================================ Is this a peak?
3716  if ( ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index ) - 1 ) ) &&
3717  ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index ) + 1 ) ) ) { ProSHADE_internal_misc::addToSignedVector ( &ret, index ); }
3718 
3719  //============================================ Deal with equally sized values
3720  if ( index < static_cast< proshade_signed > ( data.size() - 2 ) ) { if ( data.at( static_cast< size_t > ( index ) ) >= data.at( static_cast< size_t > ( index ) - 1 ) ) { if ( data.at( static_cast< size_t > ( index ) ) >= data.at( static_cast< size_t > ( index ) + 1 ) ) { if ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index ) + 2 ) ) { ProSHADE_internal_misc::addToSignedVector ( &ret, index ); } } } }
3721  }
3722 
3723  //================================================ Done
3724  return ( ret );
3725 
3726 }
3727 
3728 
3743 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 )
3744 {
3745  //================================================ Initialise local variables
3746  proshade_double threshold = 0.0;
3747  proshade_signed totSize = static_cast< proshade_signed > ( ( 1.0 / step ) + 1 );
3748  std::vector< std::pair < proshade_double, proshade_unsign > > vals;
3749  std::vector< proshade_double > hist ( static_cast< unsigned long int > ( totSize ), 0.0 );
3750  proshade_unsign histPos = 0;
3751 
3752  //================================================ Make sure window size is odd
3753  if ( windowSize % 2 == 0 ) { windowSize += 1; }
3754 
3755  //================================================ Get vector of pairs of peak heights and indices in CSym array
3756  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( CSym->size() ); symIt++ ) { vals.emplace_back ( std::pair < proshade_double, proshade_unsign > ( CSym->at(symIt)[peakPos], symIt ) ); }
3757 
3758  //================================================ Bump all top peaks together - we do not want single high peak overshadowing many good peaks
3759  for ( proshade_unsign vIt = 0; vIt < static_cast< proshade_unsign > ( vals.size() ); vIt++ ) { if ( vals.at(vIt).first > maxLim ) { vals.at(vIt).first = maxLim; } }
3760 
3761  //================================================ Convert all found heights to histogram from 0.0 to 1.0 by step
3762  for ( proshade_double it = 0.0; it <= 1.0; it = it + step )
3763  {
3764  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( vals.size() ); symIt++ )
3765  {
3766  //======================================== Is this height in the range?
3767  if ( ( vals.at(symIt).first > it ) && ( vals.at(symIt).first <= ( it + step ) ) ) { hist.at(histPos) += 1.0; }
3768  }
3769 
3770  //============================================ Update counter and continue
3771  histPos += 1;
3772  }
3773 
3774  //================================================ Smoothen the distribution
3775  std::vector< proshade_double > smoothened = ProSHADE_internal_maths::smoothen1D ( step, windowSize, sigma, hist );
3776 
3777  //================================================ Find peaks in smoothened data
3778  std::vector< proshade_signed > peaks = ProSHADE_internal_maths::findPeaks1D ( smoothened );
3779 
3780  //================================================ Take best peaks surroundings and produce a new set of "high" axes
3781  proshade_signed bestHistPos;
3782  if ( peaks.size() > 0 ) { bestHistPos = peaks.at(peaks.size()-1) + ( ( windowSize - 1 ) / 2 ); }
3783  else { bestHistPos = 0.0; }
3784 
3785  threshold = ( static_cast< proshade_double > ( bestHistPos ) * step ) - ( static_cast< proshade_double > ( windowSize - 1 ) * step );
3786 
3787  //================================================ Done
3788  return ( threshold );
3789 
3790 }
3791 
3806 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 )
3807 {
3808  //================================================ Initialise local variables
3809  proshade_double threshold = 0.0;
3810  proshade_signed totSize = static_cast< proshade_signed > ( ( 1.0 / step ) + 1 );
3811  std::vector< std::pair < proshade_double, proshade_unsign > > vals;
3812  std::vector< proshade_double > hist ( static_cast< unsigned long int > ( totSize ), 0.0 );
3813  proshade_unsign histPos = 0;
3814 
3815  //================================================ Make sure window size is odd
3816  if ( windowSize % 2 == 0 ) { windowSize += 1; }
3817 
3818  //================================================ Get vector of pairs of peak heights and indices in CSym array
3819  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( CSym->size() ); symIt++ ) { vals.emplace_back ( std::pair < proshade_double, proshade_unsign > ( CSym->at(symIt).at(peakPos), symIt ) ); }
3820 
3821  //================================================ Bump all top peaks together - we do not want single high peak overshadowing many good peaks
3822  for ( proshade_unsign vIt = 0; vIt < static_cast< proshade_unsign > ( vals.size() ); vIt++ ) { if ( vals.at(vIt).first > maxLim ) { vals.at(vIt).first = maxLim; } }
3823 
3824 
3825  //================================================ Convert all found heights to histogram from 0.0 to 1.0 by step
3826  for ( proshade_double it = 0.0; it <= 1.0; it = it + step )
3827  {
3828  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( vals.size() ); symIt++ )
3829  {
3830  //======================================== Is this height in the range?
3831  if ( ( vals.at(symIt).first > it ) && ( vals.at(symIt).first <= ( it + step ) ) ) { hist.at(histPos) += 1.0; }
3832  }
3833 
3834  //============================================ Update counter and continue
3835  histPos += 1;
3836  }
3837 
3838  //================================================ Smoothen the distribution
3839  std::vector< proshade_double > smoothened = ProSHADE_internal_maths::smoothen1D ( step, windowSize, sigma, hist );
3840 
3841  //================================================ Find peaks in smoothened data
3842  std::vector< proshade_signed > peaks = ProSHADE_internal_maths::findPeaks1D ( smoothened );
3843 
3844  //================================================ Take best peaks surroundings and produce a new set of "high" axes
3845  proshade_signed bestHistPos;
3846  if ( peaks.size() > 0 ) { bestHistPos = peaks.at(peaks.size()-1) + ( ( windowSize - 1 ) / 2 ); }
3847  else { bestHistPos = 0.0; }
3848 
3849  threshold = ( static_cast< proshade_double > ( bestHistPos ) * step ) - ( static_cast< proshade_double > ( windowSize ) * step );
3850 
3851  //================================================ Done
3852  return ( threshold );
3853 
3854 }
3855 
3865 void ProSHADE_internal_maths::combineFourierForTranslation ( fftw_complex* tmpOut1, fftw_complex* tmpOut2, fftw_complex*& resOut, proshade_unsign xD, proshade_unsign yD, proshade_unsign zD )
3866 {
3867  //================================================ Initialise local variables
3868  double normFactor = static_cast<double> ( xD * yD * zD );
3869  proshade_signed arrPos;
3870 
3871  //================================================ Combine the coefficients
3872  for ( proshade_signed xIt = 0; xIt < static_cast< proshade_signed > ( xD ); xIt++ )
3873  {
3874  for ( proshade_signed yIt = 0; yIt < static_cast< proshade_signed > ( yD ); yIt++ )
3875  {
3876  for ( proshade_signed zIt = 0; zIt < static_cast< proshade_signed > ( zD ); zIt++ )
3877  {
3878  //==================================== Find indices
3879  arrPos = zIt + static_cast< proshade_signed > ( zD ) * ( yIt + static_cast< proshade_signed > ( yD ) * xIt );
3880 
3881  //==================================== Combine
3883  &tmpOut1[arrPos][1],
3884  &tmpOut2[arrPos][0],
3885  &tmpOut2[arrPos][1],
3886  &resOut[arrPos][0],
3887  &resOut[arrPos][1] );
3888 
3889  //==================================== Save
3890  resOut[arrPos][0] /= normFactor;
3891  resOut[arrPos][1] /= normFactor;
3892  }
3893  }
3894  }
3895 
3896  //================================================ Done
3897  return ;
3898 
3899 }
3900 
3912 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 )
3913 {
3914  //================================================ Initialise variables
3915  proshade_signed arrPos;
3916  *mapPeak = 0.0;
3917 
3918  //================================================ Search the map
3919  for ( proshade_signed uIt = 0; uIt < static_cast<proshade_signed> ( xD ); uIt++ )
3920  {
3921  for ( proshade_signed vIt = 0; vIt < static_cast<proshade_signed> ( yD ); vIt++ )
3922  {
3923  for ( proshade_signed wIt = 0; wIt < static_cast<proshade_signed> ( zD ); wIt++ )
3924  {
3925  arrPos = wIt + static_cast< proshade_signed > ( zD ) * ( vIt + static_cast< proshade_signed > ( yD ) * uIt );
3926  if ( resIn[arrPos][0] > *mapPeak )
3927  {
3928  *mapPeak = resIn[arrPos][0];
3929  *trsX = static_cast< proshade_double > ( uIt );
3930  *trsY = static_cast< proshade_double > ( vIt );
3931  *trsZ = static_cast< proshade_double > ( wIt );
3932  }
3933  }
3934  }
3935  }
3936 
3937  //================================================ Done
3938  return ;
3939 
3940 }
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:711
ProSHADE_internal_maths::findVectorFromThreeVAndThreeD
std::vector< proshade_double > findVectorFromThreeVAndThreeD(proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2, proshade_double x3, proshade_double y3, proshade_double z3, proshade_double dot1, proshade_double dot2, proshade_double dot3)
Function for finding a vector which would have a given three dot products to three other vectors.
Definition: ProSHADE_maths.cpp:2455
ProSHADE_internal_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:3665
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:621
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:2809
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:3538
ProSHADE_internal_maths::computeCrossProduct
proshade_double * computeCrossProduct(proshade_double *x1, proshade_double *y1, proshade_double *z1, proshade_double *x2, proshade_double *y2, proshade_double *z2)
Simple 3D vector cross product computation.
Definition: ProSHADE_maths.cpp:1820
ProSHADE_internal_maths::getEulerZXZFromRotMatrix
void getEulerZXZFromRotMatrix(proshade_double *rotMat, proshade_double *eA, proshade_double *eB, proshade_double *eG)
This function converts rotation matrix to the Euler ZXZ angles representation.
Definition: ProSHADE_maths.cpp:1562
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:1771
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:2864
ProSHADE_internal_maths::evaluateGLSeries
proshade_double evaluateGLSeries(proshade_double *series, proshade_double target, proshade_unsign terms)
This function evaluates the Taylor expansion.
Definition: ProSHADE_maths.cpp:449
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:2004
ProSHADE_internal_maths::getSOFTPositionFromEulerZXZ
void getSOFTPositionFromEulerZXZ(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 (ZXZ convention).
Definition: ProSHADE_maths.cpp:988
ProSHADE_maths.hpp
This header file declares all the functions required for computing various information from the ProSH...
ProSHADE_internal_maths::getRotationMatrixFromEulerZXZAngles
void getRotationMatrixFromEulerZXZAngles(proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double *matrix)
Function to find the rotation matrix from Euler angles (ZXZ convention).
Definition: ProSHADE_maths.cpp:1020
ProSHADE_internal_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::getGLFirstEvenRoot
void getGLFirstEvenRoot(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::getEulerZXZFromAngleAxis
void getEulerZXZFromAngleAxis(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 ZXZ angles representation.
Definition: ProSHADE_maths.cpp:1613
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:2653
ProSHADE_internal_maths::vectorOrientationSimilarity
bool vectorOrientationSimilarity(proshade_double a1, proshade_double a2, proshade_double a3, proshade_double b1, proshade_double b2, proshade_double b3, proshade_double tolerance=0.1)
This function compares two vectors using cosine distance and decides if they are similar using tolera...
Definition: ProSHADE_maths.cpp:2589
ProSHADE_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:804
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:2754
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:2623
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:3103
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:1788
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:3693
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:1459
ProSHADE_internal_maths::computeFSC
proshade_double computeFSC(fftw_complex *fCoeffs1, fftw_complex *fCoeffs2, proshade_unsign xInds, proshade_unsign yInds, proshade_unsign zInds, proshade_signed noBins, proshade_signed *binIndexing, proshade_double **&binData, proshade_signed *&binCounts, proshade_double *&fscByBin)
This function computes the FSC.
Definition: ProSHADE_maths.cpp:3347
ProSHADE_internal_maths::findHighestValueInMap
void findHighestValueInMap(fftw_complex *resIn, proshade_unsign xD, proshade_unsign yD, proshade_unsign zD, proshade_double *trsX, proshade_double *trsY, proshade_double *trsZ, proshade_double *mapPeak)
This function simply finds the highest value in fftw_complex map and returns its position and value.
Definition: ProSHADE_maths.cpp:3912
ProSHADE_internal_maths::getAxisAngleFromRotationMatrix
void getAxisAngleFromRotationMatrix(proshade_double *rotMat, proshade_double *x, proshade_double *y, proshade_double *z, proshade_double *ang, proshade_signed verbose=1)
This function converts rotation matrix to the axis-angle representation.
Definition: ProSHADE_maths.cpp:1084
ProSHADE_internal_maths::build3x3MatrixFromXYZRotations
proshade_double * build3x3MatrixFromXYZRotations(proshade_double xRot, proshade_double yRot, proshade_double zRot)
Function for building a 3x3 rotation matrix from the x, y and z rotations in degrees.
Definition: ProSHADE_maths.cpp:2033
ProSHADE_internal_maths::binReciprocalSpaceReflections
void binReciprocalSpaceReflections(proshade_unsign xInds, proshade_unsign yInds, proshade_unsign zInds, proshade_signed *noBin, proshade_signed *&binIndexing)
This function does binning of the reciprocal space reflections.
Definition: ProSHADE_maths.cpp:3199
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:871
ProSHADE_internal_maths::combineFourierForTranslation
void combineFourierForTranslation(fftw_complex *tmpOut1, fftw_complex *tmpOut2, fftw_complex *&resOut, proshade_unsign xD, proshade_unsign yD, proshade_unsign zD)
This function combines Fourier coefficients of two structures in a way, so that inverse Fourier of th...
Definition: ProSHADE_maths.cpp:3865
ProSHADE_internal_maths::smoothen1D
std::vector< proshade_double > smoothen1D(proshade_double step, proshade_signed windowSize, proshade_double sigma, std::vector< proshade_double > data)
This function takes a 1D vector and computes smoothened version based on the parameters.
Definition: ProSHADE_maths.cpp:3129
ProSHADE_internal_maths::BicubicInterpolator
Definition: ProSHADE_maths.hpp:110
ProSHADE_internal_maths::findTopGroupSmooth
proshade_double findTopGroupSmooth(std::vector< proshade_double * > *CSym, size_t peakPos, proshade_double step, proshade_double sigma, proshade_signed windowSize, proshade_double maxLim=0.9)
This function finds a subgroup of axes with distinctly higher correlation value.
Definition: ProSHADE_maths.cpp:3743
ProSHADE_internal_maths::primeFactorsDecomp
std::vector< proshade_signed > primeFactorsDecomp(proshade_signed number)
Function to find prime factors of an integer.
Definition: ProSHADE_maths.cpp:1722
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:2974
ProSHADE_internal_maths::getLegendreAbscAndWeights
void getLegendreAbscAndWeights(proshade_unsign order, proshade_double *abscissas, proshade_double *weights, proshade_unsign taylorSeriesCap)
Function to prepare abscissas and weights for Gauss-Legendre integration.
Definition: ProSHADE_maths.cpp:289
ProSHADE_internal_maths::advanceGLPolyValue
proshade_double advanceGLPolyValue(proshade_double from, proshade_double to, proshade_double valAtFrom, proshade_unsign noSteps, proshade_unsign taylorSeriesCap)
This function finds the next value of the polynomial.
Definition: ProSHADE_maths.cpp:479
ProSHADE_internal_maths::findRotMatMatchingVectors
proshade_double * findRotMatMatchingVectors(proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2)
Computation of rotation matrix rotating one vector onto the other.
Definition: ProSHADE_maths.cpp:2095
ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication
proshade_double * compute3x3MatrixVectorMultiplication(proshade_double *mat, proshade_double x, proshade_double y, proshade_double z)
Function for computing a 3x3 matrix to 3x1 vector multiplication.
Definition: ProSHADE_maths.cpp:1898
ProSHADE_internal_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:2162
ProSHADE_internal_maths::rotationMatrixSimilarity
bool rotationMatrixSimilarity(std::vector< proshade_double > *mat1, std::vector< proshade_double > *mat2, proshade_double tolerance=0.1)
This function compares the distance between two rotation matrices and decides if they are similar usi...
Definition: ProSHADE_maths.cpp:2552
ProSHADE_internal_misc::checkMemoryAllocation
void checkMemoryAllocation(chVar checkVar, std::string fileP, unsigned int lineP, std::string funcP, std::string infoP="This error may occurs when ProSHADE requests memory to be\n : allocated to it and this operation fails. This could\n : happen when not enough memory is available, either due to\n : other processes using a lot of memory, or when the machine\n : does not have sufficient memory available. Re-run to see\n : if this problem persists.")
Checks if memory was allocated properly.
Definition: ProSHADE_misc.hpp:68
ProSHADE_internal_maths::getEulerZXZFromSOFTPosition
void getEulerZXZFromSOFTPosition(proshade_signed band, proshade_signed x, proshade_signed y, proshade_signed z, proshade_double *eulerAlpha, proshade_double *eulerBeta, proshade_double *eulerGamma)
Function to find Euler angles (ZXZ convention) from index position in the inverse SOFT map.
Definition: ProSHADE_maths.cpp:963
ProSHADE_internal_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:3576
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::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::transpose3x3MatrixInPlace
void transpose3x3MatrixInPlace(proshade_double *mat)
Transposes 3x3 matrix in place.
Definition: ProSHADE_maths.cpp:1976
ProSHADE_internal_maths::completeLegendreSeries
void completeLegendreSeries(proshade_unsign order, proshade_double *abscissa, proshade_double *weights, proshade_unsign taylorSeriesCap)
This function completes the Legendre polynomial series assuming you have obtained the first values.
Definition: ProSHADE_maths.cpp:523
ProSHADE_internal_maths::findVectorFromTwoVAndTwoD
std::vector< proshade_double > findVectorFromTwoVAndTwoD(proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2, proshade_double dot1, proshade_double dot2)
Function for finding a vector which would have a given two dot products to two other vectors.
Definition: ProSHADE_maths.cpp:2309
ProSHADE_internal_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:2919
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:1696
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:3165
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:3446
ProSHADE_internal_maths::findAllPrimes
std::vector< proshade_unsign > findAllPrimes(proshade_unsign upTo)
This function finds all prime numbers up to the supplied limit.
Definition: ProSHADE_maths.cpp:3058
ProSHADE_internal_maths::compute3x3MatrixInverse
proshade_double * compute3x3MatrixInverse(proshade_double *mat)
Function for computing a 3x3 matrix inverse.
Definition: ProSHADE_maths.cpp:1943
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::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:2499
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:1868