ProSHADE  0.7.6.0 (JUL 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::complexMatrixSVDUandVOnly ( 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  std::complex<double> *rotMatU = new std::complex< double > [dim*dim]; // The U matrix space
877  std::complex<double> *rotMatV = new std::complex< double > [dim*dim]; // The V^T matrix space
878  std::complex<double> *work = new std::complex< double > [static_cast< proshade_unsign >( ( 3 * dim) + pow( dim, 2 ) * dim)]; // Workspace, minimum required is 3*dim, using more for performance
879  int workDim = static_cast< int > ( ( 3 * dim ) + pow( dim, 2 ) ); // 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  std::complex<double> *matrixToDecompose = new std::complex<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] = std::complex<double> ( mat[(rowIt*dim)+colIt], 0.0 );
898  }
899  }
900 
901  //================================================ Run LAPACK ZGESDD
902  zgesdd_ ( &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].real();
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].real();
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 * 4.0 * static_cast< proshade_double > ( band ) ) - M_PI ) / ( 2.0 * M_PI );
992 // *y = ( eulerAlpha * static_cast< proshade_double > ( band ) ) / ( M_PI );
993 // *z = ( eulerGamma * static_cast< proshade_double > ( band ) ) / ( M_PI );
994 
995  *x = ( eulerBeta * static_cast<proshade_double> ( band ) * 2.0 ) / M_PI;
996  *y = ( eulerGamma * static_cast<proshade_double> ( band ) ) / M_PI;
997  *z = ( eulerAlpha * static_cast<proshade_double> ( band ) ) / M_PI;
998 
999  //================================================ Done
1000  return ;
1001 
1002 }
1003 
1011 void ProSHADE_internal_maths::getRotationMatrixFromEulerZXZAngles ( proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double* matrix )
1012 {
1013  //================================================ No singularity/glimbal lock present
1014  if ( std::abs ( std::cos ( eulerBeta ) ) <= 0.98 )
1015  {
1016  //============================================ First row
1017  matrix[0] = cos ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) - sin ( eulerAlpha ) * sin ( eulerGamma );
1018  matrix[1] = sin ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) + cos ( eulerAlpha ) * sin ( eulerGamma );
1019  matrix[2] = -sin ( eulerBeta ) * cos ( eulerGamma );
1020 
1021  //============================================ Second row
1022  matrix[3] = -cos ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) - sin ( eulerAlpha ) * cos ( eulerGamma );
1023  matrix[4] = -sin ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) + cos ( eulerAlpha ) * cos ( eulerGamma );
1024  matrix[5] = sin ( eulerBeta ) * sin ( eulerGamma );
1025 
1026  //============================================ Third row
1027  matrix[6] = cos ( eulerAlpha ) * sin ( eulerBeta );
1028  matrix[7] = sin ( eulerAlpha ) * sin ( eulerBeta );
1029  matrix[8] = cos ( eulerBeta );
1030  }
1031  else
1032  {
1033  //============================================ Beta is either 0 or pi, making the alpha and gamma dimensions collapse into one (either only alpha+gamma or alpha-gamma are defined). In this case, we use conversion through quatermions.
1034  proshade_double qi = std::cos ( ( eulerAlpha - eulerGamma ) / 2.0 ) * std::sin ( eulerBeta / 2.0 );
1035  proshade_double qj = std::sin ( ( eulerAlpha - eulerGamma ) / 2.0 ) * std::sin ( eulerBeta / 2.0 );
1036  proshade_double qk = std::sin ( ( eulerAlpha + eulerGamma ) / 2.0 ) * std::cos ( eulerBeta / 2.0 );
1037  proshade_double qr = std::cos ( ( eulerAlpha + eulerGamma ) / 2.0 ) * std::cos ( eulerBeta / 2.0 );
1038 
1039  //============================================ First row
1040  matrix[0] = -1.0 + 2.0 * std::pow ( qi, 2.0 ) + 2.0 * std::pow ( qr, 2.0 );
1041  matrix[1] = 2.0 * ( qi * qj - qk * qr );
1042  matrix[2] = 2.0 * ( qi * qk + qj * qr );
1043 
1044  //============================================ Second row
1045  matrix[3] = 2.0 * ( qi * qj + qk * qr );
1046  matrix[4] = -1.0 + 2.0 * std::pow ( qj, 2.0 ) + 2.0 * std::pow ( qr, 2.0 );
1047  matrix[5] = 2.0 * ( qj * qk - qi * qr );
1048 
1049  //============================================ Third row
1050  matrix[6] = 2.0 * ( qi * qk - qj * qr );
1051  matrix[7] = 2.0 * ( qj * qk + qi * qr );
1052  matrix[8] = -1.0 + 2.0 * std::pow ( qk, 2.0 ) + 2.0 * std::pow ( qr, 2.0 );
1053  }
1054 
1055  //================================================ Done
1056  return ;
1057 
1058 }
1059 
1067 void ProSHADE_internal_maths::getRotationMatrixFromEulerZXZAngles ( proshade_single eulerAlpha, proshade_single eulerBeta, proshade_single eulerGamma, proshade_single* matrix )
1068 {
1069  //================================================ No singularity/glimbal lock present
1070  if ( std::abs ( std::cos ( eulerBeta ) ) <= 0.9999999f )
1071  {
1072  //============================================ First row
1073  matrix[0] = cos ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) - sin ( eulerAlpha ) * sin ( eulerGamma );
1074  matrix[1] = sin ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) + cos ( eulerAlpha ) * sin ( eulerGamma );
1075  matrix[2] = -sin ( eulerBeta ) * cos ( eulerGamma );
1076 
1077  //============================================ Second row
1078  matrix[3] = -cos ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) - sin ( eulerAlpha ) * cos ( eulerGamma );
1079  matrix[4] = -sin ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) + cos ( eulerAlpha ) * cos ( eulerGamma );
1080  matrix[5] = sin ( eulerBeta ) * sin ( eulerGamma );
1081 
1082  //============================================ Third row
1083  matrix[6] = cos ( eulerAlpha ) * sin ( eulerBeta );
1084  matrix[7] = sin ( eulerAlpha ) * sin ( eulerBeta );
1085  matrix[8] = cos ( eulerBeta );
1086  }
1087  else
1088  {
1089  //============================================ Beta is either 0 or pi, making the alpha and gamma dimensions collapse into one (either only alpha+gamma or alpha-gamma are defined). In this case, we use conversion through quatermions.
1090  proshade_single qi = std::cos ( ( eulerAlpha - eulerGamma ) / 2.0f ) * std::sin ( eulerBeta / 2.0f );
1091  proshade_single qj = std::sin ( ( eulerAlpha - eulerGamma ) / 2.0f ) * std::sin ( eulerBeta / 2.0f );
1092  proshade_single qk = std::sin ( ( eulerAlpha + eulerGamma ) / 2.0f ) * std::cos ( eulerBeta / 2.0f );
1093  proshade_single qr = std::cos ( ( eulerAlpha + eulerGamma ) / 2.0f ) * std::cos ( eulerBeta / 2.0f );
1094 
1095  //============================================ First row
1096  matrix[0] = -1.0f + 2.0f * std::pow ( qi, 2.0f ) + 2.0f * std::pow ( qr, 2.0f );
1097  matrix[1] = 2.0f * ( qi * qj - qk * qr );
1098  matrix[2] = 2.0f * ( qi * qk + qj * qr );
1099 
1100  //============================================ Second row
1101  matrix[3] = 2.0f * ( qi * qj + qk * qr );
1102  matrix[4] = -1.0f + 2.0f * std::pow ( qj, 2.0f ) + 2.0f * std::pow ( qr, 2.0f );
1103  matrix[5] = 2.0f * ( qj * qk - qi * qr );
1104 
1105  //============================================ Third row
1106  matrix[6] = 2.0f * ( qi * qk - qj * qr );
1107  matrix[7] = 2.0f * ( qj * qk + qi * qr );
1108  matrix[8] = -1.0f + 2.0f * std::pow ( qk, 2.0f ) + 2.0f * std::pow ( qr, 2.0f );
1109  }
1110 
1111  //================================================ Done
1112  return ;
1113 
1114 }
1115 
1128  void ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( proshade_double* rotMat, proshade_double* x, proshade_double* y, proshade_double* z, proshade_double* ang )
1129 {
1130  //================================================ Initialise
1131  proshade_double singAtPiCheck = 0.01;
1132  proshade_double singAtIdentity = 0.05;
1133 
1134  //================================================ Check input for singularities
1135  if ( ( std::abs ( rotMat[1] - rotMat[3] ) < singAtPiCheck ) &&
1136  ( std::abs ( rotMat[2] - rotMat[6] ) < singAtPiCheck ) &&
1137  ( std::abs ( rotMat[5] - rotMat[7] ) < singAtPiCheck ) )
1138  {
1139  //============================================ Singularity in input! Check for identity matrix
1140  if ( ( std::abs ( rotMat[1] + rotMat[3] ) < singAtIdentity ) &&
1141  ( std::abs ( rotMat[2] + rotMat[6] ) < singAtIdentity ) &&
1142  ( std::abs ( rotMat[5] + rotMat[7] ) < singAtIdentity ) &&
1143  ( std::abs ( rotMat[0] + rotMat[4] + rotMat[8] - 3.0 ) < singAtIdentity ) )
1144  {
1145  //======================================== Identity matrix. Return 0 angle.
1146  *x = 1.0;
1147  *y = 0.0;
1148  *z = 0.0;
1149  *ang = 0.0;
1150 
1151  //======================================== Done
1152  return ;
1153  }
1154 
1155  //============================================ If we got here, this is the 180deg (pi rad) singularity. Find which axis should the rotation be done along
1156  *ang = M_PI;
1157 
1158  proshade_double xx = ( rotMat[0] + 1.0 ) / 2.0;
1159  proshade_double yy = ( rotMat[4] + 1.0 ) / 2.0;
1160  proshade_double zz = ( rotMat[8] + 1.0 ) / 2.0;
1161  proshade_double xy = ( rotMat[1] + rotMat[3] ) / 4.0;
1162  proshade_double xz = ( rotMat[2] + rotMat[6] ) / 4.0;
1163  proshade_double yz = ( rotMat[5] + rotMat[7] ) / 4.0;
1164 
1165  if ( ( xx > yy ) && ( xx > zz ) ) // XX is the largest diagonal
1166  {
1167  if ( xx < singAtPiCheck ) // and is still 0
1168  {
1169  *x = 0.0;
1170  *y = 1.0 / sqrt(2);
1171  *z = 1.0 / sqrt(2);
1172  }
1173  else
1174  {
1175  *x = sqrt ( xx );
1176  *y = xy / sqrt ( xx );
1177  *z = xz / sqrt ( xx );
1178  }
1179  }
1180 
1181  else if ( yy > zz ) // YY is the largest diagonal
1182  {
1183  if ( yy < singAtPiCheck ) // and is still 0
1184  {
1185  *x = 1.0 / sqrt(2);
1186  *y = 0.0;
1187  *z = 1.0 / sqrt(2);
1188  }
1189  else
1190  {
1191  *y = sqrt ( yy );
1192  *x = xy / sqrt ( yy );
1193  *z = yz / sqrt ( yy );
1194  }
1195  }
1196 
1197  else // ZZ is the largest diagonal
1198  {
1199  if ( zz < singAtPiCheck ) // and is still 0
1200  {
1201  *x = 1.0 / sqrt(2);
1202  *y = 1.0 / sqrt(2);
1203  *z = 0.0;
1204  }
1205  else
1206  {
1207  *z = sqrt ( zz );
1208  *x = xz / sqrt ( zz );
1209  *y = yz / sqrt ( zz );
1210  }
1211  }
1212 
1213  //============================================ Make sure largest axis is positive and so is the angle
1214  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1215  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1216  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1217  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1218  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1219  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1220  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1221  {
1222  *x *= -1.0;
1223  *y *= -1.0;
1224  *z *= -1.0;
1225  *ang *= -1.0;
1226  }
1227  if ( *ang < 0.0 ) { *ang = ( 2.0 * M_PI ) + *ang; }
1228 
1229  //============================================ Done
1230  return ;
1231  }
1232 
1233  //================================================ No singularities! Now get angle
1234  *ang = std::acos ( ( std::max ( -1.0, std::min ( 3.0, rotMat[0] + rotMat[4] + rotMat[8] ) ) - 1.0 ) / 2.0 );
1235 
1236  //================================================ Init return values
1237  *x = 1.0;
1238  *y = 0.0;
1239  *z = 0.0;
1240 
1241  //================================================ Is angle 0? This should not happen, but will
1242  if ( std::abs ( *ang ) < singAtPiCheck )
1243  {
1244  *ang = 0.0;
1245  return ;
1246  }
1247 
1248  //================================================ Axis
1249  *x = rotMat[7] - rotMat[5];
1250  *y = rotMat[2] - rotMat[6];
1251  *z = rotMat[3] - rotMat[1];
1252 
1253  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1254  *x /= normFactor;
1255  *y /= normFactor;
1256  *z /= normFactor;
1257 
1258  //================================================ Make sure largest axis is positive and so is the angle
1259  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1260  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1261  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1262  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1263  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1264  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1265  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1266  {
1267  *x *= -1.0;
1268  *y *= -1.0;
1269  *z *= -1.0;
1270  *ang *= -1.0;
1271  }
1272  if ( *ang < 0.0 ) { *ang = ( 2.0 * M_PI ) + *ang; }
1273 
1274  //================================================ Done
1275  return ;
1276 
1277 }
1278 
1291  void ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( std::vector< proshade_double >* rotMat, proshade_double* x, proshade_double* y, proshade_double* z, proshade_double* ang )
1292 {
1293  //================================================ Initialise
1294  proshade_double singAtPiCheck = 0.01;
1295  proshade_double singAtIdentity = 0.05;
1296 
1297  //================================================ Check input for singularities
1298  if ( ( std::abs ( rotMat->at(1) - rotMat->at(3) ) < singAtPiCheck ) &&
1299  ( std::abs ( rotMat->at(2) - rotMat->at(6) ) < singAtPiCheck ) &&
1300  ( std::abs ( rotMat->at(5) - rotMat->at(7) ) < singAtPiCheck ) )
1301  {
1302  //============================================ Singularity in input! Check for identity matrix
1303  if ( ( std::abs ( rotMat->at(1) + rotMat->at(3) ) < singAtIdentity ) &&
1304  ( std::abs ( rotMat->at(2) + rotMat->at(6) ) < singAtIdentity ) &&
1305  ( std::abs ( rotMat->at(5) + rotMat->at(7) ) < singAtIdentity ) &&
1306  ( std::abs ( rotMat->at(0) + rotMat->at(4) + rotMat->at(8) - 3.0 ) < singAtIdentity ) )
1307  {
1308  //======================================== Identity matrix. Return 0 angle.
1309  *x = 1.0;
1310  *y = 0.0;
1311  *z = 0.0;
1312  *ang = 0.0;
1313 
1314  //======================================== Done
1315  return ;
1316  }
1317 
1318  //============================================ If we got here, this is the 180deg (pi rad) singularity. Find which axis should the rotation be done along
1319  *ang = M_PI;
1320 
1321  proshade_double xx = ( rotMat->at(0) + 1.0 ) / 2.0;
1322  proshade_double yy = ( rotMat->at(4) + 1.0 ) / 2.0;
1323  proshade_double zz = ( rotMat->at(8) + 1.0 ) / 2.0;
1324  proshade_double xy = ( rotMat->at(1) + rotMat->at(3) ) / 4.0;
1325  proshade_double xz = ( rotMat->at(2) + rotMat->at(6) ) / 4.0;
1326  proshade_double yz = ( rotMat->at(5) + rotMat->at(7) ) / 4.0;
1327 
1328  if ( ( xx > yy ) && ( xx > zz ) ) // XX is the largest diagonal
1329  {
1330  if ( xx < singAtPiCheck ) // and is still 0
1331  {
1332  *x = 0.0;
1333  *y = 1.0 / sqrt(2);
1334  *z = 1.0 / sqrt(2);
1335  }
1336  else
1337  {
1338  *x = sqrt ( xx );
1339  *y = xy / sqrt ( xx );
1340  *z = xz / sqrt ( xx );
1341  }
1342  }
1343 
1344  else if ( yy > zz ) // YY is the largest diagonal
1345  {
1346  if ( yy < singAtPiCheck ) // and is still 0
1347  {
1348  *x = 1.0 / sqrt(2);
1349  *y = 0.0;
1350  *z = 1.0 / sqrt(2);
1351  }
1352  else
1353  {
1354  *y = sqrt ( yy );
1355  *x = xy / sqrt ( yy );
1356  *z = yz / sqrt ( yy );
1357  }
1358  }
1359 
1360  else // ZZ is the largest diagonal
1361  {
1362  if ( zz < singAtPiCheck ) // and is still 0
1363  {
1364  *x = 1.0 / sqrt(2);
1365  *y = 1.0 / sqrt(2);
1366  *z = 0.0;
1367  }
1368  else
1369  {
1370  *z = sqrt ( zz );
1371  *x = xz / sqrt ( zz );
1372  *y = yz / sqrt ( zz );
1373  }
1374  }
1375 
1376  //============================================ Make sure largest axis is positive and so is the angle
1377  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1378  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1379  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1380  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1381  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1382  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1383  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1384  {
1385  *x *= -1.0;
1386  *y *= -1.0;
1387  *z *= -1.0;
1388  *ang *= -1.0;
1389  }
1390 
1391  //============================================ Done
1392  return ;
1393  }
1394 
1395  //================================================ No singularities! Now get angle
1396  *ang = std::acos ( ( std::max ( -1.0, std::min ( 3.0, rotMat->at(0) + rotMat->at(4) + rotMat->at(8) ) ) - 1.0 ) / 2.0 );
1397 
1398  //================================================ Init return values
1399  *x = 1.0;
1400  *y = 0.0;
1401  *z = 0.0;
1402 
1403  //================================================ Is angle 0? This should not happen, but will
1404  if ( std::abs ( *ang ) < singAtPiCheck )
1405  {
1406  *ang = 0.0;
1407  return ;
1408  }
1409 
1410  //================================================ Axis
1411  *x = rotMat->at(7) - rotMat->at(5);
1412  *y = rotMat->at(2) - rotMat->at(6);
1413  *z = rotMat->at(3) - rotMat->at(1);
1414 
1415  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1416  *x /= normFactor;
1417  *y /= normFactor;
1418  *z /= normFactor;
1419 
1420  //================================================ Make sure largest axis is positive and so is the angle
1421  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1422  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1423  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1424  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1425  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1426  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1427  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1428  {
1429  *x *= -1.0;
1430  *y *= -1.0;
1431  *z *= -1.0;
1432  *ang *= -1.0;
1433  }
1434 
1435  //================================================ Done
1436  return ;
1437 
1438 }
1439 
1448 void ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( proshade_double* rotMat, proshade_double x, proshade_double y, proshade_double z, proshade_double ang )
1449 {
1450  //================================================ If angle is 0 or infinity (anything divided by 0), return identity matrix
1451  if ( ( ang == 0.0 ) || ( std::isinf ( ang ) ) )
1452  {
1453  //============================================ Create identity
1454  for ( proshade_unsign i = 0; i < 9; i++ ) { rotMat[i] = 0.0; }
1455  rotMat[0] = 1.0;
1456  rotMat[4] = 1.0;
1457  rotMat[8] = 1.0;
1458 
1459  //============================================ Done
1460  return ;
1461  }
1462 
1463  //================================================ Compute the matrix
1464  proshade_double cAng = cos ( ang );
1465  proshade_double sAng = sin ( ang );
1466  proshade_double tAng = 1.0 - cAng;
1467 
1468  rotMat[0] = cAng + x * x * tAng;
1469  rotMat[4] = cAng + y * y * tAng;
1470  rotMat[8] = cAng + z * z * tAng;
1471 
1472  proshade_double tmp1 = x * y * tAng;
1473  proshade_double tmp2 = z * sAng;
1474  rotMat[3] = tmp1 + tmp2;
1475  rotMat[1] = tmp1 - tmp2;
1476 
1477  tmp1 = x * z * tAng;
1478  tmp2 = y * sAng;
1479  rotMat[6] = tmp1 - tmp2;
1480  rotMat[2] = tmp1 + tmp2;
1481 
1482  tmp1 = y * z * tAng;
1483  tmp2 = x * sAng;
1484  rotMat[7] = tmp1 + tmp2;
1485  rotMat[5] = tmp1 - tmp2;
1486 
1487  //================================================ Done
1488  return ;
1489 
1490 }
1491 
1500 void ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( proshade_single* rotMat, proshade_double x, proshade_double y, proshade_double z, proshade_double ang )
1501 {
1502  //================================================ If angle is 0 or infinity (anything divided by 0), return identity matrix
1503  if ( ( ang == 0.0 ) || ( std::isinf ( ang ) ) )
1504  {
1505  //============================================ Create identity
1506  for ( size_t i = 0; i < 9; i++ ) { rotMat[i] = 0.0f; }
1507  rotMat[0] = 1.0f;
1508  rotMat[4] = 1.0f;
1509  rotMat[8] = 1.0f;
1510 
1511  //============================================ Done
1512  return ;
1513  }
1514 
1515  //================================================ Compute the matrix
1516  proshade_single cAng = cos ( static_cast< proshade_single > ( ang ) );
1517  proshade_single sAng = sin ( static_cast< proshade_single > ( ang ) );
1518  proshade_single tAng = 1.0f - cAng;
1519 
1520  rotMat[0] = cAng + static_cast< proshade_single > ( x ) * static_cast< proshade_single > ( x ) * tAng;
1521  rotMat[4] = cAng + static_cast< proshade_single > ( y ) * static_cast< proshade_single > ( y ) * tAng;
1522  rotMat[8] = cAng + static_cast< proshade_single > ( z ) * static_cast< proshade_single > ( z ) * tAng;
1523 
1524  proshade_single tmp1 = static_cast< proshade_single > ( x ) * static_cast< proshade_single > ( y ) * tAng;
1525  proshade_single tmp2 = static_cast< proshade_single > ( z ) * sAng;
1526  rotMat[3] = tmp1 + tmp2;
1527  rotMat[1] = tmp1 - tmp2;
1528 
1529  tmp1 = static_cast< proshade_single > ( x ) * static_cast< proshade_single > ( z ) * tAng;
1530  tmp2 = static_cast< proshade_single > ( y ) * sAng;
1531  rotMat[6] = tmp1 - tmp2;
1532  rotMat[2] = tmp1 + tmp2;
1533 
1534  tmp1 = static_cast< proshade_single > ( y ) * static_cast< proshade_single > ( z ) * tAng;
1535  tmp2 = static_cast< proshade_single > ( x ) * sAng;
1536  rotMat[7] = tmp1 + tmp2;
1537  rotMat[5] = tmp1 - tmp2;
1538 
1539  //================================================ Done
1540  return ;
1541 
1542 }
1543 
1551 void ProSHADE_internal_maths::getEulerZXZFromRotMatrix ( proshade_double* rotMat, proshade_double* eA, proshade_double* eB, proshade_double* eG )
1552 {
1553  //================================================ Convert to Eulers
1554  if ( std::abs( rotMat[8] ) <= 0.99999 )
1555  {
1556  //============================================ This case occurs when there is no singularity in the rotation matrix (i.e. it does not have 0 or 180 degrees angle)
1557  *eA = std::atan2 ( rotMat[7], rotMat[6] );
1558  *eB = std::acos ( rotMat[8] );
1559  *eG = std::atan2 ( rotMat[5], -rotMat[2] );
1560  }
1561  else
1562  {
1563  //============================================ This case occurs when there is either 0 or 180 degrees rotation angle in the rotation matrix and therefore when beta is zero.
1564  if ( rotMat[8] >= 0.99999 )
1565  {
1566  //======================================== 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.
1567  *eA = std::atan2 ( rotMat[3], rotMat[0] );
1568  *eB = 0.0;
1569  *eG = 0.0;
1570  }
1571  if ( rotMat[8] <= -0.99999 )
1572  {
1573  //======================================== 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.
1574  *eA = std::atan2 ( rotMat[3], rotMat[0] );
1575  *eB = M_PI;
1576  *eG = 0.0;
1577  }
1578  }
1579 
1580  //================================================ Get the angles to proper range
1581  if ( *eA < 0.0 ) { *eA = 2.0 * M_PI + *eA; }
1582  if ( *eB < 0.0 ) { *eB = M_PI + *eB; }
1583  if ( *eG < 0.0 ) { *eG = 2.0 * M_PI + *eG; }
1584 
1585  //================================================ Done
1586  return ;
1587 
1588 }
1589 
1602 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 )
1603 {
1604  //================================================ If angle is 0 or infinity (anything divided by 0), return no rotation
1605  if ( ( axAng == 0.0 ) || ( std::isinf ( axAng ) ) )
1606  {
1607  //============================================ Return 0 ; 0 ; 0 for no angle
1608  *eA = 0.0;
1609  *eB = 0.0;
1610  *eG = 0.0;
1611 
1612  //============================================ Done
1613  return ;
1614  }
1615 
1616  //================================================ Compute required rotation matrix elements
1617  proshade_double cAng = std::cos ( axAng );
1618  proshade_double sAng = std::sin ( axAng );
1619  proshade_double tAng = 1.0 - cAng;
1620 
1621  proshade_double element22 = cAng + axZ * axZ * tAng;
1622 
1623  proshade_double tmp1 = axX * axZ * tAng;
1624  proshade_double tmp2 = axY * sAng;
1625  proshade_double element20 = tmp1 - tmp2;
1626  proshade_double element02 = tmp1 + tmp2;
1627 
1628  tmp1 = axY * axZ * tAng;
1629  tmp2 = axX * sAng;
1630  proshade_double element21 = tmp1 + tmp2;
1631  proshade_double element12 = tmp1 - tmp2;
1632 
1633  //================================================ Convert to Eulers
1634  if ( std::abs( element22 ) <= 0.99999 )
1635  {
1636  //============================================ This case occurs when there is no singularity in the rotation matrix (i.e. it does not have 0 or 180 degrees angle)
1637  *eA = std::atan2 ( element21, element20 );
1638  *eB = std::acos ( element22 );
1639  *eG = std::atan2 ( element12, -element02 );
1640  }
1641  else
1642  {
1643  //============================================ Compute some extra rotation matrix elements
1644  tmp1 = axX * axY * tAng;
1645  tmp2 = axZ * sAng;
1646  proshade_double element10 = tmp1 + tmp2;
1647  proshade_double element00 = cAng + axX * axX * tAng;
1648 
1649  //============================================ This case occurs when there is either 0 or 180 degrees rotation angle in the rotation matrix and therefore when beta is zero.
1650  if ( element22 >= 0.99999 )
1651  {
1652  //======================================== 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.
1653  *eA = std::atan2 ( element10, element00 );
1654  *eB = 0.0;
1655  *eG = 0.0;
1656  }
1657  if ( element22 <= -0.99999 )
1658  {
1659  //======================================== 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.
1660  *eA = std::atan2 ( element10, element00 );
1661  *eB = M_PI;
1662  *eG = 0.0;
1663  }
1664  }
1665 
1666  //================================================ Get the angles to proper range
1667  if ( *eA < 0.0 ) { *eA = 2.0 * M_PI + *eA; }
1668  if ( *eB < 0.0 ) { *eB = M_PI + *eB; }
1669  if ( *eG < 0.0 ) { *eG = 2.0 * M_PI + *eG; }
1670 
1671  //================================================ Done
1672  return ;
1673 
1674 }
1675 
1685 void ProSHADE_internal_maths::multiplyTwoSquareMatrices ( proshade_double* A, proshade_double* B, proshade_double* res, proshade_unsign dim )
1686 {
1687  //================================================ Set res to 0.0s
1688  for ( proshade_unsign iter = 0; iter < 9; iter++ ) { res[iter] = 0.0; }
1689 
1690  //================================================ Compute the matrix multiplication
1691  for ( proshade_unsign row = 0; row < dim; row++ )
1692  {
1693  for ( proshade_unsign col = 0; col < dim; col++ )
1694  {
1695  for ( proshade_unsign inner = 0; inner < dim; inner++ )
1696  {
1697  res[(row*dim)+col] += A[(inner*dim)+row] * B[(col*dim)+inner];
1698  }
1699  }
1700  }
1701 
1702  //================================================ Done
1703  return ;
1704 
1705 }
1706 
1711 std::vector < proshade_signed > ProSHADE_internal_maths::primeFactorsDecomp ( proshade_signed number )
1712 {
1713  //================================================ Initialise variables
1714  std::vector < proshade_signed > ret;
1715 
1716  //================================================ Deal with negative numbers
1717  bool changeSign = false;
1718  if ( number < 0 ) { changeSign = true; number = -number; }
1719 
1720  //================================================ Deal with zero and one
1721  if ( number == 0 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, 0 ); return ( ret ); }
1722  if ( number == 1 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, 1 ); return ( ret ); }
1723 
1724  //================================================ Divide by 2 as long as you can
1725  while ( number % 2 == 0 )
1726  {
1728  number = number / 2;
1729  }
1730 
1731  //================================================ Check all odd numbers up to the square root
1732  for ( proshade_double posDiv = 3; posDiv <= sqrt ( static_cast< proshade_double > ( number ) ); posDiv += 2.0 )
1733  {
1734  // If posDiv is a divisor of the number, save the result
1735  while ( number % static_cast< proshade_signed > ( posDiv ) == 0 )
1736  {
1737  ProSHADE_internal_misc::addToSignedVector ( &ret, static_cast< proshade_signed > ( posDiv ) );
1738  number = number / static_cast< proshade_signed > ( posDiv );
1739  }
1740  }
1741 
1742  //================================================ If the number was a large prime number, save it as it is
1743  if ( number > 2 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, number ); }
1744 
1745  //================================================ Finish dealing with negative numbers
1746  if ( changeSign ) { ret.at(0) = -ret.at(0); }
1747 
1748  //================================================ Done
1749  return ( ret );
1750 
1751 }
1752 
1760 proshade_double ProSHADE_internal_maths::normalDistributionValue ( proshade_double mean, proshade_double standardDev, proshade_double value )
1761 {
1762  //================================================ Compute and return
1763  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) ) );
1764 
1765 }
1766 
1777 proshade_double ProSHADE_internal_maths::computeDotProduct ( proshade_double* x1, proshade_double* y1, proshade_double* z1, proshade_double* x2, proshade_double* y2, proshade_double* z2 )
1778 {
1779  //================================================ Compute and return
1780  return ( (*x1 * *x2) + (*y1 * *y2) + (*z1 * *z2) );
1781 }
1782 
1793 proshade_double ProSHADE_internal_maths::computeDotProduct ( proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2 )
1794 {
1795  //================================================ Compute and return
1796  return ( (x1 * x2) + (y1 * y2) + (z1 * z2) );
1797 }
1798 
1809 proshade_double* ProSHADE_internal_maths::computeCrossProduct ( proshade_double* x1, proshade_double* y1, proshade_double* z1, proshade_double* x2, proshade_double* y2, proshade_double* z2 )
1810 {
1811  //================================================ Allocate memory
1812  proshade_double* crossProd = new proshade_double[3];
1813  ProSHADE_internal_misc::checkMemoryAllocation ( crossProd, __FILE__, __LINE__, __func__ );
1814 
1815  //================================================ Compute
1816  crossProd[0] = ( (*y1) * (*z2) ) - ( (*z1) * (*y2) );
1817  crossProd[1] = ( (*z1) * (*x2) ) - ( (*x1) * (*z2) );
1818  crossProd[2] = ( (*x1) * (*y2) ) - ( (*y1) * (*x2) );
1819 
1820  //================================================ Done
1821  return ( crossProd );
1822 
1823 }
1824 
1831 proshade_double* ProSHADE_internal_maths::compute3x3MatrixMultiplication ( proshade_double* mat1, proshade_double* mat2 )
1832 {
1833  //================================================ Allocate memory
1834  proshade_double* ret = new proshade_double[9];
1835  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1836 
1837  //================================================ Multiply
1838  ret[0] = ( mat1[0] * mat2[0] ) + ( mat1[1] * mat2[3] ) + ( mat1[2] * mat2[6] );
1839  ret[1] = ( mat1[0] * mat2[1] ) + ( mat1[1] * mat2[4] ) + ( mat1[2] * mat2[7] );
1840  ret[2] = ( mat1[0] * mat2[2] ) + ( mat1[1] * mat2[5] ) + ( mat1[2] * mat2[8] );
1841  ret[3] = ( mat1[3] * mat2[0] ) + ( mat1[4] * mat2[3] ) + ( mat1[5] * mat2[6] );
1842  ret[4] = ( mat1[3] * mat2[1] ) + ( mat1[4] * mat2[4] ) + ( mat1[5] * mat2[7] );
1843  ret[5] = ( mat1[3] * mat2[2] ) + ( mat1[4] * mat2[5] ) + ( mat1[5] * mat2[8] );
1844  ret[6] = ( mat1[6] * mat2[0] ) + ( mat1[7] * mat2[3] ) + ( mat1[8] * mat2[6] );
1845  ret[7] = ( mat1[6] * mat2[1] ) + ( mat1[7] * mat2[4] ) + ( mat1[8] * mat2[7] );
1846  ret[8] = ( mat1[6] * mat2[2] ) + ( mat1[7] * mat2[5] ) + ( mat1[8] * mat2[8] );
1847 
1848  //================================================ Done
1849  return ( ret );
1850 
1851 }
1852 
1861 proshade_double* ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( proshade_double* mat, proshade_double x, proshade_double y, proshade_double z )
1862 {
1863  //================================================ Allocate memory
1864  proshade_double* ret = new proshade_double[3];
1865  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1866 
1867  //================================================ Compute the multiplication
1868  ret[0] = ( x * mat[0] ) + ( y * mat[1] ) + ( z * mat[2] );
1869  ret[1] = ( x * mat[3] ) + ( y * mat[4] ) + ( z * mat[5] );
1870  ret[2] = ( x * mat[6] ) + ( y * mat[7] ) + ( z * mat[8] );
1871 
1872  //================================================ Done
1873  return ( ret );
1874 
1875 }
1876 
1885 proshade_single* ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( proshade_single* mat, proshade_single x, proshade_single y, proshade_single z )
1886 {
1887  //================================================ Allocate memory
1888  proshade_single* ret = new proshade_single[3];
1889  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1890 
1891  //================================================ Compute the multiplication
1892  ret[0] = ( x * mat[0] ) + ( y * mat[1] ) + ( z * mat[2] );
1893  ret[1] = ( x * mat[3] ) + ( y * mat[4] ) + ( z * mat[5] );
1894  ret[2] = ( x * mat[6] ) + ( y * mat[7] ) + ( z * mat[8] );
1895 
1896  //================================================ Done
1897  return ( ret );
1898 
1899 }
1900 
1906 proshade_double* ProSHADE_internal_maths::compute3x3MatrixInverse ( proshade_double* mat )
1907 {
1908  //================================================ Allocate memory
1909  proshade_double* inverse = new proshade_double[9];
1910  ProSHADE_internal_misc::checkMemoryAllocation ( inverse, __FILE__, __LINE__, __func__ );
1911 
1912  //================================================ Compute determinant
1913  proshade_double matDet = ( mat[0] * mat[4] * mat[8] ) +
1914  ( mat[1] * mat[5] * mat[6] ) +
1915  ( mat[2] * mat[3] * mat[7] ) -
1916  ( mat[0] * mat[5] * mat[7] ) -
1917  ( mat[1] * mat[3] * mat[8] ) -
1918  ( mat[2] * mat[4] * mat[6] );
1919 
1920  //================================================ Compute inverse matrix
1921  inverse[0] = ( mat[4] * mat[8] - mat[5] * mat[7] ) / matDet;
1922  inverse[1] = ( mat[2] * mat[7] - mat[1] * mat[8] ) / matDet;
1923  inverse[2] = ( mat[1] * mat[5] - mat[2] * mat[4] ) / matDet;
1924  inverse[3] = ( mat[5] * mat[6] - mat[3] * mat[8] ) / matDet;
1925  inverse[4] = ( mat[0] * mat[8] - mat[2] * mat[6] ) / matDet;
1926  inverse[5] = ( mat[2] * mat[3] - mat[0] * mat[5] ) / matDet;
1927  inverse[6] = ( mat[3] * mat[7] - mat[4] * mat[6] ) / matDet;
1928  inverse[7] = ( mat[1] * mat[6] - mat[0] * mat[7] ) / matDet;
1929  inverse[8] = ( mat[0] * mat[4] - mat[1] * mat[3] ) / matDet;
1930 
1931  //================================================ Done
1932  return ( inverse );
1933 }
1934 
1940 {
1941  //================================================ Initialise variables
1942  proshade_double tmp;
1943 
1944  //================================================ Transpose the non-diagonal values
1945  tmp = mat[1];
1946  mat[1] = mat[3];
1947  mat[3] = tmp;
1948 
1949  tmp = mat[2];
1950  mat[2] = mat[6];
1951  mat[6] = tmp;
1952 
1953  tmp = mat[5];
1954  mat[5] = mat[7];
1955  mat[7] = tmp;
1956 
1957  //================================================ Done
1958  return ;
1959 
1960 }
1961 
1979 proshade_double* ProSHADE_internal_maths::findRotMatMatchingVectors ( proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2 )
1980 {
1981  //================================================ Allocate required memory
1982  proshade_double* inPlaneRotation = new proshade_double[9];
1983  proshade_double* basisChangeMat = new proshade_double[9];
1984  ProSHADE_internal_misc::checkMemoryAllocation ( inPlaneRotation, __FILE__, __LINE__, __func__ );
1985  ProSHADE_internal_misc::checkMemoryAllocation ( basisChangeMat, __FILE__, __LINE__, __func__ );
1986 
1987  //================================================ Normalise inputs
1988  proshade_double normF = std::sqrt( std::pow( x1, 2.0 ) + std::pow ( y1, 2.0 ) + std::pow ( z1, 2.0 ) );
1989  x1 /= normF; y1 /= normF; z1 /= normF;
1990 
1991  normF = std::sqrt( std::pow( x2, 2.0 ) + std::pow ( y2, 2.0 ) + std::pow ( z2, 2.0 ) );
1992  x2 /= normF; y2 /= normF; z2 /= normF;
1993 
1994  //================================================ Compute cross product's magnitude
1995  proshade_double* crossProd = ProSHADE_internal_maths::computeCrossProduct( &x1, &y1, &z1, &x2, &y2, &z2 );
1996  proshade_double crossProdMag = std::sqrt( std::pow( crossProd[0], 2.0 ) + std::pow ( crossProd[1], 2.0 ) + std::pow ( crossProd[2], 2.0 ) );
1997  delete[] crossProd;
1998 
1999  //================================================ Compute dot product
2000  proshade_double dotProd = ProSHADE_internal_maths::computeDotProduct ( &x1, &y1, &z1, &x2, &y2, &z2 );
2001 
2002  //================================================ Construct the in-plane rotation matrix
2003  inPlaneRotation[0] = dotProd; inPlaneRotation[1] = -crossProdMag; inPlaneRotation[2] = 0.0;
2004  inPlaneRotation[3] = crossProdMag; inPlaneRotation[4] = dotProd; inPlaneRotation[5] = 0.0;
2005  inPlaneRotation[6] = 0.0; inPlaneRotation[7] = 0.0; inPlaneRotation[8] = 1.0;
2006 
2007  //================================================ Construct change of basis matrix
2008  crossProd = ProSHADE_internal_maths::computeCrossProduct( &x2, &y2, &z2, &x1, &y1, &z1 );
2009  normF = std::sqrt ( std::pow ( x2 - ( dotProd * x1 ), 2.0 ) + std::pow ( y2 - ( dotProd * y1 ), 2.0 ) + std::pow ( z2 - ( dotProd * z1 ), 2.0 ) );
2010 
2011  basisChangeMat[0] = x1; basisChangeMat[1] = ( x2 - ( dotProd * x1 ) ) / normF; basisChangeMat[2] = crossProd[0];
2012  basisChangeMat[3] = y1; basisChangeMat[4] = ( y2 - ( dotProd * y1 ) ) / normF; basisChangeMat[5] = crossProd[1];
2013  basisChangeMat[6] = z1; basisChangeMat[7] = ( z2 - ( dotProd * z1 ) ) / normF; basisChangeMat[8] = crossProd[2];
2014 
2015  //================================================ Invert the change of basis matrix
2016  proshade_double* basisChangeMatInverse = ProSHADE_internal_maths::compute3x3MatrixInverse ( basisChangeMat );
2017 
2018  //================================================ Multiply inverse of change of basis matrix with the in plane rotation matrix, then multiply the result with the inverse
2019  proshade_double* tmpMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( basisChangeMat, inPlaneRotation );
2020  proshade_double* rotMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( tmpMat, basisChangeMatInverse );
2021 
2022  //================================================ Release memory
2023  delete[] crossProd;
2024  delete[] inPlaneRotation;
2025  delete[] basisChangeMat;
2026  delete[] basisChangeMatInverse;
2027  delete[] tmpMat;
2028 
2029  //================================================ Done
2030  return ( rotMat );
2031 
2032 }
2033 
2055 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 )
2056 {
2057  //================================================ Initialise variables
2058  std::vector < proshade_double > ret;
2059 
2060  //================================================ Solution
2061  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 ) -
2062  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 ) ) *
2063  ( 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 ) ) ) -
2064  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 ) /
2065  ( 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 ) ) );
2066  proshade_double solY = ( ( dot2 * pow ( x2, 2.0 ) * pow ( z1, 3.0 ) ) /
2067  ( 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 ) -
2068  ( dot1 * pow ( x2, 2.0 ) * z2 * pow ( z1, 2.0 ) ) /
2069  ( 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 ) -
2070  ( 2.0 * x1 * dot2 * x2 * z2 * pow ( z1, 2.0 ) ) /
2071  ( 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 -
2072  ( 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 ) -
2073  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 ) *
2074  ( 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 ) /
2075  ( 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 ) ) +
2076  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) * z1 ) /
2077  ( 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 ) +
2078  ( x1 * dot1 * x2 * pow ( y2, 2.0 ) * z1 ) /
2079  ( 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 ) +
2080  ( pow ( x1, 2.0 ) * dot2 * pow ( z2, 2.0 ) * z1 ) /
2081  ( 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 ) +
2082  ( 2.0 * x1 * dot1 * x2 * pow ( z2, 2.0 ) * z1 ) /
2083  ( 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 ) -
2084  ( y1 * dot1 * pow ( x2, 2.0 ) * y2 * z1 ) /
2085  ( 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 ) -
2086  ( x1 * y1 * dot2 * x2 * y2 * z1 ) /
2087  ( 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 +
2088  ( 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 ) -
2089  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 ) *
2090  ( 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 ) ) ) /
2091  ( 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 ) ) -
2092  ( pow ( x1, 2.0 ) * dot1 * pow ( z2, 3.0 ) ) /
2093  ( 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 ) -
2094  ( pow ( x1, 2.0 ) * dot1 * pow ( y2, 2.0 ) * z2 ) /
2095  ( 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 ) -
2096  ( x1 * pow ( y1, 2.0 ) * dot2 * x2 * z2 ) /
2097  ( 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 ) +
2098  ( pow ( x1, 2.0 ) * y1 * dot2 * y2 * z2 ) /
2099  ( 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 ) +
2100  ( x1 * y1 * dot1 * x2 * y2 * z2 ) /
2101  ( 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 );
2102  proshade_double solZ = ( - ( dot2 * pow ( x2, 2.0 ) * y2 * pow ( z1, 3.0 ) ) /
2103  ( ( 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 ) ) -
2104  ( dot2 * pow ( x2, 2.0 ) * pow ( z1, 2.0 ) ) /
2105  ( 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 ) +
2106  ( dot1 * pow ( x2, 2.0 ) * y2 * z2 * pow ( z1, 2.0 ) ) /
2107  ( ( 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 ) ) +
2108  ( 2.0 * x1 * dot2 * x2 * y2 * z2 * pow ( z1, 2.0 ) ) /
2109  ( ( 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 ) ) +
2110  ( 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 ) -
2111  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 ) *
2112  ( 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 ) /
2113  ( 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 ) ) +
2114  ( dot2 * y2 * z1 ) / ( y1 * z2 - z1 * y2 ) +
2115  ( dot1 * pow ( x2, 2.0 ) * z2 * z1 ) /
2116  ( 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 ) +
2117  ( x1 * dot2 * x2 * z2 * z1 ) /
2118  ( 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 ) -
2119  ( x1 * dot1 * x2 * pow ( y2, 3.0 ) * z1 ) /
2120  ( ( 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 ) ) +
2121  ( y1 * dot1 * pow ( x2, 2.0 ) * pow ( y2, 2.0 ) * z1 ) /
2122  ( ( 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 ) ) +
2123  ( x1 * y1 * dot2 * x2 * pow ( y2, 2.0 ) * z1 ) /
2124  ( ( 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 ) ) -
2125  ( pow ( x1, 2.0 ) * dot2 * y2 * pow ( z2, 2.0 ) * z1 ) /
2126  ( ( 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 ) ) -
2127  ( 2.0 * x1 * dot1 * x2 * y2 * pow ( z2, 2.0 ) * z1 ) /
2128  ( ( 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 ) ) -
2129  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) * y2 * z1 ) /
2130  ( ( 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 +
2131  ( 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 ) -
2132  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 ) *
2133  ( 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 ) ) ) /
2134  ( 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 ) ) -
2135  ( 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 ) -
2136  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 ) *
2137  ( 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 ) ) ) /
2138  ( 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 ) ) -
2139  ( dot1 * y2 * z2 ) / ( y1 * z2 - z1 * y2 ) -
2140  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) ) /
2141  ( 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 ) -
2142  ( x1 * dot1 * x2 * pow ( y2, 2.0 ) ) /
2143  ( 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 ) -
2144  ( x1 * dot1 * x2 * pow ( z2, 2.0 ) ) /
2145  ( 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 ) +
2146  ( y1 * dot1 * pow ( x2, 2.0 ) * y2 ) /
2147  ( 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 ) +
2148  ( x1 * y1 * dot2 * x2 * y2 ) /
2149  ( 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 ) +
2150  ( pow ( x1, 2.0 ) * dot1 * y2 * pow ( z2, 3.0 ) ) /
2151  ( ( 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 ) ) +
2152  ( pow ( x1, 2.0 ) * dot1 * pow ( y2, 3.0 ) * z2 ) /
2153  ( ( 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 ) ) -
2154  ( pow ( x1, 2.0 ) * y1 * dot2 * pow ( y2, 2.0 ) * z2 ) /
2155  ( ( 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 ) ) -
2156  ( x1 * y1 * dot1 * x2 * pow ( y2, 2.0 ) * z2 ) /
2157  ( ( 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 ) ) +
2158  ( x1 * pow ( y1, 2.0 ) * dot2 * x2 * y2 * z2 ) /
2159  ( ( 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;
2160 
2161  //================================================ Set largest axis element to positive (ProSHADE standard)
2162  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) );
2163  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solX ) );
2164  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solY ) );
2165  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solZ ) );
2166  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( solX < 0.0 ) ) ||
2167  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( solY < 0.0 ) ) ||
2168  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( solZ < 0.0 ) ) ) { solX *= -1.0; solY *= -1.0; solZ *= -1.0; }
2169 
2170  //================================================ Save solutions
2174 
2175  //================================================ Done
2176  return ( ret );
2177 
2178 }
2179 
2201 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 )
2202 {
2203  //================================================ Initialise variables
2204  std::vector < proshade_double > ret;
2205 
2206  //================================================ Solution
2207  proshade_double solX = - ( y1 * dot2 * z3 - y1 * dot3 * z2 - z1 * dot2 * y3 + z1 * dot3 * y2 + dot1 * y3 * z2 - dot1 * z3 * y2 ) /
2208  ( -x1 * y3 * z2 + x1 * z3 * y2 + y1 * x3 * z2 - y1 * z3 * x2 - z1 * x3 * y2 + z1 * y3 * x2 );
2209  proshade_double solY = - ( x1 * dot2 * z3 - x1 * dot3 * z2 - z1 * dot2 * x3 + z1 * dot3 * x2 + dot1 * x3 * z2 - dot1 * z3 * x2 ) /
2210  ( x1 * y3 * z2 - x1 * z3 * y2 - y1 * x3 * z2 + y1 * z3 * x2 + z1 * x3 * y2 - z1 * y3 * x2 );
2211  proshade_double solZ = - ( x1 * dot2 * y3 - x1 * dot3 * y2 - y1 * dot2 * x3 + y1 * dot3 * x2 + dot1 * x3 * y2 - dot1 * y3 * x2 ) /
2212  ( -x1 * y3 * z2 + x1 * z3 * y2 + y1 * x3 * z2 - y1 * z3 * x2 - z1 * x3 * y2 + z1 * y3 * x2 );
2213 
2214  //================================================ Normalise the axis to magnitude 1
2215  proshade_double normFactor = sqrt ( pow ( solX, 2.0 ) + pow ( solY, 2.0 ) + pow ( solZ, 2.0 ) );
2216  solX /= normFactor;
2217  solY /= normFactor;
2218  solZ /= normFactor;
2219 
2220  //================================================ Set largest axis element to positive (ProSHADE standard)
2221  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) );
2222  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solX ) );
2223  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solY ) );
2224  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solZ ) );
2225  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( solX < 0.0 ) ) ||
2226  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( solY < 0.0 ) ) ||
2227  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( solZ < 0.0 ) ) ) { solX *= -1.0; solY *= -1.0; solZ *= -1.0; }
2228 
2229  //================================================ Save solutions
2233 
2234  //================================================ Done
2235  return ( ret );
2236 
2237 }
2238 
2245 std::vector< proshade_double > ProSHADE_internal_maths::multiplyGroupElementMatrices ( std::vector< proshade_double >* el1, std::vector< proshade_double >* el2 )
2246 {
2247  //================================================ Initialise variables
2248  std::vector< proshade_double > ret;
2249 
2250  //================================================ Compute
2251  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(0) ) +
2252  ( el1->at(1) * el2->at(3) ) +
2253  ( el1->at(2) * el2->at(6) ) );
2254  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(1) ) +
2255  ( el1->at(1) * el2->at(4) ) +
2256  ( el1->at(2) * el2->at(7) ) );
2257  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(2) ) +
2258  ( el1->at(1) * el2->at(5) ) +
2259  ( el1->at(2) * el2->at(8) ) );
2260 
2261  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(0) ) +
2262  ( el1->at(4) * el2->at(3) ) +
2263  ( el1->at(5) * el2->at(6) ) );
2264  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(1) ) +
2265  ( el1->at(4) * el2->at(4) ) +
2266  ( el1->at(5) * el2->at(7) ) );
2267  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(2) ) +
2268  ( el1->at(4) * el2->at(5) ) +
2269  ( el1->at(5) * el2->at(8) ) );
2270 
2271  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(0) ) +
2272  ( el1->at(7) * el2->at(3) ) +
2273  ( el1->at(8) * el2->at(6) ) );
2274  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(1) ) +
2275  ( el1->at(7) * el2->at(4) ) +
2276  ( el1->at(8) * el2->at(7) ) );
2277  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(2) ) +
2278  ( el1->at(7) * el2->at(5) ) +
2279  ( el1->at(8) * el2->at(8) ) );
2280 
2281 
2282  //================================================ Done
2283  return ( ret );
2284 
2285 }
2286 
2299 bool ProSHADE_internal_maths::rotationMatrixSimilarity ( std::vector< proshade_double >* mat1, std::vector< proshade_double >* mat2, proshade_double tolerance )
2300 {
2301  //================================================ Initialise variables
2302  bool ret = false;
2303 
2304  //================================================ Compute trace of mat1 * mat2^T
2305  proshade_double trace = ( mat1->at(0) * mat2->at(0) ) + ( mat1->at(1) * mat2->at(1) ) + ( mat1->at(2) * mat2->at(2) );
2306  trace += ( mat1->at(3) * mat2->at(3) ) + ( mat1->at(4) * mat2->at(4) ) + ( mat1->at(5) * mat2->at(5) );
2307  trace += ( mat1->at(6) * mat2->at(6) ) + ( mat1->at(7) * mat2->at(7) ) + ( mat1->at(8) * mat2->at(8) );
2308 
2309  //================================================ Subtract 3 (so that we would have 0 in case of idenity matrix)
2310  trace -= 3.0;
2311 
2312  //================================================ Compare to tolerance
2313  if ( tolerance > std::abs ( trace ) ) { ret = true; }
2314 
2315  //================================================ Done
2316  return ( ret );
2317 
2318 }
2319 
2336 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 )
2337 {
2338  //================================================ Initialise variables
2339  bool ret = false;
2340 
2341  //================================================ Cosine distance
2342  proshade_double cosDist = ( ( a1 * b1 ) + ( a2 * b2 ) + ( a3 * b3 ) ) /
2343  ( sqrt( pow( a1, 2.0 ) + pow( a2, 2.0 ) + pow( a3, 2.0 ) ) *
2344  sqrt( pow( b1, 2.0 ) + pow( b2, 2.0 ) + pow( b3, 2.0 ) ) );
2345 
2346  //================================================ Compare the absolute value of distance to 1.0 - tolerance
2347  if ( std::abs( cosDist ) > ( 1.0 - tolerance ) ) { ret = true; }
2348 
2349  //================================================ Done
2350  return ( ret );
2351 
2352 }
2353 
2370 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 )
2371 {
2372  //================================================ Initialise variables
2373  bool ret = false;
2374 
2375  //================================================ Cosine distance
2376  proshade_double cosDist = ( ( a1 * b1 ) + ( a2 * b2 ) + ( a3 * b3 ) ) /
2377  ( sqrt( pow( a1, 2.0 ) + pow( a2, 2.0 ) + pow( a3, 2.0 ) ) *
2378  sqrt( pow( b1, 2.0 ) + pow( b2, 2.0 ) + pow( b3, 2.0 ) ) );
2379 
2380  //================================================ Compare the absolute value of distance to 1.0 - tolerance
2381  if ( cosDist > ( 1.0 - tolerance ) ) { ret = true; }
2382 
2383  //================================================ Done
2384  return ( ret );
2385 
2386 }
2387 
2400 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 )
2401 {
2402  //================================================ Initialise variables
2403  proshade_double lonM, lonP, latM, latP, movSum;
2404  std::vector<proshade_double> latVals ( 3 );
2405  std::vector<proshade_double> lonVals ( 3 );
2406  proshade_double learningRate = 0.1;
2407  proshade_double prevVal = *bestSum;
2408  proshade_double valChange = 999.9;
2409  proshade_double origBestLat = std::round ( *bestLattitude );
2410  proshade_double origBestLon = std::round ( *bestLongitude );
2411  proshade_double tmpVal;
2412 
2413  //================================================ Initialise interpolators in all directions around the point of interest
2414  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsMinusMinus;
2415  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsMinusPlus;
2416  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsPlusMinus;
2417  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsPlusPlus;
2418  prepareBiCubicInterpolatorsMinusMinus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsMinusMinus, sphereMappedRotFun );
2419  prepareBiCubicInterpolatorsMinusPlus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsMinusPlus, sphereMappedRotFun );
2420  prepareBiCubicInterpolatorsPlusMinus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsPlusMinus, sphereMappedRotFun );
2421  prepareBiCubicInterpolatorsPlusPlus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsPlusPlus, sphereMappedRotFun );
2422 
2423  //================================================ Start the pseudo gradient ascent (while there is some change)
2424  while ( valChange > 0.0001 )
2425  {
2426  //============================================ Find the surrounding points to the currently best position
2427  lonM = *bestLongitude - step;
2428  lonP = *bestLongitude + step;
2429  latM = *bestLattitude - step;
2430  latP = *bestLattitude + step;
2431 
2432  //============================================ Deal with optimising outside of prepared range - recursion
2433  const FloatingPoint< proshade_double > lhs1 ( *bestLattitude ), rhs1 ( origBestLat - 1.0 );
2434  const FloatingPoint< proshade_double > lhs2 ( *bestLattitude ), rhs2 ( origBestLat + 1.0 );
2435  const FloatingPoint< proshade_double > lhs3 ( *bestLongitude ), rhs3 ( origBestLon - 1.0 );
2436  const FloatingPoint< proshade_double > lhs4 ( *bestLongitude ), rhs4 ( origBestLon + 1.0 );
2437  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; }
2438  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; }
2439  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; }
2440  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; }
2441 
2442  //============================================ Prepare vectors of tested positions
2443  latVals.at(0) = latM; latVals.at(1) = *bestLattitude; latVals.at(2) = latP;
2444  lonVals.at(0) = lonM; lonVals.at(1) = *bestLongitude; lonVals.at(2) = lonP;
2445 
2446  //============================================ Find the best change
2447  for ( proshade_unsign laIt = 0; laIt < static_cast<proshade_unsign> ( latVals.size() ); laIt++ )
2448  {
2449  for ( proshade_unsign loIt = 0; loIt < static_cast<proshade_unsign> ( lonVals.size() ); loIt++ )
2450  {
2451  //==================================== For this combination of lat and lon, find sum over spheres
2452  movSum = 1.0;
2453  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sphereList->size() ); iter++ )
2454  {
2455  //================================ Interpolate using correct interpolators
2456  if ( ( latVals.at(laIt) <= origBestLat ) && ( lonVals.at(loIt) <= origBestLon ) ) { movSum += interpolsMinusMinus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2457  if ( ( latVals.at(laIt) <= origBestLat ) && ( lonVals.at(loIt) > origBestLon ) ) { movSum += interpolsMinusPlus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2458  if ( ( latVals.at(laIt) > origBestLat ) && ( lonVals.at(loIt) <= origBestLon ) ) { movSum += interpolsPlusMinus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2459  if ( ( latVals.at(laIt) > origBestLat ) && ( lonVals.at(loIt) > origBestLon ) ) { movSum += interpolsPlusPlus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2460  }
2461 
2462  //==================================== If position has improved, save it
2463  if ( *bestSum < movSum )
2464  {
2465  *bestSum = movSum;
2466  *bestLongitude = lonVals.at(loIt);
2467  *bestLattitude = latVals.at(laIt);
2468  }
2469  }
2470  }
2471 
2472  //============================================ Prepare for next iteration
2473  valChange = std::floor ( 100000.0 * ( *bestSum - prevVal ) ) / 100000.0;
2474  prevVal = std::floor ( 100000.0 * ( *bestSum ) ) / 100000.0;
2475  step = std::max ( ( valChange / step ) * learningRate, 0.01 );
2476  if ( learningRate >= 0.02 ) { learningRate -= 0.01; }
2477 
2478  }
2479 
2480  //================================================ Release interpolators memory
2481  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsMinusMinus.size() ); intIt++ ) { delete interpolsMinusMinus.at(intIt); }
2482  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsMinusPlus.size() ); intIt++ ) { delete interpolsMinusPlus.at(intIt); }
2483  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsPlusMinus.size() ); intIt++ ) { delete interpolsPlusMinus.at(intIt); }
2484  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsPlusPlus.size() ); intIt++ ) { delete interpolsPlusPlus.at(intIt); }
2485 
2486  //================================================ Done
2487  return ;
2488 }
2489 
2501 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 )
2502 {
2503  //================================================ Initialise local variables
2504  proshade_signed latHlp, lonHlp;
2505  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2506 
2507  //================================================ Prepare the interpolator objects for interpolation around the position
2508  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2509  {
2510  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2511  proshade_double** interpGrid = new proshade_double*[4];
2512  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2513 
2514  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2515  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2516  {
2517  interpGrid[iter] = new proshade_double[4];
2518  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2519  }
2520 
2521  //============================================ Fill in the value grid on which the interpolation is to be done
2522  for ( proshade_signed latIt = 0; latIt < 4; latIt++ )
2523  {
2524  for ( proshade_signed lonIt = 0; lonIt < 4; lonIt++ )
2525  {
2526  latHlp = static_cast< proshade_signed > ( bestLattitude - 2.0 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2527  lonHlp = static_cast< proshade_signed > ( bestLongitude - 2.0 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2528  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2529  }
2530  }
2531 
2532  //============================================ Create the interpolators
2533  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude - 1.0, bestLongitude - 1.0 );
2534  interpols->emplace_back ( biCubInterp );
2535 
2536  //============================================ Release memory
2537  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2538  delete[] interpGrid;
2539  }
2540 
2541  //================================================ Done
2542  return ;
2543 }
2544 
2556 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 )
2557 {
2558  //================================================ Initialise local variables
2559  proshade_signed latHlp, lonHlp;
2560  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2561 
2562  //================================================ Prepare the interpolator objects for interpolation around the position
2563  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2564  {
2565  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2566  proshade_double** interpGrid = new proshade_double*[4];
2567  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2568 
2569  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2570  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2571  {
2572  interpGrid[iter] = new proshade_double[4];
2573  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2574  }
2575 
2576  //============================================ Fill in the value grid on which the interpolation is to be done
2577  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2578  {
2579  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2580  {
2581  latHlp = static_cast< proshade_signed > ( bestLattitude - 2 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2582  lonHlp = static_cast< proshade_signed > ( bestLongitude - 1 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2583  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ) , static_cast< proshade_unsign > ( lonHlp ) );
2584  }
2585  }
2586 
2587  //============================================ Create the interpolators
2588  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude - 1.0, bestLongitude );
2589  interpols->emplace_back ( biCubInterp );
2590 
2591  //============================================ Release memory
2592  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2593  delete[] interpGrid;
2594  }
2595 
2596  //================================================ Done
2597  return ;
2598 }
2599 
2611 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 )
2612 {
2613  //================================================ Initialise local variables
2614  proshade_signed latHlp, lonHlp;
2615  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2616 
2617  //================================================ Prepare the interpolator objects for interpolation around the position
2618  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2619  {
2620  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2621  proshade_double** interpGrid = new proshade_double*[4];
2622  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2623 
2624  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2625  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2626  {
2627  interpGrid[iter] = new proshade_double[4];
2628  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2629  }
2630 
2631  //============================================ Fill in the value grid on which the interpolation is to be done
2632  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2633  {
2634  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2635  {
2636  latHlp = static_cast< proshade_signed > ( bestLattitude - 1 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2637  lonHlp = static_cast< proshade_signed > ( bestLongitude - 2 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2638  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2639  }
2640  }
2641 
2642  //============================================ Create the interpolators
2643  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude, bestLongitude - 1.0 );
2644  interpols->emplace_back ( biCubInterp );
2645 
2646  //============================================ Release memory
2647  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2648  delete[] interpGrid;
2649  }
2650 
2651  //================================================ Done
2652  return ;
2653 }
2654 
2666 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 )
2667 {
2668  //================================================ Initialise local variables
2669  proshade_signed latHlp, lonHlp;
2670  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2671 
2672  //================================================ Prepare the interpolator objects for interpolation around the position
2673  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2674  {
2675  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2676  proshade_double** interpGrid = new proshade_double*[4];
2677  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2678 
2679  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2680  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2681  {
2682  interpGrid[iter] = new proshade_double[4];
2683  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2684  }
2685 
2686  //============================================ Fill in the value grid on which the interpolation is to be done
2687  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2688  {
2689  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2690  {
2691  latHlp = static_cast< proshade_signed > ( bestLattitude - 1 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2692  lonHlp = static_cast< proshade_signed > ( bestLongitude - 1 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2693  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2694  }
2695  }
2696 
2697  //============================================ Create the interpolators
2698  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude, bestLongitude );
2699  interpols->emplace_back ( biCubInterp );
2700 
2701  //============================================ Release memory
2702  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2703  delete[] interpGrid;
2704  }
2705 
2706  //================================================ Done
2707  return ;
2708 }
2709 
2721 bool ProSHADE_internal_maths::isAxisUnique ( std::vector< proshade_double* >* CSymList, proshade_double* axis, proshade_double tolerance, bool improve )
2722 {
2723  //================================================ Initialise variables
2724  bool ret = true;
2725  proshade_unsign whichImprove = 0;
2726 
2727  //================================================ For each already detected member
2728  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
2729  {
2730  //============================================ Is fold the same?
2731  const FloatingPoint< proshade_double > lhs ( CSymList->at(grIt)[0] ), rhs ( axis[0] );
2732  if ( lhs.AlmostEquals ( rhs ) )
2733  {
2734  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], axis[1], axis[2], axis[3], tolerance ) )
2735  {
2736  ret = false;
2737  whichImprove = grIt;
2738  break;
2739  }
2740  }
2741  }
2742 
2743  //================================================ Improve, if required
2744  if ( improve && !ret )
2745  {
2746  CSymList->at(whichImprove)[1] = axis[1];
2747  CSymList->at(whichImprove)[2] = axis[2];
2748  CSymList->at(whichImprove)[3] = axis[3];
2749  CSymList->at(whichImprove)[4] = axis[4];
2750  CSymList->at(whichImprove)[5] = axis[5];
2751  }
2752 
2753  //================================================ Done
2754  return ( ret );
2755 
2756 }
2757 
2770 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 )
2771 {
2772  //================================================ Initialise variables
2773  bool ret = true;
2774 
2775  //================================================ For each already detected member
2776  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
2777  {
2778  const FloatingPoint< proshade_double > lhs ( fold ), rhs ( CSymList->at(grIt)[0] );
2779  if ( lhs.AlmostEquals ( rhs ) )
2780  {
2781  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], X, Y, Z, tolerance ) )
2782  {
2783  ret = false;
2784  break;
2785  }
2786  }
2787  }
2788 
2789  //================================================ Done
2790  return ( ret );
2791 
2792 }
2793 
2802 std::vector< proshade_unsign > ProSHADE_internal_maths::findAllPrimes ( proshade_unsign upTo )
2803 {
2804  //================================================ Initialise variables
2805  std::vector< proshade_unsign > ret;
2806  std::vector< std::pair< proshade_unsign, bool > > sieveOfEratosthenesArray;
2807 
2808  //================================================ Sanity check
2809  if ( upTo < 2 ) { return ( ret ); }
2810 
2811  //================================================ Initialise the sieve array up to the required number
2812  for ( proshade_unsign iter = 2; iter <= upTo; iter++ ) { sieveOfEratosthenesArray.emplace_back ( std::pair< proshade_unsign, bool > ( iter, true ) ); }
2813 
2814  //================================================ For each entry in the array
2815  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); iter++ )
2816  {
2817  //============================================ If this entry is still true
2818  if ( sieveOfEratosthenesArray.at(iter).second )
2819  {
2820  //======================================== Set all entries with the position x * [this entry value] to false
2821  for ( proshade_unsign it = iter + sieveOfEratosthenesArray.at(iter).first; it < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); it += sieveOfEratosthenesArray.at(iter).first )
2822  {
2823  sieveOfEratosthenesArray.at(it).second = false;
2824  }
2825  }
2826  }
2827 
2828  //================================================ Copy passing results to return vector
2829  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); iter++ )
2830  {
2831  if ( sieveOfEratosthenesArray.at(iter).second ) { ProSHADE_internal_misc::addToUnsignVector ( &ret, sieveOfEratosthenesArray.at(iter).first ); }
2832  }
2833 
2834  //================================================ Done
2835  return ( ret );
2836 
2837 }
2838 
2847 proshade_double ProSHADE_internal_maths::computeGaussian ( proshade_double val, proshade_double sigma )
2848 {
2849  //================================================ Compute cumulative probability from Z-score
2850  proshade_double zScore = ( val / sigma );
2851  proshade_double cumulativeProbability = 0.5 * std::erfc ( zScore * M_SQRT1_2 );
2852 
2853  //================================================ Symmetrise
2854  if ( cumulativeProbability > 0.5 ) { cumulativeProbability = 1.0 - cumulativeProbability; }
2855 
2856  //================================================ Done
2857  return ( cumulativeProbability );
2858 
2859 }
2860 
2873 std::vector < proshade_double > ProSHADE_internal_maths::smoothen1D ( proshade_double step, proshade_signed windowSize, proshade_double sigma, std::vector< proshade_double > data )
2874 {
2875  //================================================ Initialise local variables
2876  proshade_signed windowHalf = ( windowSize - 1 ) / 2;
2877  proshade_signed totSize = static_cast< proshade_signed > ( ( 1.0 / step ) + 1 );
2878  std::vector< proshade_double > smoothened ( static_cast< size_t > ( totSize - ( windowSize - 1 ) ), 0.0 );
2879  std::vector< proshade_double > winWeights ( static_cast< size_t > ( windowSize ), 0.0 );
2880 
2881  //================================================ Prepare window weights
2882  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 ); }
2883 
2884  //================================================ Compute smoothened data
2885  for ( proshade_unsign it = 0; it < static_cast< proshade_unsign > ( smoothened.size() ); it++ )
2886  {
2887  //============================================ Compute window weighted average
2888  for ( proshade_signed winIt = 0; winIt < windowSize; winIt++ )
2889  {
2890  smoothened.at(it) += winWeights.at( static_cast< size_t > ( winIt ) ) * data.at( static_cast< size_t > ( static_cast< proshade_signed > ( it ) + winIt ) );
2891  }
2892  }
2893 
2894  //================================================ Done
2895  return ( smoothened );
2896 
2897 }
2898 
2909 proshade_single ProSHADE_internal_maths::getResolutionOfReflection ( proshade_single h, proshade_single k, proshade_single l, proshade_single xDim, proshade_single yDim, proshade_single zDim )
2910 {
2911  //================================================ Compute volume and proportions
2912  proshade_single vol = ( xDim * yDim * zDim );
2913  proshade_single sa = ( yDim * zDim ) / vol;
2914  proshade_single sb = ( xDim * zDim ) / vol;
2915  proshade_single sc = ( xDim * yDim ) / vol;
2916 
2917  //================================================ Compute distance
2918  proshade_single s2 = ( std::pow ( h * sa, 2.0f ) +
2919  std::pow ( k * sb, 2.0f ) +
2920  std::pow ( l * sc, 2.0f ) ) / 4.0f;
2921 
2922  //================================================ Deal with F000
2923  if ( s2 == 0.0f ) { s2 = 0.0000000001f; }
2924 
2925  //================================================ Done
2926  return ( 1.0f / ( 2.0f * std::sqrt ( s2 ) ) );
2927 
2928 }
2929 
2943 void ProSHADE_internal_maths::binReciprocalSpaceReflections ( proshade_unsign xInds, proshade_unsign yInds, proshade_unsign zInds, proshade_signed* noBin, proshade_signed*& binIndexing )
2944 {
2945  //================================================ Allocate output bin indexing memory and set to -100
2946  binIndexing = new proshade_signed [xInds * yInds * zInds];
2947  ProSHADE_internal_misc::checkMemoryAllocation ( binIndexing, __FILE__, __LINE__, __func__ );
2948  for ( size_t iter = 0; iter < static_cast< size_t > ( xInds * yInds * zInds ); iter++ ) { binIndexing[iter] = -100; }
2949  proshade_single xIndsF = static_cast< proshade_single > ( xInds ), yIndsF = static_cast< proshade_single > ( yInds ), zIndsF = static_cast< proshade_single > ( zInds );
2950 
2951  //================================================ Allocate local memory
2952  proshade_single *mins = new proshade_single[3];
2953  proshade_single *maxs = new proshade_single[3];
2954  proshade_single *resMins = new proshade_single[3];
2955  proshade_signed *resMinLoc = new proshade_signed[3];
2956  proshade_single *steps = new proshade_single[3];
2957 
2958  //================================================ Check local memory
2959  ProSHADE_internal_misc::checkMemoryAllocation ( mins, __FILE__, __LINE__, __func__ );
2960  ProSHADE_internal_misc::checkMemoryAllocation ( maxs, __FILE__, __LINE__, __func__ );
2961  ProSHADE_internal_misc::checkMemoryAllocation ( resMins, __FILE__, __LINE__, __func__ );
2962  ProSHADE_internal_misc::checkMemoryAllocation ( resMinLoc, __FILE__, __LINE__, __func__ );
2963  ProSHADE_internal_misc::checkMemoryAllocation ( steps, __FILE__, __LINE__, __func__ );
2964 
2965  //================================================ Initialise local variables
2966  proshade_single resol = 0.0f;
2967  proshade_signed reciX, reciY, reciZ, arrPos = 0, minLoc = -1;
2968  *noBin = 0;
2969 
2970  //================================================ Determine reciprocal space indexing
2971  mins[0] = std::floor ( xIndsF / -2.0f );
2972  mins[1] = std::floor ( yIndsF / -2.0f );
2973  mins[2] = std::floor ( zIndsF / -2.0f );
2974 
2975  maxs[0] = -mins[0];
2976  maxs[1] = -mins[1];
2977  maxs[2] = -mins[2];
2978 
2979  if ( xInds % 2 == 0 ) { mins[0] += 1.0f; }
2980  if ( yInds % 2 == 0 ) { mins[1] += 1.0f; }
2981  if ( zInds % 2 == 0 ) { mins[2] += 1.0f; }
2982 
2983  //================================================ Get minimum resolution based on dims for each dimension
2984  resMins[0] = ProSHADE_internal_maths::getResolutionOfReflection ( maxs[0], 0.0f, 0.0f, xIndsF, yIndsF, zIndsF );
2985  resMins[1] = ProSHADE_internal_maths::getResolutionOfReflection ( 0.0f, maxs[1], 0.0f, xIndsF, yIndsF, zIndsF );
2986  resMins[2] = ProSHADE_internal_maths::getResolutionOfReflection ( 0.0f, 0.0f, maxs[2], xIndsF, yIndsF, zIndsF );
2987 
2988  //================================================ Decide which dimension to work with (the one with the lowest resolution)
2989  resMinLoc[0] = 0; resMinLoc[1] = 0; resMinLoc[2] = 0;
2990  const FloatingPoint< proshade_single > lhs1 ( resMins[0] ), lhs2 ( resMins[1] ), lhs3 ( resMins[2] ), rhs1 ( std::min( resMins[0], std::min( resMins[1], resMins[2] ) ) );
2991  if ( lhs1.AlmostEquals ( rhs1 ) ) { resMinLoc[0] = 1; minLoc = 0; }
2992  if ( lhs2.AlmostEquals ( rhs1 ) ) { resMinLoc[1] = 1; minLoc = 1; }
2993  if ( lhs3.AlmostEquals ( rhs1 ) ) { resMinLoc[2] = 1; minLoc = 2; }
2994 
2995  //================================================ Find the bins and corresponding cut-offs
2996  std::vector< proshade_single > resArray ( static_cast< size_t > ( maxs[minLoc] - 1 ), 0.0f );
2997  std::vector< proshade_single > binArray ( static_cast< size_t > ( maxs[minLoc] - 1 ), 0.0f );
2998  for ( proshade_signed dimIt = 0; dimIt < static_cast< proshade_signed > ( maxs[minLoc] - 1 ); dimIt++ )
2999  {
3000  //============================================ Prepare steps
3001  steps[0] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[0] );
3002  steps[1] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[1] );
3003  steps[2] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[2] );
3004 
3005  //============================================ Find resolution
3006  resol = ProSHADE_internal_maths::getResolutionOfReflection ( steps[0], steps[1], steps[2], xIndsF, yIndsF, zIndsF );
3007 
3008  //============================================ Assign to arrays
3009  resArray.at( static_cast< size_t > ( dimIt ) ) = resol;
3010  binArray.at( static_cast< size_t > ( dimIt ) ) = static_cast< proshade_single > ( dimIt ) + 2.5f;
3011  *noBin = dimIt + 1;
3012  }
3013 
3014  //================================================ Assign reflections to bins
3015  for ( proshade_signed xIt = 0; xIt < static_cast< proshade_signed > ( xInds ); xIt++ )
3016  {
3017  for ( proshade_signed yIt = 0; yIt < static_cast< proshade_signed > ( yInds ); yIt++ )
3018  {
3019  for ( proshade_signed zIt = 0; zIt < static_cast< proshade_signed > ( zInds / 2 ) + 1; zIt++ )
3020  {
3021  //==================================== Deal with reciprocal indices ordering
3022  reciX = xIt; if ( reciX > static_cast< proshade_signed > ( maxs[0] ) ) { reciX -= static_cast< proshade_signed > ( xInds ); }
3023  reciY = yIt; if ( reciY > static_cast< proshade_signed > ( maxs[1] ) ) { reciY -= static_cast< proshade_signed > ( yInds ); }
3024  reciZ = zIt; if ( reciZ > static_cast< proshade_signed > ( maxs[2] ) ) { reciZ -= static_cast< proshade_signed > ( zInds ); }
3025 
3026  //==================================== For each bin, check if this reflection belongs to it
3027  for ( proshade_signed binIt = 0; binIt < (*noBin); binIt++ )
3028  {
3029  //================================ Check by comparing distances
3030  if ( std::sqrt ( std::pow ( static_cast< proshade_single > ( reciX ), 2.0f ) +
3031  std::pow ( static_cast< proshade_single > ( reciY ), 2.0f ) +
3032  std::pow ( static_cast< proshade_single > ( reciZ ), 2.0f ) ) <= binArray.at( static_cast< size_t > ( binIt ) ) )
3033  {
3034  //============================ This is the bin for this reflection. Assign it.
3035  arrPos = zIt + static_cast< proshade_signed > ( zInds ) * ( yIt + static_cast< proshade_signed > ( yInds ) * xIt );
3036  binIndexing[ static_cast< size_t > ( arrPos ) ] = binIt;
3037 
3038  //============================ If one of the uneven ends, do not use Friedel's Law
3039  if ( reciX == static_cast< proshade_signed > ( mins[0] ) || -reciX == static_cast< proshade_signed > ( mins[0] ) ) { break; }
3040  if ( reciY == static_cast< proshade_signed > ( mins[1] ) || -reciY == static_cast< proshade_signed > ( mins[1] ) ) { break; }
3041  if ( reciZ == static_cast< proshade_signed > ( mins[2] ) || -reciZ == static_cast< proshade_signed > ( mins[2] ) ) { break; }
3042 
3043  //============================ Use Friedel's Law to find the second index (this is why we can use zDim / 2)
3044  reciX *= -1; if ( reciX < 0 ) { reciX += static_cast< proshade_signed > ( xInds ); }
3045  reciY *= -1; if ( reciY < 0 ) { reciY += static_cast< proshade_signed > ( yInds ); }
3046  reciZ *= -1; if ( reciZ < 0 ) { reciZ += static_cast< proshade_signed > ( zInds ); }
3047 
3048  //============================ Apply Friedel's Law
3049  arrPos = reciZ + static_cast< proshade_signed > ( zInds ) * ( reciY + static_cast< proshade_signed > ( yInds ) * reciX );
3050  binIndexing[ static_cast< size_t > ( arrPos ) ] = binIt;
3051 
3052  //============================ Done, exit bins loop
3053  break;
3054  }
3055  }
3056  }
3057  }
3058  }
3059 
3060  //================================================ Release memory
3061  delete[] mins;
3062  delete[] maxs;
3063  delete[] resMins;
3064  delete[] resMinLoc;
3065  delete[] steps;
3066 
3067  //================================================ Done
3068  return ;
3069 
3070 }
3071 
3090 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 )
3091 {
3092  //================================================ Initialise local variables
3093  proshade_double realOrig, realRot, imagOrig, imagRot, fsc = 0.0;;
3094  proshade_signed indx, arrPos;
3095  std::vector< proshade_double > covarByBin ( static_cast< size_t > ( noBins ), 0.0 );
3096  std::vector< proshade_double > fscByBin ( static_cast< size_t > ( noBins ), 0.0 );
3097 
3098  //================================================ Compute bin sums
3099  for ( proshade_signed xIt = 0; xIt < static_cast< proshade_signed > ( xInds ); xIt++ )
3100  {
3101  for ( proshade_signed yIt = 0; yIt < static_cast< proshade_signed > ( yInds ); yIt++ )
3102  {
3103  for ( proshade_signed zIt = 0; zIt < static_cast< proshade_signed > ( zInds ); zIt++ )
3104  {
3105  //==================================== Find array position
3106  arrPos = zIt + static_cast< proshade_signed > ( zInds ) * ( yIt + static_cast< proshade_signed > ( yInds ) * xIt );
3107 
3108  //==================================== If no bin is associated, skip this reflection
3109  indx = binIndexing[ static_cast< size_t > ( arrPos ) ];
3110  if ( ( indx < 0 ) || ( indx > noBins ) ) { continue; }
3111 
3112  //==================================== Calculate the sums
3113  realOrig = fCoeffs1[arrPos][0];
3114  imagOrig = fCoeffs1[arrPos][1];
3115  realRot = fCoeffs2[arrPos][0];
3116  imagRot = fCoeffs2[arrPos][1];
3117 
3118  binData[indx][0] += realOrig;
3119  binData[indx][1] += imagOrig;
3120  binData[indx][2] += realRot;
3121  binData[indx][3] += imagRot;
3122  binData[indx][4] += realOrig * realRot;
3123  binData[indx][5] += imagOrig * imagRot;
3124  binData[indx][6] += std::pow ( realOrig, 2.0 );
3125  binData[indx][7] += std::pow ( imagOrig, 2.0 );
3126  binData[indx][8] += std::pow ( realRot, 2.0 );
3127  binData[indx][9] += std::pow ( imagRot, 2.0 );
3128 
3129  //==================================== Update bin counts
3130  binCounts[indx] += 1;
3131  }
3132  }
3133  }
3134 
3135  //================================================ Compute covariance by bin
3136  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3137  {
3138  covarByBin.at(binIt) = ( ( binData[binIt][4] + binData[binIt][5] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3139  ( ( binData[binIt][0] / static_cast< proshade_double > ( binCounts[binIt] ) *
3140  binData[binIt][2] / static_cast< proshade_double > ( binCounts[binIt] ) ) +
3141  ( binData[binIt][1] / static_cast< proshade_double > ( binCounts[binIt] ) *
3142  binData[binIt][3] / static_cast< proshade_double > ( binCounts[binIt] ) ) ) );
3143  }
3144 
3145  //================================================ Get FSC by bin
3146  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3147  {
3148  binData[binIt][10] = ( binData[binIt][6] + binData[binIt][7] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3149  ( std::pow ( binData[binIt][0] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) +
3150  std::pow ( binData[binIt][1] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) );
3151  binData[binIt][11] = ( binData[binIt][8] + binData[binIt][9] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3152  ( std::pow ( binData[binIt][2] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) +
3153  std::pow ( binData[binIt][3] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) );
3154  fscByBin.at(binIt) = covarByBin.at(binIt) / ( std::sqrt ( binData[binIt][10] ) * std::sqrt ( binData[binIt][11] ) );
3155  }
3156 
3157  //================================================ Get average FSC over all bins
3158  proshade_double binSizeSum = 0.0;
3159  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3160  {
3161  fsc += fscByBin.at(binIt) * static_cast< proshade_double > ( binCounts[binIt] );
3162  binSizeSum += static_cast< proshade_double > ( binCounts[binIt] );
3163  }
3164  fsc /= static_cast< proshade_double > ( binSizeSum );
3165 
3166  //================================================ Done
3167  return ( fsc );
3168 
3169 }
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:2201
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:2556
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:1809
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:1551
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:1760
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:2611
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::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:1011
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_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:1602
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:2400
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:2336
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:2501
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:2370
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:2847
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::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)
This function computes the FSC.
Definition: ProSHADE_maths.cpp:3090
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:1777
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::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:1448
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:2943
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:2873
ProSHADE_internal_maths::BicubicInterpolator
Definition: ProSHADE_maths.hpp:105
ProSHADE_internal_maths::primeFactorsDecomp
std::vector< proshade_signed > primeFactorsDecomp(proshade_signed number)
Function to find prime factors of an integer.
Definition: ProSHADE_maths.cpp:1711
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:2721
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::getAxisAngleFromRotationMatrix
void getAxisAngleFromRotationMatrix(proshade_double *rotMat, proshade_double *x, proshade_double *y, proshade_double *z, proshade_double *ang)
This function converts rotation matrix to the axis-angle representation.
Definition: ProSHADE_maths.cpp:1128
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:1979
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:1861
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:2299
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:67
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_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:1939
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:2055
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:2666
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:1685
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:2909
ProSHADE_internal_maths::findAllPrimes
std::vector< proshade_unsign > findAllPrimes(proshade_unsign upTo)
This function finds all prime numbers up to the supplied limit.
Definition: ProSHADE_maths.cpp:2802
ProSHADE_internal_maths::compute3x3MatrixInverse
proshade_double * compute3x3MatrixInverse(proshade_double *mat)
Function for computing a 3x3 matrix inverse.
Definition: ProSHADE_maths.cpp:1906
ProSHADE_internal_maths::complexMatrixSVDUandVOnly
void complexMatrixSVDUandVOnly(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::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:2245
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:1831