/*! \file fmriPredictor.cu \brief Contains definitions for class for making Gaussian process based predictions about fMRI data. \author Jesper Andersson \version 1.0b, May., 2022. */ // Definitions of class to make Gaussian-Process // based predictions about fMRI data. // // fmriPredictor.cu // // Jesper Andersson, FMRIB Image Analysis Group // // Copyright (C) 2011 University of Oxford // #include #include #include #include #pragma push #pragma diag_suppress = code_is_unreachable // Supress warnings from armawrap #pragma diag_suppress = expr_has_no_effect // Supress warnings from boost #include "armawrap/newmat.h" #include "newimage/newimageall.h" #pragma pop #include "miscmaths/miscmaths.h" #include "EddyHelperClasses.h" #include "EddyUtils.h" #include "fmriPredictor.h" #include "CudaVolume.h" using namespace EDDY; /****************************************************************//** * \brief Returns prediction for point given by indx * * Returns a predicted image for the given index, where index refers * to the corresponding time-point. * It should be noted that this implementation isn't very efficient as * it reloads all image to the GPU. That means that if there are N images * and we want to predict them all it takes N*N transfers to the GPU. * \param index refers to the corresponding time-point * \param exclude Decides if indx itself should be used in the prediction * (exclude=false) or not (exclude=true) * \param pvec Prediction vector for index * \param pi The "predicted image" * ********************************************************************/ void fmriPredictor::predict_image_gpu(// Input unsigned int indx, bool exclude, const arma::rowvec& pvec, // Output NEWIMAGE::volume& pi) const EddyTry { unsigned int pvec_length = (exclude) ? this->no_of_scans_in_same_session(indx)-1 : this->no_of_scans_in_same_session(indx); if (pvec_length != pvec.n_cols) throw EddyException("fmriPredictor::predict_image_gpu: Wrong length pvec"); if (!NEWIMAGE::samesize(pi,*(this->first_imptr()))) { pi.reinitialize(this->first_imptr()->xsize(),this->first_imptr()->ysize(),this->first_imptr()->zsize()); NEWIMAGE::copybasicproperties(*(this->first_imptr()),pi); } EDDY::CudaVolume pcv(pi,false); int sindx = this->index_in_session(indx); std::shared_ptr > ptr=nullptr; for (unsigned int s=0; sno_of_scans_in_same_session(indx); s++) { if (exclude) { if (s < sindx) pcv.MultiplyAndAddToMe(EDDY::CudaVolume(*(this->imptr_from_same_session(indx,s))),pvec(s)); // Do nothing if s==sindx else if (s > indx) pcv.MultiplyAndAddToMe(EDDY::CudaVolume(*(this->imptr_from_same_session(indx,s))),pvec(s-1)); } else pcv.MultiplyAndAddToMe(EDDY::CudaVolume(*(this->imptr_from_same_session(indx,s))),pvec(s)); } pcv += EDDY::CudaVolume(*(this->meanptr_from_same_session(indx))); pcv.GetVolume(pi); return; } EddyCatch void fmriPredictor::predict_images_gpu(// Input const std::vector& indicies, bool exclude, const std::vector& pvecs, // Output std::vector >& pi) const EddyTry { // Sanity checks if (indicies.size() != pvecs.size() || indicies.size() != pi.size()) { throw EDDY::EddyException("fmriPredictor::predict_images_gpu: mismatch among indicies, pvecs and pi"); } if (!this->all_in_same_session(indicies)) throw EDDY::EddyException("fmriPredictor::predict_images_gpu: indicies are in different sessions"); unsigned int pvec_length = (exclude) ? this->no_of_scans_in_same_session(indicies[0])-1 : this->no_of_scans_in_same_session(indicies[0]); if (std::any_of(pvecs.begin(),pvecs.end(),[pvec_length](const arma::rowvec& rv){ return(rv.n_cols != pvec_length); })) { throw EDDY::EddyException("fmriPredictor::predict_images_gpu: pvec with wrong length"); } // Start by allocating space on GPU for all output images std::vector pcvs(indicies.size()); for (unsigned int i=0; ifirst_imptr()))) { pi[i].reinitialize(this->first_imptr()->xsize(),this->first_imptr()->ysize(),this->first_imptr()->zsize()); NEWIMAGE::copybasicproperties(*(this->first_imptr()),pi[i]); } pcvs[i].SetHdr(pi[i]); } // Transfer mean image to the GPU EDDY::CudaVolume mean = *(this->meanptr_from_same_session(indicies[0])); // Do the GP predictions for (unsigned int s=0; sno_of_scans_in_same_session(indicies[0]); s++) { // s index into original volumes EDDY::CudaVolume cv = *(this->imptr_from_same_session(indicies[0],s)); for (unsigned int i=0; iindex_in_session(indicies[i])) pcvs[i].MultiplyAndAddToMe(cv,pvecs[i](s)); // Do nothing if (s == indicies[i]) else if (s > this->index_in_session(indicies[i])) pcvs[i].MultiplyAndAddToMe(cv,pvecs[i](s-1)); } else pcvs[i].MultiplyAndAddToMe(cv,pvecs[i](s)); } } // Add means to predictions and transfer back from GPU for (unsigned int i=0; i