EddyInternalGpuUtils.h.prehip 17.7 KB
Newer Older
wangkx1's avatar
init  
wangkx1 committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
/////////////////////////////////////////////////////////////////////
///
/// \file EddyInternalGpuUtils.h
/// \brief Declarations of static class with collection of GPU routines used in the eddy project
///
/// \author Jesper Andersson
/// \version 1.0b, Nov., 2012.
/// \Copyright (C) 2012 University of Oxford 
///
/////////////////////////////////////////////////////////////////////

#ifndef EddyInternalGpuUtils_h
#define EddyInternalGpuUtils_h

#include <cstdlib>
#include <string>
#include <vector>
#include <cmath>
#include <memory>
#pragma push
#pragma diag_suppress = code_is_unreachable // Supress warnings from armawrap
#include "CudaVolume.h"
#pragma pop
#include "DiffusionGP.h"
#include "b0Predictor.h"
#include "ECScanClasses.h"
#include "EddyCommandLineOptions.h"

namespace EDDY {

class EddyGpuUtils;         // Forward declaration of friend
class DerivativeCalculator; // Forward declaration of friend

/////////////////////////////////////////////////////////////////////
///
/// \brief This class contains a set of static methods that implement
/// various utility functions for the eddy project implemented on 
/// CUDA GPU.
///
/////////////////////////////////////////////////////////////////////
class EddyInternalGpuUtils
{
private:
  friend class DerivativeCalculator;
  friend class EddyGpuUtils;
  friend class PostEddyCFImpl;

  static const int threads_per_block_make_deriv = 128;
  static const int threads_per_block_ec_field = 128;

  /// Loads predicition maker with scans unwarped according to current EC estimates
  static void load_prediction_maker(// Input
				    const EddyCommandLineOptions&        clo,
				    ScanType                             st,
				    const ECScanManager&                 sm,
				    unsigned int                         iter,
				    float                                fwhm,
		                    bool                                 use_orig,
				    // Output
				    std::shared_ptr<DWIPredictionMaker>  pmp,
				    NEWIMAGE::volume<float>&             mask);

  /*
  static void update_prediction_maker(// Input
				      const EddyCommandLineOptions&          clo,
				      ScanType                               st,
				      const ECScanManager&                   sm,
				      const ReplacementManager&              rm,
				      const NEWIMAGE::volume<float>&         mask,
				      // Input/Output
				      std::shared_ptr<DWIPredictionMaker>    pmp);
  */

  /// Motion corrects a scan from native (scanner) space to model space
  static void get_motion_corrected_scan(// Input
					const EDDY::ECScan&     scan,
					bool                    use_orig,
					// Output
					EDDY::CudaVolume&       oima,
					// Optional output
					EDDY::CudaVolume&       omask);

  /// Unwarps a scan from native (scanner) space to model space
  static void get_unwarped_scan(// Input
				const EDDY::ECScan&        scan,
				const EDDY::CudaVolume&    susc,
				const EDDY::CudaVolume&    bias,
				const EDDY::CudaVolume&    pred,
				bool                       jacmod,
				bool                       use_orig,
				// Output
				EDDY::CudaVolume&          oima,
				EDDY::CudaVolume&          omask);

  /// Unwarps a scan from native (scanner) space to model space. It uses a 
  /// volumetric model regardless of what the movement degrees of freedom
  /// is set to.
  static void get_volumetric_unwarped_scan(// Input
					   const EDDY::ECScan&        scan,
					   const EDDY::CudaVolume&    susc,
					   const EDDY::CudaVolume&    bias,
					   bool                       jacmod,
					   bool                       use_orig,
					   // Output
					   EDDY::CudaVolume&          oima,
					   EDDY::CudaVolume&          omask,
					   EDDY::CudaVolume4D&        deriv);

  static void detect_outliers(// Input
			      const EddyCommandLineOptions&             clo,
			      ScanType                                  st,
			      const std::shared_ptr<DWIPredictionMaker> pmp,
			      const NEWIMAGE::volume<float>&            mask,
			      const ECScanManager&                      sm,
			      // Input for debugging purposes only
			      unsigned int                              iter,
			      unsigned int                              level,
			      // Input/Output
			      ReplacementManager&                       rm,
			      DiffStatsVector&                          dsv);

