OpenWalnut  1.5.0dev
WSphericalHarmonicsCoefficientsThread.h
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
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.
14 //
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.
19 //
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/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #ifndef WSPHERICALHARMONICSCOEFFICIENTSTHREAD_H
26 #define WSPHERICALHARMONICSCOEFFICIENTSTHREAD_H
27 
28 #include <cmath>
29 #include <fstream>
30 #include <iostream>
31 #include <map>
32 #include <memory>
33 #include <string>
34 #include <utility> // for std::pair
35 #include <vector>
36 
37 #include <boost/math/special_functions/spherical_harmonic.hpp>
38 #include <boost/thread/thread.hpp>
39 
40 #include "core/common/WAssert.h"
41 #include "core/common/WLimits.h"
42 #include "core/common/WProgress.h"
43 #include "core/common/WThreadedRunner.h"
44 #include "core/common/math/WMatrix.h"
45 #include "core/dataHandler/WDataSetRawHARDI.h"
46 #include "core/dataHandler/WDataSetSphericalHarmonics.h"
47 #include "core/dataHandler/WGridRegular3D.h"
48 
49 // forward declaration
50 template< typename T = void >
52 
53 /**
54  * A specialization for void.
55  */
56 template<>
58 {
59 public:
60  /**
61  * This structure is a collection of parameter and pointer to input and output data needed by each thread.
62  */
63  struct ThreadParameter
64  {
65  /**
66  * Constructor, we need to initialize a reference.
67  *
68  * \param flag A reference to a shutdown flag that we should listen to.
69  */
70  ThreadParameter( WBoolFlag const& flag ) // NOLINT no explicit
71  : m_CSADelta1( 0.01 ),
72  m_CSADelta2( 0.01 ),
73  m_shutdownFlag( flag )
74  {
75  }
76 
77  /**
78  * Pointer to the HARDI measurements
79  */
80  std::shared_ptr< WValueSetBase > m_valueSet;
81 
82  /**
83  * Indices of nonzero gradients
84  */
85  std::vector< size_t > m_validIndices;
86 
87  /**
88  * Indices of zero gradients (this should be normal T2 measurement)
89  */
90  std::vector< size_t > m_S0Indexes;
91 
92  /**
93  * Output data, the spherical harmonics coefficients
94  */
95  std::shared_ptr< std::vector<double> > m_data;
96 
97  /**
98  * The order of the calculated spherical harmonics
99  */
100  int m_order;
101 
102  /**
103  * Transformation-Matrix for conversion from HARDI measurements to spherical harmonics coefficients
104  * (see Descoteaux dissertation)
105  */
106  std::shared_ptr< WMatrix< double > > m_TransformMatrix;
107 
108  /**
109  * Gradients of all measurements (including )
110  */
111  std::vector< WVector3d > m_gradients;
112 
113  /**
114  * Pointer to progess indicator
115  */
116  std::shared_ptr< WProgress > m_progress;
117 
118  /**
119  * Indicate if the is error calculation is done.
120  */
122 
123  /**
124  * Indicate if the Funk-Radon-Transformation is done.
125  */
127 
128  /**
129  * Indicate if the residuals will be calculated.
130  * The residuals are the reprojection error. This means the
131  */
133 
134  /**
135  * The stored residuals.
136  */
137  std::shared_ptr< std::vector<double> > m_dataResiduals;
138 
139  /**
140  * The b-value used during the creation of the HARDI-data.
141  */
143 
144  /**
145  * Indicate if the normalisation from 0 to 1 is done.
146  */
148 
149  /**
150  * Indicate if the constant solid angle reconstruction is done.
151  */
152  bool m_csa;
153 
154  /**
155  * Delta1 value for the constant solid angle reconstruction.
156  */
157  double m_CSADelta1;
158 
159  /**
160  * Delta2 value for the constant solid angle reconstruction.
161  */
162  double m_CSADelta2;
163 
164  /**
165  * A shutdownFlag that may tell the thread to stop.
166  */
168  };
169 };
170 
171 /**
172  * Module for the creation of a spherical harmonic data set from raw HARDI data.
173  * \ingroup modules
174  */
175 template< typename T >
177 {
178 public:
179  /**
180  * The constructor.
181  * \param parameter collection of parameter and so on (description in more detail above)
182  * \param range the range (start and end) of input data this thread should use
183  */
185 
186  /**
187  * The main function of the thread. Here the calculation of the spherical harmonics coefficients is done.
188  */
189  void threadMain();
190 
191  /**
192  * Returns the average error of the thread.
193  *
194  * \return error measure
195  */
196  double getError() const;
197 
198 private:
199  double m_overallError; //!< accumulated error
200  unsigned int m_errorCount; //!< number of accumulated errors, necessary for average error calculation
201  WSphericalHarmonicsCoefficientsThread<>::ThreadParameter m_parameter; //!< collection of parameter and so on (description in more detail above)
202  std::pair< size_t, size_t > m_range; //!< the range (start and end) of input data this thread use
203 };
204 
205 template< typename T >
208  std::pair< size_t, size_t > range )
209  : m_parameter( parameter ),
210  m_range( range )
211 {
212 }
213 
214 template< typename T >
216 {
217  m_errorCount = 0;
218  m_overallError = 0.0;
219 
220  WMatrix<double> transformMatrix( *m_parameter.m_TransformMatrix );
221  size_t l = ( m_parameter.m_order + 1 ) * ( m_parameter.m_order + 2 ) / 2;
222 
223  for( size_t i = m_range.first; i < m_range.second; i++ )
224  {
225  if( m_parameter.m_shutdownFlag() )
226  {
227  break;
228  }
229 
230  // get measure vector
231  std::shared_ptr< WValueSet< T > > vs = std::dynamic_pointer_cast< WValueSet< T > >( m_parameter.m_valueSet );
232  if( !vs )
233  {
234  throw WException( "Valueset pointer not valid." );
235  }
236 
237  WValue< T > allMeasures( vs->getWValue( i ) );
238 
239  // extract measures for gradients != 0
240  WValue< double > measures( m_parameter.m_validIndices.size() );
241  unsigned int idx = 0;
242 
243  // find max S0 value
244  double S0avg = 0.0;
245  for( std::vector< size_t >::const_iterator it = m_parameter.m_S0Indexes.begin(); it != m_parameter.m_S0Indexes.end(); it++ )
246  {
247  S0avg += static_cast< double >( allMeasures[ *it ] );
248  }
249  S0avg /= m_parameter.m_S0Indexes.size();
250 
251  // to have a valid value for the average S0 signal
252  if( S0avg <= 0.01 )
253  {
254  S0avg = 0.01;
255  }
256 
257  // double minVal = 1e99;
258  // double maxVal = -1e99;
259  for( std::vector< size_t >::const_iterator it = m_parameter.m_validIndices.begin(); it != m_parameter.m_validIndices.end(); it++, idx++ )
260  {
261  if( m_parameter.m_csa )
262  {
263  double val = static_cast< double >( allMeasures[ *it ] ) / S0avg;
264  if( val < 0.0 )
265  {
266  val = m_parameter.m_CSADelta1 / 2.0;
267  }
268  else if( val < m_parameter.m_CSADelta1 )
269  {
270  val = m_parameter.m_CSADelta1 / 2.0 + val * val / ( 2.0 * m_parameter.m_CSADelta1 );
271  }
272  else if( val > 1.0 - m_parameter.m_CSADelta2 && val < 1.0 )
273  {
274  val = 1.0 - m_parameter.m_CSADelta2 / 2.0 - std::pow( 1.0 - val, 2 ) / ( 2.0 * m_parameter.m_CSADelta2 );
275  }
276  else if( val >= 1.0 )
277  {
278  val = 1.0 - m_parameter.m_CSADelta2 / 2.0;
279  }
280  measures[ idx ] = std::log( -std::log( val ) );
281  }
282  else
283  {
284  measures[ idx ] = static_cast< double >( allMeasures[ *it ] ) / S0avg;
285  }
286  }
287 
288  WValue< double > coefficients( *m_parameter.m_TransformMatrix * measures );
289 
290  if( m_parameter.m_doResidualCalculation || m_parameter.m_doErrorCalculation )
291  {
292  WSymmetricSphericalHarmonic< double > currentSphericalHarmonic( coefficients );
293  for( idx = 0; idx < m_parameter.m_validIndices.size(); idx++ )
294  {
295  double error = static_cast< double >( measures[ idx ] )
296  - currentSphericalHarmonic.getValue( WUnitSphereCoordinates< double >( m_parameter.m_gradients[ idx ] ) );
297 
298  if( m_parameter.m_doResidualCalculation )
299  {
300  m_parameter.m_dataResiduals->operator[]( m_parameter.m_validIndices.size() * i + idx ) = error;
301  }
302  if( m_parameter.m_doErrorCalculation )
303  {
304  m_overallError += fabs( error );
305  m_errorCount++;
306  }
307  }
308  }
309 
310  // show progress
311  ++( *( m_parameter.m_progress ) );
312 
313  // copy coefficients to output "data"
314 
315  // normalization
316  double scale = 1.0;
317  if( m_parameter.m_normalize )
318  {
319  scale *= std::sqrt( 4.0 * pi() ) / coefficients[ 0 ];
320  }
321 
322  if( m_parameter.m_csa )
323  {
324  coefficients[ 0 ] = 1.0 / ( 2.0 * std::sqrt( pi() ) );
325  }
326 
327  for( std::size_t j = 0; j < l; j++ )
328  {
329  m_parameter.m_data->operator[]( l * i + j ) = coefficients[ j ];
330  // wlog::debug( "WSphericalHarmonicsCoefficientsThread" ) << "coefficients[" << j << "]: " << coefficients[ j ];
331  }
332  }
333 }
334 
335 template< typename T >
337 {
338  if( m_errorCount == 0 ) return 0.0;
339  return m_overallError / static_cast< double >( m_errorCount );
340 }
341 
342 #endif // WSPHERICALHARMONICSCOEFFICIENTSTHREAD_H
Basic exception handler.
Definition: WException.h:39
Module for the creation of a spherical harmonic data set from raw HARDI data.
double getError() const
Returns the average error of the thread.
std::pair< size_t, size_t > m_range
the range (start and end) of input data this thread use
unsigned int m_errorCount
number of accumulated errors, necessary for average error calculation
WSphericalHarmonicsCoefficientsThread ::ThreadParameter m_parameter
collection of parameter and so on (description in more detail above)
WSphericalHarmonicsCoefficientsThread(WSphericalHarmonicsCoefficientsThread<>::ThreadParameter parameter, std::pair< size_t, size_t > range)
The constructor.
Class for symmetric spherical harmonics The index scheme of the coefficients/basis values is like in ...
T getValue(T theta, T phi) const
Return the value on the sphere.
Base class for all classes needing to be executed in a separate thread.
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
This class stores coordinates on the unit sphere.
Base class for all higher level values like tensors, vectors, matrices and so on.
Definition: WValue.h:41
std::vector< size_t > m_S0Indexes
Indices of zero gradients (this should be normal T2 measurement)
std::shared_ptr< WMatrix< double > > m_TransformMatrix
Transformation-Matrix for conversion from HARDI measurements to spherical harmonics coefficients (see...
WBoolFlag const & m_shutdownFlag
A shutdownFlag that may tell the thread to stop.
std::shared_ptr< WValueSetBase > m_valueSet
Pointer to the HARDI measurements.
std::vector< WVector3d > m_gradients
Gradients of all measurements (including )
ThreadParameter(WBoolFlag const &flag)
Constructor, we need to initialize a reference.
bool m_csa
Indicate if the constant solid angle reconstruction is done.
double m_CSADelta1
Delta1 value for the constant solid angle reconstruction.
bool m_doFunkRadonTransformation
Indicate if the Funk-Radon-Transformation is done.
std::shared_ptr< WProgress > m_progress
Pointer to progess indicator.
double m_bDiffusionWeightingFactor
The b-value used during the creation of the HARDI-data.
std::shared_ptr< std::vector< double > > m_data
Output data, the spherical harmonics coefficients.
std::shared_ptr< std::vector< double > > m_dataResiduals
The stored residuals.
double m_CSADelta2
Delta2 value for the constant solid angle reconstruction.