25 #ifndef WTENSORFUNCTIONS_H
26 #define WTENSORFUNCTIONS_H
35 #include <boost/array.hpp>
37 #include <Eigen/Dense>
39 #include "../WAssert.h"
40 #include "../WLimits.h"
41 #include "WCompileTimeFunctions.h"
43 #include "WTensorSym.h"
50 typedef boost::array< std::pair< double, WVector3d >, 3 > RealEigenSystem;
55 typedef boost::array< std::pair< std::complex< double >,
WVector3d >, 3 > EigenSystem;
57 std::ostream& operator<<( std::ostream& os,
const RealEigenSystem& sys );
64 inline void sortRealEigenSystem( RealEigenSystem* es )
66 if( ( *es )[0].first > ( *es )[2].first )
68 std::swap( ( *es )[0], ( *es )[2] );
70 if( ( *es )[0].first > ( *es )[1].first )
72 std::swap( ( *es )[0], ( *es )[1] );
74 if( ( *es )[1].first > ( *es )[2].first )
76 std::swap( ( *es )[1], ( *es )[2] );
89 template<
typename Data_T >
92 RealEigenSystem& result = *es;
95 ev( 0, 0 ) = ev( 1, 1 ) = ev( 2, 2 ) = 1.0;
106 for(
int i = 0; i < 2; ++i )
108 if( fabs( in( 2, i ) ) > fabs( in( p, q ) ) )
117 if( std::abs( in( 0, 1 ) ) + std::abs( in( 0, 2 ) ) + std::abs( in( 1, 2 ) ) < 1.0e-50 )
119 for(
int i = 0; i < 3; ++i )
121 result[i].first = in( i, i );
122 for(
int j = 0; j < 3; ++j )
124 result[i].second[j] =
static_cast< double >( ev( j, i ) );
127 sortRealEigenSystem( es );
131 Data_T r = in( q, q ) - in( p, p );
132 Data_T o = r / ( 2.0 * in( p, q ) );
135 Data_T signofo = ( o < 0.0 ? -1.0 : 1.0 );
138 t = signofo / ( 2.0 * fabs( o ) );
142 t = signofo / ( fabs( o ) + sqrt( o * o + 1.0 ) );
153 c = 1.0 / sqrt( t * t + 1.0 );
159 while( k == q || k == p )
164 Data_T u = ( 1.0 - c ) / s;
166 Data_T x = in( k, p );
167 Data_T y = in( k, q );
168 in( p, k ) = in( k, p ) = x - s * ( y + u * x );
169 in( q, k ) = in( k, q ) = y + s * ( x - u * y );
172 in( p, p ) = x - t * in( p, q );
173 in( q, q ) = y + t * in( p, q );
174 in( q, p ) = in( p, q ) = 0.0;
176 for(
int l = 0; l < 3; ++l )
178 evp[ l ] = ev( l, p );
179 evq[ l ] = ev( l, q );
181 for(
int l = 0; l < 3; ++l )
183 ev( l, p ) = c * evp[ l ] - s * evq[ l ];
184 ev( l, q ) = s * evp[ l ] + c * evq[ l ];
189 WAssert( iter >= 0,
"Jacobi eigenvector iteration did not converge." );
201 template<
typename Data_T >
204 RealEigenSystem& result = *es;
205 typedef Eigen::Matrix< Data_T, 3, 3 > MatrixType;
208 m << mat( 0, 0 ), mat( 0, 1 ), mat( 0, 2 ),
209 mat( 1, 0 ), mat( 1, 1 ), mat( 1, 2 ),
210 mat( 2, 0 ), mat( 2, 1 ), mat( 2, 2 );
212 Eigen::SelfAdjointEigenSolver< MatrixType > solv( m );
214 for( std::size_t k = 0; k < 3; ++k )
216 result[ k ].first = solv.eigenvalues()[ k ];
217 for( std::size_t j = 0; j < 3; ++j )
219 result[ k ].second[ j ] = solv.eigenvectors()( j, k );
244 template<
template< std::
size_t, std::
size_t,
typename >
class TensorType1,
245 template< std::
size_t, std::
size_t,
typename >
class TensorType2,
249 TensorType2< 2, dim, Data_T >
const& other )
254 for( std::size_t i = 0; i < dim; ++i )
256 for( std::size_t j = 0; j < dim; ++j )
259 for( std::size_t k = 0; k < dim; ++k )
261 res( i, j ) += one( i, k ) * other( k, j );
279 template<
typename Data_T >
285 return gradient[ 0 ] * gradient[ 0 ] * gradient[ 0 ] * gradient[ 0 ] * tens( 0, 0, 0, 0 )
286 + gradient[ 1 ] * gradient[ 1 ] * gradient[ 1 ] * gradient[ 1 ] * tens( 1, 1, 1, 1 )
287 + gradient[ 2 ] * gradient[ 2 ] * gradient[ 2 ] * gradient[ 2 ] * tens( 2, 2, 2, 2 )
288 +
static_cast< Data_T
>( 4 ) *
289 ( gradient[ 0 ] * gradient[ 0 ] * gradient[ 0 ] * gradient[ 1 ] * tens( 0, 0, 0, 1 )
290 + gradient[ 0 ] * gradient[ 0 ] * gradient[ 0 ] * gradient[ 2 ] * tens( 0, 0, 0, 2 )
291 + gradient[ 1 ] * gradient[ 1 ] * gradient[ 1 ] * gradient[ 0 ] * tens( 1, 1, 1, 0 )
292 + gradient[ 2 ] * gradient[ 2 ] * gradient[ 2 ] * gradient[ 0 ] * tens( 2, 2, 2, 0 )
293 + gradient[ 1 ] * gradient[ 1 ] * gradient[ 1 ] * gradient[ 2 ] * tens( 1, 1, 1, 2 )
294 + gradient[ 2 ] * gradient[ 2 ] * gradient[ 2 ] * gradient[ 1 ] * tens( 2, 2, 2, 1 ) )
295 +
static_cast< Data_T
>( 12 ) *
296 ( gradient[ 2 ] * gradient[ 1 ] * gradient[ 0 ] * gradient[ 0 ] * tens( 2, 1, 0, 0 )
297 + gradient[ 0 ] * gradient[ 2 ] * gradient[ 1 ] * gradient[ 1 ] * tens( 0, 2, 1, 1 )
298 + gradient[ 0 ] * gradient[ 1 ] * gradient[ 2 ] * gradient[ 2 ] * tens( 0, 1, 2, 2 ) )
299 +
static_cast< Data_T
>( 6 ) *
300 ( gradient[ 0 ] * gradient[ 0 ] * gradient[ 1 ] * gradient[ 1 ] * tens( 0, 0, 1, 1 )
301 + gradient[ 0 ] * gradient[ 0 ] * gradient[ 2 ] * gradient[ 2 ] * tens( 0, 0, 2, 2 )
302 + gradient[ 1 ] * gradient[ 1 ] * gradient[ 2 ] * gradient[ 2 ] * tens( 1, 1, 2, 2 ) );
315 template<
typename Data_T >
318 return gradient[ 0 ] * gradient[ 0 ] * tens( 0, 0 )
319 + gradient[ 1 ] * gradient[ 1 ] * tens( 1, 1 )
320 + gradient[ 2 ] * gradient[ 2 ] * tens( 2, 2 )
321 +
static_cast< Data_T
>( 2 ) *
322 ( gradient[ 0 ] * gradient[ 1 ] * tens( 0, 1 )
323 + gradient[ 0 ] * gradient[ 2 ] * tens( 0, 2 )
324 + gradient[ 1 ] * gradient[ 2 ] * tens( 1, 2 ) );
333 template<
typename T >
340 eigenEigenvector3D( tens, &sys );
343 if( sys[ 0 ].first <= 0.0 || sys[ 1 ].first <= 0.0 || sys[ 2 ].first <= 0.0 )
345 res( 0, 0 ) = res( 1, 1 ) = res( 2, 2 ) = 1.0;
351 res( 0, 0 ) = sys[ 0 ].second[ 0 ] * sys[ 0 ].second[ 0 ] * log( sys[ 0 ].first )
352 + sys[ 1 ].second[ 0 ] * sys[ 1 ].second[ 0 ] * log( sys[ 1 ].first )
353 + sys[ 2 ].second[ 0 ] * sys[ 2 ].second[ 0 ] * log( sys[ 2 ].first );
354 res( 0, 1 ) = sys[ 0 ].second[ 0 ] * sys[ 0 ].second[ 1 ] * log( sys[ 0 ].first )
355 + sys[ 1 ].second[ 0 ] * sys[ 1 ].second[ 1 ] * log( sys[ 1 ].first )
356 + sys[ 2 ].second[ 0 ] * sys[ 2 ].second[ 1 ] * log( sys[ 2 ].first );
357 res( 0, 2 ) = sys[ 0 ].second[ 0 ] * sys[ 0 ].second[ 2 ] * log( sys[ 0 ].first )
358 + sys[ 1 ].second[ 0 ] * sys[ 1 ].second[ 2 ] * log( sys[ 1 ].first )
359 + sys[ 2 ].second[ 0 ] * sys[ 2 ].second[ 2 ] * log( sys[ 2 ].first );
360 res( 1, 1 ) = sys[ 0 ].second[ 1 ] * sys[ 0 ].second[ 1 ] * log( sys[ 0 ].first )
361 + sys[ 1 ].second[ 1 ] * sys[ 1 ].second[ 1 ] * log( sys[ 1 ].first )
362 + sys[ 2 ].second[ 1 ] * sys[ 2 ].second[ 1 ] * log( sys[ 2 ].first );
363 res( 1, 2 ) = sys[ 0 ].second[ 1 ] * sys[ 0 ].second[ 2 ] * log( sys[ 0 ].first )
364 + sys[ 1 ].second[ 1 ] * sys[ 1 ].second[ 2 ] * log( sys[ 1 ].first )
365 + sys[ 2 ].second[ 1 ] * sys[ 2 ].second[ 2 ] * log( sys[ 2 ].first );
366 res( 2, 2 ) = sys[ 0 ].second[ 2 ] * sys[ 0 ].second[ 2 ] * log( sys[ 0 ].first )
367 + sys[ 1 ].second[ 2 ] * sys[ 1 ].second[ 2 ] * log( sys[ 1 ].first )
368 + sys[ 2 ].second[ 2 ] * sys[ 2 ].second[ 2 ] * log( sys[ 2 ].first );
378 template<
typename T >
385 eigenEigenvector3D( tens, &sys );
389 res( 0, 0 ) = sys[ 0 ].second[ 0 ] * sys[ 0 ].second[ 0 ] * exp( sys[ 0 ].first )
390 + sys[ 1 ].second[ 0 ] * sys[ 1 ].second[ 0 ] * exp( sys[ 1 ].first )
391 + sys[ 2 ].second[ 0 ] * sys[ 2 ].second[ 0 ] * exp( sys[ 2 ].first );
392 res( 0, 1 ) = sys[ 0 ].second[ 0 ] * sys[ 0 ].second[ 1 ] * exp( sys[ 0 ].first )
393 + sys[ 1 ].second[ 0 ] * sys[ 1 ].second[ 1 ] * exp( sys[ 1 ].first )
394 + sys[ 2 ].second[ 0 ] * sys[ 2 ].second[ 1 ] * exp( sys[ 2 ].first );
395 res( 0, 2 ) = sys[ 0 ].second[ 0 ] * sys[ 0 ].second[ 2 ] * exp( sys[ 0 ].first )
396 + sys[ 1 ].second[ 0 ] * sys[ 1 ].second[ 2 ] * exp( sys[ 1 ].first )
397 + sys[ 2 ].second[ 0 ] * sys[ 2 ].second[ 2 ] * exp( sys[ 2 ].first );
398 res( 1, 1 ) = sys[ 0 ].second[ 1 ] * sys[ 0 ].second[ 1 ] * exp( sys[ 0 ].first )
399 + sys[ 1 ].second[ 1 ] * sys[ 1 ].second[ 1 ] * exp( sys[ 1 ].first )
400 + sys[ 2 ].second[ 1 ] * sys[ 2 ].second[ 1 ] * exp( sys[ 2 ].first );
401 res( 1, 2 ) = sys[ 0 ].second[ 1 ] * sys[ 0 ].second[ 2 ] * exp( sys[ 0 ].first )
402 + sys[ 1 ].second[ 1 ] * sys[ 1 ].second[ 2 ] * exp( sys[ 1 ].first )
403 + sys[ 2 ].second[ 1 ] * sys[ 2 ].second[ 2 ] * exp( sys[ 2 ].first );
404 res( 2, 2 ) = sys[ 0 ].second[ 2 ] * sys[ 0 ].second[ 2 ] * exp( sys[ 0 ].first )
405 + sys[ 1 ].second[ 2 ] * sys[ 1 ].second[ 2 ] * exp( sys[ 1 ].first )
406 + sys[ 2 ].second[ 2 ] * sys[ 2 ].second[ 2 ] * exp( sys[ 2 ].first );
416 template< std::
size_t order,
typename Data_T >
418 double threshold,
double minAngularSeparationCosine,
double stepSize,
419 std::vector< WVector3d >
const& startingPoints,
420 std::vector< WVector3d >& maxima )
422 std::vector< double > values;
424 std::vector< WVector3d >::const_iterator it;
425 for( it = startingPoints.begin(); it != startingPoints.end(); ++it )
428 WVector3d gradient = approximateGradient( tensor, position );
431 for( iter = 0; iter < 100; ++iter )
433 WVector3d newPosition = normalize( position + stepSize * gradient );
434 WVector3d newGradient = approximateGradient( tensor, newPosition );
436 double cos = dot( newGradient, gradient );
441 else if( cos < 0.866 )
444 if( stepSize < 0.000001 )
451 gradient = newGradient;
452 position = newPosition;
461 std::vector< int > m;
462 m.reserve( maxima.size() );
464 for( std::size_t k = 0; k != maxima.size(); ++k )
467 if( dot( position, maxima[ k ] ) > minAngularSeparationCosine
468 || dot( maxima[ k ], -1.0 * position ) > minAngularSeparationCosine )
471 if( values[ k ] >= newFuncValue )
479 maxima.push_back( position );
480 values.push_back( newFuncValue );
482 for(
int k =
static_cast< int >( m.size() - 1 ); k > 0; --k )
484 maxima.erase( maxima.begin() + m[ k ] );
485 values.erase( values.begin() + m[ k ] );
493 for( std::size_t k = 0; k != maxima.size(); ++k )
495 if( values[ k ] > max )
502 while( k < maxima.size() )
504 if( values[ k ] < threshold * max )
506 maxima.erase( maxima.begin() + k );
507 values.erase( values.begin() + k );
516 template< std::
size_t order,
typename Data_T >
522 if( fabs( fabs( pos[ 2 ] ) - 1.0 ) < 0.001 )
530 eXY = normalize(
WVector3d( -pos[ 1 ], pos[ 0 ], 0.0 ) );
532 eZ = normalize(
WVector3d( eXY[ 1 ] * pos[ 2 ], -eXY[ 0 ] * pos[ 2 ], eXY[ 0 ] * pos[ 1 ] - eXY[ 1 ] * pos[ 0 ] ) );
543 double d = 1.0 - pos[ 2 ] * pos[ 2 ];
548 WVector3d res = eZ * dZ + eXY * ( dXY / std::sqrt( d ) );
549 return normalize( res );
Implements a symmetric tensor that has the same number of components in every direction.
Data_T evaluateSphericalFunction(WValue< Data_T > const &gradient) const
Evaluate - for a given gradient - the spherical function represented by this symmetric tensor.
Implements a tensor that has the same number of components in every direction.
const double MAX_DOUBLE
Maximum double value.
const double DBL_EPS
Smallest double such: 1.0 + DBL_EPS == 1.0 is still true.