  static void replace_outliers(// Input
			       const EddyCommandLineOptions&             clo,
			       ScanType                                  st,
			       const std::shared_ptr<DWIPredictionMaker> pmp,
			       const NEWIMAGE::volume<float>&            mask,
			       const ReplacementManager&                 rm,
			       bool                                      add_noise,
			       // Input/Output
			       ECScanManager&                            sm);

  /// Calculates the total field for transform scanner->model
  static void field_for_scan_to_model_transform(// Input
						const EDDY::ECScan&     scan,
						const EDDY::CudaVolume& susc,
						// Output
						EDDY::CudaVolume4D&     dfield,
						EDDY::CudaVolume&       omask,
						EDDY::CudaVolume&       jac);

  /// Calculates the total field for transform scanner->model, forcing volumetric field regardless of slice-to-vol
  static void field_for_scan_to_model_volumetric_transform(// Input
							   const EDDY::ECScan&            scan,
							   const EDDY::CudaVolume&        susc,
							   // Output
							   EDDY::CudaVolume4D&            dfield,
							   // Optional output
							   EDDY::CudaVolume&              omask,
							   EDDY::CudaVolume&              jac);

  /// Performs update of parameters given by whichp for one scan.
  static double param_update(// Input
			     const NEWIMAGE::volume<float>&                  pred,     // Prediction in model space
			     std::shared_ptr<const NEWIMAGE::volume<float> > susc,     // Susc-induced off-resonance field
			     std::shared_ptr<const NEWIMAGE::volume<float> > bias,     // Recieve bias field			  
   			     const NEWIMAGE::volume<float>&                  pmask, 
			     EDDY::ParametersType                            whichp,   // Which parameters to update    
			     float                                           fwhm,     // FWHM of smoothing
			     bool                                            very_verbose,
			     // These inputs are for debug purposes only
			     unsigned int                                    scindex,
			     unsigned int                                    iter,
			     unsigned int                                    level,
			     // Input/output
			     EDDY::ECScan&                                   scan,     // Scan we want to register to pred
			     // Optional output
			     NEWMAT::ColumnVector                            *rupdate);// Vector of updates


  /// The writing of debug info was lifted out of param_update to simplify the code
  static void write_debug_info_for_param_update(const EDDY::ECScan&               scan,							  
						unsigned int                      scindx,
						unsigned int                      iter,
						unsigned int                      level,
						float                             fwhm,
						const EDDY::DerivativeCalculator& dc,
						const EDDY::CudaVolume&           susc,
						const EDDY::CudaVolume&           bias,
						const EDDY::CudaVolume&           pred,
						const EDDY::CudaVolume&           dima,
						const EDDY::CudaVolume&           pmask,
						const NEWMAT::Matrix&             XtX,
						const NEWMAT::ColumnVector&       Xty,
						const NEWMAT::ColumnVector&       update);

  /// Performs update of long time-constant EC parameters for all scans
  static std::vector<double> long_ec_update(// Input
					    const std::vector<NEWIMAGE::volume<float> >&      pred,         // Predictions in model space
					    const NEWIMAGE::volume<float>&                    pmask,        // "Data valid" mask in model space
					    float                                             fwhm,         // FWHM for Gaussian smoothing
					    bool                                              very_verbose, // Write detailed output to screen?
					    // These input parameters are for debugging only
					    unsigned int                                      iter,         // Iteration
					    unsigned int                                      level,        // Determines how much gets written
					    const std::vector<unsigned int>&                  debug_index,  // Indicies of scans to write debug info for
					    // Input/output
					    EDDY::ECScanManager&                              sm);          // Scans we want to register to predictions

  /// Caclulate new mss for single volume to check if update improved it.
  static double calculate_new_mss(// Input
				  const EDDY::CudaVolume&      pred_gpu,     // Predictions in model space
				  const EDDY::CudaVolume&      pmask_gpu,    // "Data valid" mask in model space
				  const EDDY::CudaVolume&      susc_gpu,     // Susc map already on GPU.
				  float                        fwhm,
				  const EDDY::ECScan&          scan);

  /// Caclulate new mss for all volumes to check if update improved it.
  static double calculate_new_mss(// Input
				  const std::vector<NEWIMAGE::volume<float> >& pred,         // Predictions in model space
				  const EDDY::CudaVolume&                      pmask_gpu,    // "Data valid" mask in model space
				  float                                        fwhm,
				  const EDDY::ECScanManager&                   sm);

