1
//---------------------------------------------------------------------------
3
// Project: OpenWalnut ( http://www.openwalnut.org )
5
// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
6
// For more information see http://www.openwalnut.org/copying
8
// This file is part of OpenWalnut.
10
// OpenWalnut is free software: you can redistribute it and/or modify
11
// it under the terms of the GNU Lesser General Public License as published by
12
// the Free Software Foundation, either version 3 of the License, or
13
// (at your option) any later version.
15
// OpenWalnut is distributed in the hope that it will be useful,
16
// but WITHOUT ANY WARRANTY; without even the implied warranty of
17
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
// GNU Lesser General Public License for more details.
20
// You should have received a copy of the GNU Lesser General Public License
21
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
23
//---------------------------------------------------------------------------
27
#include "core/dataHandler/WDataSetDTI.h"
28
#include "core/dataHandler/WDataSetVector.h"
29
#include "core/kernel/WKernel.h"
30
#include "core/kernel/WModuleInputData.h"
31
#include "core/kernel/WModuleOutputData.h"
32
#include "WMEigenSystem.xpm"
33
#include "WMEigenSystem.h"
35
// This line is needed by the module loader to actually find your module. Do not remove. Do NOT add a ";" here.
36
W_LOADABLE_MODULE( WMEigenSystem )
38
WMEigenSystem::WMEigenSystem():
43
WMEigenSystem::~WMEigenSystem()
48
boost::shared_ptr< WModule > WMEigenSystem::factory() const
50
// See "src/modules/template/" for an extensively documented example.
51
return boost::shared_ptr< WModule >( new WMEigenSystem() );
54
const char** WMEigenSystem::getXPMIcon() const
56
return WMEigenSystem_xpm;
58
const std::string WMEigenSystem::getName() const
60
return "Eigen System";
63
const std::string WMEigenSystem::getDescription() const
65
// Specify your module description here. Be detailed. This text is read by the user.
66
// See "src/modules/template/" for an extensively documented example.
67
return "Someone should add some documentation here. "
68
"Probably the best person would be the modules's creator, i.e. \"math\"";
71
void WMEigenSystem::connectors()
73
// Put the code for your connectors here. See "src/modules/template/" for an extensively documented example.
74
m_tensorIC = WModuleInputData< WDataSetDTI >::createAndAdd( shared_from_this(), "tensorInput", "The tensor field" );
76
m_evecOutputs.push_back( WModuleOutputData< WDataSetVector >::createAndAdd( shared_from_this(), "evec1Output", "The 1. eigenvector field" ) );
77
m_evecOutputs.push_back( WModuleOutputData< WDataSetVector >::createAndAdd( shared_from_this(), "evec2Output", "The 2. eigenvector field" ) );
78
m_evecOutputs.push_back( WModuleOutputData< WDataSetVector >::createAndAdd( shared_from_this(), "evec3Output", "The 3. eigenvector field" ) );
79
m_evecOutputs.push_back( WModuleOutputData< WDataSetVector >::createAndAdd( shared_from_this(), "evalsOutput", "All three eigenvalues" ) );
81
m_evalOutputs.push_back( WModuleOutputData< WDataSetScalar >::createAndAdd( shared_from_this(), "eval1Output", "The 1. eigenvalue field" ) );
82
m_evalOutputs.push_back( WModuleOutputData< WDataSetScalar >::createAndAdd( shared_from_this(), "eval2Output", "The 2. eigenvalue field" ) );
83
m_evalOutputs.push_back( WModuleOutputData< WDataSetScalar >::createAndAdd( shared_from_this(), "eval3Output", "The 3. eigenvalue field" ) );
85
WModule::connectors();
88
void WMEigenSystem::properties()
90
// for selecting the strategy
91
boost::shared_ptr< WItemSelection > strategies( new WItemSelection() );
92
strategies->addItem( "LibEigen", "Eigensystem is computed via libEigen and its SelfAdjointEigenSolver" );
93
strategies->addItem( "Jacobi", "Self implemented Jacobi iterative eigen decomposition" );
94
m_strategySelector = m_properties->addProperty( "Strategy", "How the eigen system should be computed",
95
strategies->getSelectorFirst() );
97
WPropertyHelper::PC_SELECTONLYONE::addTo( m_strategySelector );
98
WPropertyHelper::PC_NOTEMPTY::addTo( m_strategySelector );
100
WModule::properties();
103
void WMEigenSystem::requirements()
105
// Put the code for your requirements here. See "src/modules/template/" for an extensively documented example.
108
void WMEigenSystem::moduleMain()
110
m_moduleState.setResetable( true, true );
111
m_moduleState.add( m_tensorIC->getDataChangedCondition() );
112
m_moduleState.add( m_strategySelector->getCondition() );
116
while( !m_shutdownFlag() )
118
infoLog() << "Waiting.";
119
m_moduleState.wait();
121
if( m_shutdownFlag() )
126
boost::shared_ptr< WDataSetDTI > tensors = m_tensorIC->getData();
128
if( !m_eigenPool && tensors )
130
// start the eigenvector computation if input is DTI double or float otherwise continue
131
// when the computation finishes, we'll be notified by the threadspool's threadsDoneCondition
132
resetEigenFunction( tensors );
137
resetProgress( tensors->getValueSet()->size(), "Compute eigen system" );
139
infoLog() << "Computing eigen systems...";
141
else if( m_eigenPool && m_eigenPool->status() == W_THREADS_FINISHED )
143
// the computation of the eigenvectors has finished we have a new field of eigen systems
144
m_currentProgress->finish();
145
WAssert( m_eigenOperationFloat || m_eigenOperationDouble, "Bug: No result is available. Checked double and float!" );
147
if( tensors->getValueSet()->getDataType() == W_DT_DOUBLE )
149
updateOCs( m_eigenOperationDouble->getResult() );
153
updateOCs( m_eigenOperationFloat->getResult() );
157
infoLog() << "Computing eigen systems done.";
162
void WMEigenSystem::updateOCs( boost::shared_ptr< const WDataSetSingle > es )
164
WAssert( es, "Bug: updating the output with no data makes no sense." );
165
boost::shared_ptr< const WValueSet< double > > vs = boost::shared_dynamic_cast< WValueSet< double > >( es->getValueSet() );
166
WAssert( vs, "Bug: invalid value-set from WThreadedPerVoxelOperation dataset" );
167
boost::shared_ptr< WGrid > grid = es->getGrid();
169
typedef boost::shared_ptr< std::vector< double > > DataPointer;
170
std::vector< DataPointer > vecdata( 4, DataPointer( new std::vector< double >( vs->size() * 3 ) ) );
171
std::vector< DataPointer > valdata( 3, DataPointer( new std::vector< double >( vs->size() ) ) );
173
for( size_t i = 0; i < vs->size(); ++i )
175
WValue< double > sys = vs->getWValue( i );
177
( *vecdata[0] )[ i * 3 ] = sys[0];
178
( *valdata[0] )[ i ] = sys[0];
179
( *vecdata[0] )[ i * 3 + 1] = sys[4];
180
( *valdata[1] )[ i ] = sys[4];
181
( *vecdata[0] )[ i * 3 + 2] = sys[8];
182
( *valdata[2] )[ i ] = sys[8];
184
( *vecdata[1] )[ i * 3 ] = sys[1];
185
( *vecdata[1] )[ i * 3 + 1] = sys[2];
186
( *vecdata[1] )[ i * 3 + 2] = sys[3];
187
// second eigenvector
188
( *vecdata[2] )[ i * 3 ] = sys[5];
189
( *vecdata[2] )[ i * 3 + 1] = sys[6];
190
( *vecdata[2] )[ i * 3 + 2] = sys[7];
192
( *vecdata[3] )[ i * 3 ] = sys[9];
193
( *vecdata[3] )[ i * 3 + 1] = sys[10];
194
( *vecdata[3] )[ i * 3 + 2] = sys[11];
196
typedef boost::shared_ptr< WDataSetVector > PDSV;
197
typedef boost::shared_ptr< WDataSetScalar > PDSS;
198
typedef WValueSet< double > WVSDBL;
199
typedef boost::shared_ptr< WVSDBL > PWVSDBL;
201
m_evecOutputs[0]->updateData( PDSV( new WDataSetVector( PWVSDBL( new WVSDBL( 1, 3, vecdata[0], W_DT_DOUBLE ) ), grid ) ) );
202
m_evecOutputs[1]->updateData( PDSV( new WDataSetVector( PWVSDBL( new WVSDBL( 1, 3, vecdata[1], W_DT_DOUBLE ) ), grid ) ) );
203
m_evecOutputs[2]->updateData( PDSV( new WDataSetVector( PWVSDBL( new WVSDBL( 1, 3, vecdata[2], W_DT_DOUBLE ) ), grid ) ) );
204
m_evecOutputs[3]->updateData( PDSV( new WDataSetVector( PWVSDBL( new WVSDBL( 1, 3, vecdata[3], W_DT_DOUBLE ) ), grid ) ) );
205
m_evalOutputs[0]->updateData( PDSS( new WDataSetScalar( PWVSDBL( new WVSDBL( 0, 1, valdata[0], W_DT_DOUBLE ) ), grid ) ) );
206
m_evalOutputs[1]->updateData( PDSS( new WDataSetScalar( PWVSDBL( new WVSDBL( 0, 1, valdata[1], W_DT_DOUBLE ) ), grid ) ) );
207
m_evalOutputs[2]->updateData( PDSS( new WDataSetScalar( PWVSDBL( new WVSDBL( 0, 1, valdata[2], W_DT_DOUBLE ) ), grid ) ) );
210
boost::array< double, 12 > WMEigenSystem::computeEigenSystem( WTensorSym< 2, 3, double > const& m ) const
213
jacobiEigenvector3D( m, &sys );
214
boost::array< double, 12 > result = { { sys[0].first, sys[0].second[0],
217
sys[1].first, sys[1].second[0],
220
sys[2].first, sys[2].second[0],
222
sys[2].second[2] } }; // NOLINT
226
WMEigenSystem::TPVOFloat::OutTransmitType const WMEigenSystem::eigenFuncFloat( TPVOFloat::TransmitType const& input )
228
WTensorSym< 2, 3, double > m;
229
m( 0, 0 ) = static_cast< double >( input[ 0 ] );
230
m( 0, 1 ) = static_cast< double >( input[ 1 ] );
231
m( 0, 2 ) = static_cast< double >( input[ 2 ] );
232
m( 1, 1 ) = static_cast< double >( input[ 3 ] );
233
m( 1, 2 ) = static_cast< double >( input[ 4 ] );
234
m( 2, 2 ) = static_cast< double >( input[ 5 ] );
236
++*m_currentProgress;
238
return computeEigenSystem( m );
241
WMEigenSystem::TPVODouble::OutTransmitType const WMEigenSystem::eigenFuncDouble( TPVODouble::TransmitType const& input )
243
WTensorSym< 2, 3, double > m;
244
m( 0, 0 ) = static_cast< double >( input[ 0 ] );
245
m( 0, 1 ) = static_cast< double >( input[ 1 ] );
246
m( 0, 2 ) = static_cast< double >( input[ 2 ] );
247
m( 1, 1 ) = static_cast< double >( input[ 3 ] );
248
m( 1, 2 ) = static_cast< double >( input[ 4 ] );
249
m( 2, 2 ) = static_cast< double >( input[ 5 ] );
251
++*m_currentProgress;
253
return computeEigenSystem( m );
256
WMEigenSystem::TPVODouble::OutTransmitType const WMEigenSystem::eigenSolverDouble( TPVODouble::TransmitType const &input )
259
m << input[0], input[1], input[2],
260
input[1], input[3], input[4],
261
input[2], input[4], input[5];
263
return applyEigenSolver( m );
266
WMEigenSystem::TPVOFloat::OutTransmitType const WMEigenSystem::eigenSolverFloat( TPVOFloat::TransmitType const &input )
269
m << input[0], input[1], input[2],
270
input[1], input[3], input[4],
271
input[2], input[4], input[5];
273
return applyEigenSolver( m );
276
boost::array< double, 12 > WMEigenSystem::applyEigenSolver( const Eigen::Matrix3d &m ) const
278
Eigen::SelfAdjointEigenSolver< Eigen::Matrix3d > es( m );
279
const Eigen::Matrix3d &evecs = es.eigenvectors();
280
const Eigen::Vector3d &evals = es.eigenvalues();
281
boost::array< double, 12 > result = { { evals( 0 ), evecs( 0, 0 ),
284
evals( 1 ), evecs( 0, 1 ),
287
evals( 2 ), evecs( 0, 2 ),
289
evecs( 2, 2 ) } }; // NOLINT curly braces
293
void WMEigenSystem::resetProgress( std::size_t todo, std::string name )
295
if( m_currentProgress )
297
m_currentProgress->finish();
299
m_currentProgress = boost::shared_ptr< WProgress >( new WProgress( name, todo ) );
300
m_progress->addSubProgress( m_currentProgress );
303
void WMEigenSystem::resetEigenFunction( boost::shared_ptr< WDataSetDTI > tensors )
305
// check if we need to stop the currently running eigencomputation
308
debugLog() << "Stopping eigencomputation.";
309
WThreadedFunctionStatus s = m_eigenPool->status();
310
if( s != W_THREADS_FINISHED && s != W_THREADS_ABORTED )
314
s = m_eigenPool->status();
315
WAssert( s == W_THREADS_FINISHED || s == W_THREADS_ABORTED, "" );
317
m_moduleState.remove( m_eigenPool->getThreadsDoneCondition() );
319
// the threadpool should have finished computing by now
321
m_eigenOperationFloat = boost::shared_ptr< TPVOFloat >();
322
m_eigenOperationDouble = boost::shared_ptr< TPVODouble >();
325
if( tensors->getValueSet()->getDataType() == W_DT_DOUBLE )
327
if( m_strategySelector->get().at( 0 )->getName() == "LibEigen" )
329
m_eigenOperationDouble = boost::shared_ptr< TPVODouble >( new TPVODouble( tensors, boost::bind( &WMEigenSystem::eigenSolverDouble, this, _1 ) ) ); // NOLINT line length
331
else if( m_strategySelector->get().at( 0 )->getName() == "Jacobi" )
333
m_eigenOperationDouble = boost::shared_ptr< TPVODouble >( new TPVODouble( tensors, boost::bind( &WMEigenSystem::eigenFuncDouble, this, _1 ) ) ); // NOLINT line length
337
WAssert( 0, "Bug: Invalid strategy for eigen decomposition selected!" );
339
m_eigenPool = boost::shared_ptr< WThreadedFunctionBase >( new EigenFunctionTypeDouble( W_AUTOMATIC_NB_THREADS, m_eigenOperationDouble ) );
340
m_moduleState.add( m_eigenPool->getThreadsDoneCondition() );
342
else if( tensors->getValueSet()->getDataType() == W_DT_FLOAT )
344
if( m_strategySelector->get().at( 0 )->getName() == "LibEigen" )
346
m_eigenOperationFloat = boost::shared_ptr< TPVOFloat >( new TPVOFloat( tensors, boost::bind( &WMEigenSystem::eigenSolverFloat, this, _1 ) ) ); // NOLINT line length
348
else if( m_strategySelector->get().at( 0 )->getName() == "Jacobi" )
350
m_eigenOperationFloat = boost::shared_ptr< TPVOFloat >( new TPVOFloat( tensors, boost::bind( &WMEigenSystem::eigenFuncFloat, this, _1 ) ) ); // NOLINT line length
354
WAssert( 0, "Bug: Invalid strategy for eigen decomposition selected!" );
356
m_eigenPool = boost::shared_ptr< WThreadedFunctionBase >( new EigenFunctionTypeFloat( W_AUTOMATIC_NB_THREADS, m_eigenOperationFloat ) );
357
m_moduleState.add( m_eigenPool->getThreadsDoneCondition() );
361
errorLog() << "Input data does not contain floating point values, skipping.";