1
//---------------------------------------------------------------------------
3
// Project: OpenWalnut ( http://www.openwalnut.org )
5
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-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
//---------------------------------------------------------------------------
25
#ifndef WSPHERICALHARMONICSCOEFFICIENTSTHREAD_H
26
#define WSPHERICALHARMONICSCOEFFICIENTSTHREAD_H
33
#include <utility> // for std::pair
36
#include <boost/math/special_functions/spherical_harmonic.hpp>
37
#include <boost/thread/thread.hpp>
39
#include "core/common/WLimits.h"
40
#include "core/common/WAssert.h"
41
#include "core/common/WProgress.h"
42
#include "core/common/WThreadedRunner.h"
43
#include "core/common/math/WMatrix.h"
45
#include "core/dataHandler/WDataSetRawHARDI.h"
46
#include "core/dataHandler/WDataSetSphericalHarmonics.h"
47
#include "core/dataHandler/WGridRegular3D.h"
49
// forward declaration
50
template< typename T = void >
51
class WSphericalHarmonicsCoefficientsThread;
54
* A specialization for void.
57
class WSphericalHarmonicsCoefficientsThread< void >
61
* This structure is a collection of parameter and pointer to input and output data needed by each thread.
63
struct ThreadParameter
66
* Constructor, we need to initialize a reference.
68
* \param flag A reference to a shutdown flag that we should listen to.
70
ThreadParameter( WBoolFlag const& flag ) // NOLINT no explicit
71
: m_shutdownFlag( flag )
76
* Pointer to the HARDI measurements
78
boost::shared_ptr< WValueSetBase > m_valueSet;
81
* Indices of nonzero gradients
83
std::vector< size_t > m_validIndices;
86
* Indices of zero gradients (this should be normal T2 measurement)
88
std::vector< size_t > m_S0Indexes;
91
* Output data, the spherical harmonics coefficients
93
boost::shared_ptr< std::vector<double> > m_data;
96
* The order of the calculated spherical harmonics
101
* Transformation-Matrix for conversion from HARDI measurements to spherical harmonics coefficients
102
* (see Descoteaux dissertation)
104
boost::shared_ptr< WMatrix< double > > m_TransformMatrix;
107
* Gradients of all measurements (including )
109
std::vector< WVector3d > m_gradients;
112
* Pointer to progess indicator
114
boost::shared_ptr< WProgress > m_progress;
117
* Indicate if the is error calculation is done.
119
bool m_doErrorCalculation;
122
* Indicate if the Funk-Radon-Transformation is done.
124
bool m_doFunkRadonTransformation;
127
* Indicate if the residuals will be calculated.
128
* The residuals are the reprojection error. This means the
130
bool m_doResidualCalculation;
133
* The stored residuals.
135
boost::shared_ptr< std::vector<double> > m_dataResiduals;
138
* The b-value used during the creation of the HARDI-data.
140
double m_bDiffusionWeightingFactor;
143
* Indicate if the normalisation from 0 to 1 is done.
148
* Indicate if the constant solid angle reconstruction is done.
153
* A shutdownFlag that may tell the thread to stop.
155
WBoolFlag const& m_shutdownFlag;
160
* Module for the creation of a spherical harmonic data set from raw HARDI data.
163
template< typename T >
164
class WSphericalHarmonicsCoefficientsThread : public WThreadedRunner
169
* \param parameter collection of parameter and so on (description in more detail above)
170
* \param range the range (start and end) of input data this thread should use
172
WSphericalHarmonicsCoefficientsThread( WSphericalHarmonicsCoefficientsThread<>::ThreadParameter parameter, std::pair< size_t, size_t > range );
175
* The main function of the thread. Here the calculation of the spherical harmonics coefficients is done.
180
* Returns the average error of the thread.
182
* \return error measure
184
double getError() const;
187
double m_overallError; //!< accumulated error
188
unsigned int m_errorCount; //!< number of accumulated errors, necessary for average error calculation
189
WSphericalHarmonicsCoefficientsThread<>::ThreadParameter m_parameter; //!< collection of parameter and so on (description in more detail above)
190
std::pair< size_t, size_t > m_range; //!< the range (start and end) of input data this thread use
193
template< typename T >
194
WSphericalHarmonicsCoefficientsThread< T >::WSphericalHarmonicsCoefficientsThread(
195
WSphericalHarmonicsCoefficientsThread<>::ThreadParameter parameter,
196
std::pair< size_t, size_t > range )
197
: m_parameter( parameter ),
202
template< typename T >
203
void WSphericalHarmonicsCoefficientsThread< T >::threadMain()
206
m_overallError = 0.0;
208
WMatrix<double> transformMatrix( *m_parameter.m_TransformMatrix );
209
size_t l = ( m_parameter.m_order + 1 ) * ( m_parameter.m_order + 2 ) / 2;
211
for( size_t i = m_range.first; i < m_range.second; i++ )
213
if( m_parameter.m_shutdownFlag() )
218
// get measure vector
219
boost::shared_ptr< WValueSet< T > > vs = boost::shared_dynamic_cast< WValueSet< T > >( m_parameter.m_valueSet );
222
throw WException( "Valueset pointer not valid." );
225
WValue< T > allMeasures( vs->getWValue( i ) );
227
// extract measures for gradients != 0
228
WValue< double > measures( m_parameter.m_validIndices.size() );
229
unsigned int idx = 0;
233
for( std::vector< size_t >::const_iterator it = m_parameter.m_S0Indexes.begin(); it != m_parameter.m_S0Indexes.end(); it++ )
235
S0avg += static_cast< double >( allMeasures[ *it ] );
237
S0avg /= m_parameter.m_S0Indexes.size();
239
// to have a valid value for the average S0 signal
245
// double minVal = 1e99;
246
// double maxVal = -1e99;
247
double thresholdDelta1 = 0.01;
248
double thresholdDelta2 = 0.01;
249
for( std::vector< size_t >::const_iterator it = m_parameter.m_validIndices.begin(); it != m_parameter.m_validIndices.end(); it++, idx++ )
251
if( m_parameter.m_csa )
253
double val = static_cast< double >( allMeasures[ *it ] ) / S0avg;
256
val = thresholdDelta1 / 2.0;
258
else if( val < thresholdDelta1 )
260
val = thresholdDelta1 / 2.0 + val * val / ( 2.0 * thresholdDelta1 );
262
else if( val > 1.0 - thresholdDelta2 && val < 1.0 )
264
val = 1.0 - thresholdDelta2 / 2.0 - std::pow( 1.0 - val, 2 ) / ( 2.0 * thresholdDelta2 );
266
else if( val >= 1.0 )
268
val = 1.0 - thresholdDelta2 / 2.0;
270
measures[ idx ] = std::log( -std::log( val ) );
274
measures[ idx ] = static_cast< double >( allMeasures[ *it ] ) / S0avg;
278
WValue< double > coefficients( *m_parameter.m_TransformMatrix * measures );
280
if( m_parameter.m_doResidualCalculation || m_parameter.m_doErrorCalculation )
282
WSymmetricSphericalHarmonic currentSphericalHarmonic( coefficients );
283
for( idx = 0; idx < m_parameter.m_validIndices.size(); idx++ )
285
double error = static_cast< double >( measures[ idx ] )
286
- currentSphericalHarmonic.getValue( WUnitSphereCoordinates( m_parameter.m_gradients[ idx ] ) );
288
if( m_parameter.m_doResidualCalculation )
290
m_parameter.m_dataResiduals->operator[]( m_parameter.m_validIndices.size() * i + idx ) = error;
292
if( m_parameter.m_doErrorCalculation )
294
m_overallError += fabs( error );
301
++( *( m_parameter.m_progress ) );
303
// copy coefficients to output "data"
307
if( m_parameter.m_normalize )
309
scale *= std::sqrt( 4.0 * piDouble ) / coefficients[ 0 ];
312
if( m_parameter.m_csa )
314
coefficients[ 0 ] = 1.0 / ( 2.0 * std::sqrt( piDouble ) );
317
for( std::size_t j = 0; j < l; j++ )
319
m_parameter.m_data->operator[]( l * i + j ) = coefficients[ j ];
320
// wlog::debug( "WSphericalHarmonicsCoefficientsThread" ) << "coefficients[" << j << "]: " << coefficients[ j ];
325
template< typename T >
326
double WSphericalHarmonicsCoefficientsThread< T >::getError() const
328
if( m_errorCount == 0 ) return 0.0;
329
return m_overallError / static_cast< double >( m_errorCount );
332
#endif // WSPHERICALHARMONICSCOEFFICIENTSTHREAD_H