  /// Writes debug info pertaining to updating of long EC parameters.
  /// The writing is divided into this and the two following routines for practical reasons.
  static void write_debug_info_long_ec_step_one(const EDDY::ECScan&               scan,
						unsigned int                      scindx,
						const std::vector<unsigned int>&  debug_indx,
						unsigned int                      iter,
						unsigned int                      level,
						const EDDY::DerivativeCalculator& dc,
						const EDDY::CudaVolume&           pred,
						const EDDY::CudaVolume&           dima,
						const EDDY::CudaVolume&           pmask,
						const arma::mat&                  XtX,
						const arma::colvec&               Xty);

  static void write_debug_info_long_ec_updates(unsigned int                     iter,
					       const EDDY::LongECModel&         lecm,
					       const std::vector<arma::colvec>& updates);

  static void write_debug_info_long_ec_cbs_step(const EDDY::ECScan&               scan,
						unsigned int                      scindx,
						const std::vector<unsigned int>&  debug_indx,
						unsigned int                      iter,
						unsigned int                      level,
						const EDDY::CudaVolume&           dima,
						const EDDY::CudaVolume&           mask,
						const EDDY::CudaVolume&           pios,
						const EDDY::CudaVolume&           jac);

  /// Transforms a volume in model space to scan/observation space, leaving the result on the gpu
  static void transform_model_to_scan_space(// Input
					    const EDDY::CudaVolume&     pred,
					    const EDDY::ECScan&         scan,
					    const EDDY::CudaVolume&     susc,
					    bool                        jacmod,
					    // Output
					    EDDY::CudaVolume&           oima,
					    EDDY::CudaVolume&           omask,
					    // Optional output
					    EDDY::CudaVolume&           jac,
					    EDDY::CudaVolume4D&         grad);

  /// Calculates field used for transforming model to scan space
  static void field_for_model_to_scan_transform(// Input
						const EDDY::ECScan&       scan,
						const EDDY::CudaVolume&   susc,
						// Output
						EDDY::CudaVolume4D&       dfield,
						EDDY::CudaVolume&         omask,
						// Optional output
						EDDY::CudaVolume&         jac);

  /// Transform regular-grid coordinates in model space to scan space
  static EDDY::CudaImageCoordinates transform_coordinates_from_model_to_scan_space(// Input
										   const EDDY::CudaVolume&     pred,
										   const EDDY::ECScan&         scan,
										   const EDDY::CudaVolume&     susc,
										   // Output
										   EDDY::CudaImageCoordinates& coord,
										   // Optional Output
										   EDDY::CudaVolume&           omask,
										   EDDY::CudaVolume&           jac);

  /// Calculates partiald derivatives with respect EC and movement parameters
  static void get_partial_derivatives_in_scan_space(const EDDY::CudaVolume&  pred,
						    const EDDY::ECScan&      scan,
						    const EDDY::CudaVolume&  susc,
						    EDDY::ParametersType     whichp,
						    EDDY::CudaVolume4D&      derivs);

  static void get_direct_partial_derivatives_in_scan_space(const EDDY::CudaVolume& pred,
							   const EDDY::ECScan&     scan,
							   const EDDY::CudaVolume& susc,
							   EDDY::ParametersType    whichp,
							   EDDY::CudaVolume4D&     derivs);

  static void make_deriv_from_components(const EDDY::CudaImageCoordinates&  coord,
					 const EDDY::CudaVolume4D&          grad,
					 const EDDY::CudaVolume&            base,
					 const EDDY::CudaVolume&            jac,
					 const EDDY::CudaVolume&            basejac,
					 float                              dstep,
					 EDDY::CudaVolume4D&                deriv,
					 unsigned int                       indx);

  static NEWMAT::Matrix make_XtX(const EDDY::CudaVolume4D&  X,
				 const EDDY::CudaVolume&    mask);

  static NEWMAT::Matrix make_XtX_cuBLAS(const EDDY::CudaVolume4D&  X);

  static NEWMAT::ColumnVector make_Xty(const EDDY::CudaVolume4D&  X,
				       const EDDY::CudaVolume&    y,
				       const EDDY::CudaVolume&    mask);

  static void make_scatter_brain_predictions(// Input
					     const EddyCommandLineOptions&  clo,
					     const ECScanManager&           sm,
					     const std::vector<double>&     hypar,
					     // Output
					     NEWIMAGE::volume4D<float>&     pred,
					     // Optional input
					     bool                           vwbvrot=false);

