///////////////////////////////////////////////////////////////////// /// /// \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 #include #include #include #include #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 pmp, NEWIMAGE::volume& mask); /* static void update_prediction_maker(// Input const EddyCommandLineOptions& clo, ScanType st, const ECScanManager& sm, const ReplacementManager& rm, const NEWIMAGE::volume& mask, // Input/Output std::shared_ptr 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 pmp, const NEWIMAGE::volume& 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 pmp, const NEWIMAGE::volume& 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& pred, // Prediction in model space std::shared_ptr > susc, // Susc-induced off-resonance field std::shared_ptr > bias, // Recieve bias field const NEWIMAGE::volume& 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 long_ec_update(// Input const std::vector >& pred, // Predictions in model space const NEWIMAGE::volume& 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& 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 >& 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& 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& updates); static void write_debug_info_long_ec_cbs_step(const EDDY::ECScan& scan, unsigned int scindx, const std::vector& 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& hypar, // Output NEWIMAGE::volume4D& 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& A, const EDDY::CudaVolume4D& dfield, const std::vector& 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& 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& 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& 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