  static void general_transform(const EDDY::CudaVolume&    inima,
				const NEWMAT::Matrix&      A,
				const EDDY::CudaVolume4D&  dfield,
				const NEWMAT::Matrix&      M,
				EDDY::CudaVolume&          oima,
				EDDY::CudaVolume4D&        deriv,
				EDDY::CudaVolume&          omask);

  static void general_transform(// Input
				const EDDY::CudaVolume&             inima,
				const std::vector<NEWMAT::Matrix>&  A,
				const EDDY::CudaVolume4D&           dfield,
				const std::vector<NEWMAT::Matrix>&  M,
				// Output
				EDDY::CudaVolume&                   oima,
				// Optional output
				EDDY::CudaVolume4D&                 deriv,
				EDDY::CudaVolume&                   omask);

  static void general_slice_to_vol_transform(// Input
					     const EDDY::CudaVolume&             inima,
					     const std::vector<NEWMAT::Matrix>&  A,
					     const EDDY::CudaVolume4D&           dfield,
					     const EDDY::CudaVolume&             jac,
					     const EDDY::CudaVolume&             pred,
					     bool                                jacmod,
					     const EDDY::PolationPara&           pp,
					     // Output
					     EDDY::CudaVolume&                   oima,
					     // Optional output
					     EDDY::CudaVolume&                   omask);

  static void half_way_slice_to_vol_transform(// Input
					      const EDDY::CudaVolume&             inima,
					      const std::vector<NEWMAT::Matrix>&  A,
					      const EDDY::CudaVolume4D&           dfield,
					      const EDDY::CudaVolume&             jac,
					      // Output
					      EDDY::CudaVolume&                   hwima,
					      EDDY::CudaVolume&                   zcoordV,
					      // Optional output
					      EDDY::CudaVolume&                   oima,
					      EDDY::CudaVolume&                   omask);

  static void MovementDisplacementToModelSpace(// Input
					       const ECScan&       scan,
					       bool                exclude_pe_tr,
					       // Output
					       EDDY::CudaVolume4D& mov_field);

  static void affine_transform(const EDDY::CudaVolume&    inima,
			       const NEWMAT::Matrix&      R,
			       EDDY::CudaVolume&          oima,
			       EDDY::CudaVolume4D&        deriv,
			       EDDY::CudaVolume&          omask);

  static void affine_transform(const EDDY::CudaVolume&             inima,
			       const std::vector<NEWMAT::Matrix>&  R,
			       EDDY::CudaVolume&                   oima,
			       EDDY::CudaVolume4D&                 deriv,
			       EDDY::CudaVolume&                   omask);

  /// Caclulates EC field given current parameters
  static void get_ec_field(// Input
			   const EDDY::ECScan&        scan,
			   // Output
			   EDDY::CudaVolume&          ecfield);

};

/////////////////////////////////////////////////////////////////////
///
/// \brief This class contains a set of static methods that implement
/// various field related utility functions for the eddy project 
/// implemented on CUDA GPU.
///
/////////////////////////////////////////////////////////////////////
class FieldGpuUtils
{
private:
  friend class EddyInternalGpuUtils;
  friend class DerivativeCalculator;

  static const int threads_per_block_invert_field = 128;

  static void Hz2VoxelDisplacements(const EDDY::CudaVolume&  hzfield,
				    const EDDY::AcqPara&     acqp,
				    EDDY::CudaVolume4D&      dfield);

  static void Voxel2MMDisplacements(EDDY::CudaVolume4D&      dfield);

  static void InvertDisplacementField(// Input
				      const EDDY::CudaVolume4D&  dfield,
				      const EDDY::AcqPara&       acqp,
				      const EDDY::CudaVolume&    inmask,
				      // Output
				      EDDY::CudaVolume4D&        idfield,
				      EDDY::CudaVolume&          omask);
    
  static void GetJacobian(// Input
			  const EDDY::CudaVolume4D&  dfield,
			  const EDDY::AcqPara&       acqp,
			  // Output
			  EDDY::CudaVolume&          jac);

  static void GetDiscreteJacobian(// Input
				  const EDDY::CudaVolume4D&  dfield,
				  const EDDY::AcqPara&       acqp,
				  // Output
				  EDDY::CudaVolume&          jac);

};

} // End namespace EDDY

#endif // End #ifndef EddyInternalGpuUtils_h