Xmipp  v3.23.11-Nereus
Public Member Functions | Static Public Member Functions | List of all members
Alignment::CudaShiftCorrEstimator< T > Class Template Reference

#include <cuda_shift_corr_estimator.h>

Inheritance diagram for Alignment::CudaShiftCorrEstimator< T >:
Inheritance graph
[legend]
Collaboration diagram for Alignment::CudaShiftCorrEstimator< T >:
Collaboration graph
[legend]

Public Member Functions

 CudaShiftCorrEstimator ()
 
virtual ~CudaShiftCorrEstimator ()
 
void init2D (const std::vector< HW *> &hw, AlignType type, const FFTSettings< T > &dims, size_t maxShift, bool includingBatchFT, bool includingSingleFT, bool allowDataOverwrite) override
 
void release ()
 
void load2DReferenceOneToN (const std::complex< T > *h_ref) override
 
void load2DReferenceOneToN (const T *h_ref) override
 
void computeCorrelations2DOneToN (std::complex< T > *h_inOut, bool center) override
 
void computeCorrelations2DOneToN (const HW &hw, std::complex< T > *inOut, const std::complex< T > *ref, const Dimensions &dims, bool center) override
 
void computeShift2DOneToN (T *others) override
 
HWgetHW () const override
 
- Public Member Functions inherited from Alignment::AShiftCorrEstimator< T >
 AShiftCorrEstimator ()
 
 AShiftCorrEstimator (const AShiftCorrEstimator &)=delete
 
 AShiftCorrEstimator (const AShiftCorrEstimator &&)=delete
 
virtual ~AShiftCorrEstimator ()
 
AShiftCorrEstimatoroperator= (const AShiftCorrEstimator &)=delete
 
AShiftCorrEstimatoroperator= (const AShiftCorrEstimator &&)=delete
 
- Public Member Functions inherited from Alignment::AShiftEstimator< T >
 AShiftEstimator ()
 
 AShiftEstimator (const AShiftEstimator &)=delete
 
 AShiftEstimator (const AShiftEstimator &&)=delete
 
virtual ~AShiftEstimator ()
 
AShiftEstimatoroperator= (const AShiftEstimator &)=delete
 
AShiftEstimatoroperator= (const AShiftEstimator &&)=delete
 
std::vector< Point2D< float > > getShifts2D ()
 
constexpr bool isInitialized () const
 
constexpr Dimensions getDimensions () const
 
constexpr AlignType getAlignType () const
 

Static Public Member Functions

static std::vector< Point2D< float > > computeShifts2DOneToN (const std::vector< GPU *> &gpus, std::complex< T > *d_othersF, T *d_othersS, std::complex< T > *d_ref, const FFTSettings< T > &settings, cufftHandle plan, T *h_centers, size_t maxShift)
 
template<bool center>
static void sComputeCorrelations2DOneToN (const GPU &gpu, std::complex< T > *d_inOut, const std::complex< T > *d_ref, const Dimensions &dims)
 

Additional Inherited Members

- Protected Member Functions inherited from Alignment::AShiftCorrEstimator< T >
virtual void init2D (AlignType type, const FFTSettings< T > &dims, size_t maxShift, bool includingBatchFT, bool includingSingleFT, bool allowDataOverwrite)
 
void init2D (const std::vector< HW *> &hw, AlignType type, const Dimensions &dims, size_t batch, size_t maxShift)
 
- Protected Member Functions inherited from Alignment::AShiftEstimator< T >
virtual void init2D (AlignType type, const Dimensions &dims, size_t batch, size_t maxShift)
 
- Protected Attributes inherited from Alignment::AShiftCorrEstimator< T >
FFTSettings< T > * m_settingsInv
 
size_t m_centerSize
 
bool m_includingBatchFT
 
bool m_includingSingleFT
 
bool m_is_ref_FD_loaded
 
bool m_allowDataOverwrite
 
- Protected Attributes inherited from Alignment::AShiftEstimator< T >
AlignType m_type
 
const Dimensionsm_dims
 
size_t m_batch
 
size_t m_maxShift
 
std::vector< Point2D< float > > m_shifts2D
 
bool m_is_ref_loaded
 
bool m_is_shift_computed
 
bool m_isInit
 

Detailed Description

template<typename T>
class Alignment::CudaShiftCorrEstimator< T >

Definition at line 45 of file cuda_shift_corr_estimator.h.

Constructor & Destructor Documentation

◆ CudaShiftCorrEstimator()

template<typename T>
Alignment::CudaShiftCorrEstimator< T >::CudaShiftCorrEstimator ( )
inline

Definition at line 47 of file cuda_shift_corr_estimator.h.

47  {
48  setDefault();
49  }

◆ ~CudaShiftCorrEstimator()

template<typename T>
virtual Alignment::CudaShiftCorrEstimator< T >::~CudaShiftCorrEstimator ( )
inlinevirtual

Definition at line 51 of file cuda_shift_corr_estimator.h.

Member Function Documentation

◆ computeCorrelations2DOneToN() [1/2]

template<typename T >
void Alignment::CudaShiftCorrEstimator< T >::computeCorrelations2DOneToN ( std::complex< T > *  h_inOut,
bool  center 
)
overridevirtual

Implements Alignment::AShiftCorrEstimator< T >.

Definition at line 184 of file cuda_shift_corr_estimator.cpp.

185  {
186  bool isReady = (this->m_isInit && (AlignType::OneToN == this->m_type) && m_is_d_single_FD_loaded);
187 
188  if ( ! isReady) {
189  REPORT_ERROR(ERR_LOGIC_ERROR, "Not ready to execute. Call init() before");
190  }
191 
192  m_loadStream->set();
193  m_workStream->set();
194  auto loadStream = *(cudaStream_t*)m_loadStream->stream();
195  auto workStream = *(cudaStream_t*)m_workStream->stream();
196  // process signals in batches
197  for (size_t offset = 0; offset < this->m_settingsInv->fDim().n(); offset += this->m_settingsInv->batch()) {
198  // how many signals to process
199  size_t toProcess = std::min(this->m_settingsInv->batch(), this->m_settingsInv->fDim().n() - offset);
200 
201  // copy memory
202  gpuErrchk(cudaMemcpyAsync(
203  m_d_batch_FD,
204  h_inOut + offset * this->m_settingsInv->fDim().xy(),
205  toProcess * this->m_settingsInv->fBytesSingle(),
206  cudaMemcpyHostToDevice, loadStream));
207  m_loadStream->synch();
208 
209  auto dims = Dimensions(
210  this->m_settingsInv->fDim().x(),
211  this->m_settingsInv->fDim().y(),
212  1,
213  toProcess);
214  if (center) {
215  sComputeCorrelations2DOneToN<true>(*m_workStream, m_d_batch_FD, m_d_single_FD, dims);
216  } else {
217  sComputeCorrelations2DOneToN<false>(*m_workStream, m_d_batch_FD, m_d_single_FD, dims);
218  }
219  m_workStream->synch();
220 
221  // copy data back
222  gpuErrchk(cudaMemcpyAsync(
223  h_inOut + offset * this->m_settingsInv->fDim().xy(),
224  m_d_batch_FD,
225  toProcess * this->m_settingsInv->fBytesSingle(),
226  cudaMemcpyDeviceToHost, loadStream));
227  }
228 }
#define gpuErrchk(code)
Definition: cuda_asserts.h:31
void * stream() const
Definition: gpu.h:50
void min(Image< double > &op1, const Image< double > &op2)
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
void set()
Definition: gpu.cpp:50
void synch() const
Definition: gpu.cpp:129
Some logical error in the pipeline.
Definition: xmipp_error.h:147

◆ computeCorrelations2DOneToN() [2/2]

template<typename T >
void Alignment::CudaShiftCorrEstimator< T >::computeCorrelations2DOneToN ( const HW hw,
std::complex< T > *  inOut,
const std::complex< T > *  ref,
const Dimensions dims,
bool  center 
)
overridevirtual

Implements Alignment::AShiftCorrEstimator< T >.

Definition at line 419 of file cuda_shift_corr_estimator.cpp.

424  {
425  const GPU *gpu;
426  try {
427  gpu = &dynamic_cast<const GPU&>(hw);
428  } catch (std::bad_cast&) {
429  REPORT_ERROR(ERR_ARG_INCORRECT, "Instance of GPU expected");
430  }
431  if (center) {
432  return sComputeCorrelations2DOneToN<true>(*gpu, inOut, ref, dims);
433  } else {
434  return sComputeCorrelations2DOneToN<false>(*gpu, inOut, ref, dims);
435  }
436 }
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
Incorrect argument received.
Definition: xmipp_error.h:113
Definition: gpu.h:36

◆ computeShift2DOneToN()

template<typename T >
void Alignment::CudaShiftCorrEstimator< T >::computeShift2DOneToN ( T *  others)
overridevirtual

Implements Alignment::AShiftEstimator< T >.

Definition at line 281 of file cuda_shift_corr_estimator.cpp.

282  {
283  bool isReady = (this->m_isInit && (AlignType::OneToN == this->m_type)
284  && m_is_d_single_FD_loaded && this->m_includingBatchFT);
285 
286  if ( ! isReady) {
287  REPORT_ERROR(ERR_LOGIC_ERROR, "Not ready to execute. Call init() before");
288  }
289  const auto isGpuPtr = m_workStream->isGpuPointer(others);
290  if(!isGpuPtr) {
291  if ( ! GPU::isMemoryPinned(others)) {
292  REPORT_ERROR(ERR_LOGIC_ERROR, "Input memory has to be pinned (page-locked)");
293  }
294  if (this->m_allowDataOverwrite) {
295  REPORT_ERROR(ERR_LOGIC_ERROR, "Incompatible parameters: allowDataOverwrite && 'others' data on host");
296  }
297  }
298 
299  m_workStream->set();
300  // make sure that all work (e.g. loading and processing of the reference) is done
301  m_loadStream->synch();
302  m_workStream->synch();
303  // start loading data at the background
304  m_isDataReady = false;
305  const bool createLocalCopy = ( ! this->m_allowDataOverwrite);
306  std::thread loadingThread;
307  if (createLocalCopy) {
308  loadingThread = std::thread(&CudaShiftCorrEstimator<T>::loadThreadRoutine, this, others);
309  }
310 
311  // reserve enough space for shifts
312  this->m_shifts2D.reserve(this->m_settingsInv->fDim().n());
313  // process signals
314  for (size_t offset = 0; offset < this->m_settingsInv->fDim().n(); offset += this->m_settingsInv->batch()) {
315  size_t batchOffset = createLocalCopy
316  ? offset
317  : std::min(offset, this->m_settingsInv->fDim().n() - this->m_settingsInv->batch());
318  // how many signals to process
319  size_t toProcess = std::min(
320  this->m_settingsInv->batch(),
321  this->m_settingsInv->fDim().n() - batchOffset);
322 
323  if (createLocalCopy) {
324  waitAndConvert();
325  } else {
326  T *in = others + (batchOffset * this->m_settingsInv->sDim().sizeSingle());
327  CudaFFT<T>::fft(*m_batchToFD, in, m_d_batch_FD);
328  }
329 
330  // compute shifts
331  auto shifts = computeShifts2DOneToN(
332  std::vector<GPU*>{m_workStream, m_loadStream},
333  m_d_batch_FD,
334  m_d_batch_SD_work,
335  m_d_single_FD,
336  this->m_settingsInv->createSubset(toProcess),
337  *m_batchToSD,
338  this->m_h_centers,
339  this->m_maxShift);
340 
341  size_t start = createLocalCopy
342  ? 0
343  : (offset - batchOffset);
344  // append shifts to existing results
345  this->m_shifts2D.insert(this->m_shifts2D.end(),
346  shifts.begin() + start,
347  shifts.end());
348  }
349  if (createLocalCopy) {
350  loadingThread.join();
351  }
352  // update state
353  this->m_is_shift_computed = true;
354 }
void min(Image< double > &op1, const Image< double > &op2)
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
std::vector< Point2D< float > > m_shifts2D
static bool isMemoryPinned(const void *h_mem)
Definition: gpu.cpp:140
static std::vector< Point2D< float > > computeShifts2DOneToN(const std::vector< GPU *> &gpus, std::complex< T > *d_othersF, T *d_othersS, std::complex< T > *d_ref, const FFTSettings< T > &settings, cufftHandle plan, T *h_centers, size_t maxShift)
int in
void set()
Definition: gpu.cpp:50
void synch() const
Definition: gpu.cpp:129
std::complex< T > * fft(T *h_inOut)
Definition: cuda_fft.cpp:119
bool isGpuPointer(const void *)
Definition: gpu.cpp:153
Some logical error in the pipeline.
Definition: xmipp_error.h:147

◆ computeShifts2DOneToN()

template<typename T >
std::vector< Point2D< float > > Alignment::CudaShiftCorrEstimator< T >::computeShifts2DOneToN ( const std::vector< GPU *> &  gpus,
std::complex< T > *  d_othersF,
T *  d_othersS,
std::complex< T > *  d_ref,
const FFTSettings< T > &  settings,
cufftHandle  plan,
T *  h_centers,
size_t  maxShift 
)
static

Definition at line 357 of file cuda_shift_corr_estimator.cpp.

365  {
366  // we need even input in order to perform the shift (in FD, while correlating) properly
367  assert(0 == (settings.sDim().x() % 2));
368  assert(0 == (settings.sDim().y() % 2));
369  assert(1 == settings.sDim().zPadded());
370  assert(2 == gpus.size());
371 
372  size_t centerSize = maxShift * 2 + 1;
373 
374  // make sure we have enough memory for centers of the correlation functions
375  assert(settings.fBytesBatch() >= (settings.sDim().n() * centerSize * centerSize * sizeof(T)));
376 
377  auto workGPU = gpus.at(0);
378  auto loadGPU = gpus.at(1);
379  loadGPU->set();
380  workGPU->set();
381  auto loadStream = *(cudaStream_t*)loadGPU->stream();
382  auto workStream = *(cudaStream_t*)workGPU->stream();
383 
384  // correlate signals and shift FT so that it will be centered after IFT
385  sComputeCorrelations2DOneToN<true>(*workGPU,
386  d_othersF, d_ref,
387  settings.fDim());
388 
389  // perform IFT
390  CudaFFT<T>::ifft(plan, d_othersF, d_othersS);
391 
392  // locate maxima
393  auto p_pos = (float*)d_othersF;
394  auto h_pos = (float*)h_centers;
396  *workGPU, settings.sDim(), d_othersS, p_pos, nullptr, maxShift);
397  workGPU->synch();
398  // copy data back
399  gpuErrchk(cudaMemcpyAsync(h_pos, p_pos,
400  settings.batch() * sizeof(float),
401  cudaMemcpyDeviceToHost, loadStream));
402  loadGPU->synch();
403 
404  // convert absolute 1D index to logical 2D index
405  // FIXME DS extract this to some utils
406  auto result = std::vector<Point2D<float>>();
407  result.reserve(settings.sDim().n());
408  for (size_t n = 0; n < settings.batch(); ++n) {
409  float y = (size_t)h_pos[n] / settings.sDim().x();
410  float x = (size_t)h_pos[n] % settings.sDim().x();
411  result.emplace_back(
412  x - settings.sDim().x() / 2,
413  y - settings.sDim().y() / 2);
414  }
415  return result;
416 }
#define gpuErrchk(code)
Definition: cuda_asserts.h:31
constexpr size_t fBytesBatch() const
Definition: fft_settings.h:98
static double * y
constexpr Dimensions fDim() const
Definition: fft_settings.h:82
doublereal * x
constexpr size_t batch() const
Definition: fft_settings.h:86
CUDA_HD constexpr size_t x() const
Definition: dimensions.h:51
constexpr size_t zPadded() const
Definition: dimensions.h:73
T * ifft(std::complex< T > *h_inOut)
Definition: cuda_fft.cpp:129
static void sFindMax2DAroundCenter(const GPU &gpu, const Dimensions &dims, const T *d_data, float *d_positions, T *d_values, size_t maxDist)
CUDA_HD constexpr size_t y() const
Definition: dimensions.h:60
CUDA_HD constexpr size_t n() const
Definition: dimensions.h:78
constexpr Dimensions sDim() const
Definition: fft_settings.h:78
int * n

◆ getHW()

template<typename T>
HW& Alignment::CudaShiftCorrEstimator< T >::getHW ( ) const
inlineoverridevirtual

Implements Alignment::AShiftEstimator< T >.

Definition at line 93 of file cuda_shift_corr_estimator.h.

93  {
94  return *m_workStream;
95  }

◆ init2D()

template<typename T >
void Alignment::CudaShiftCorrEstimator< T >::init2D ( const std::vector< HW *> &  hw,
AlignType  type,
const FFTSettings< T > &  dims,
size_t  maxShift,
bool  includingBatchFT,
bool  includingSingleFT,
bool  allowDataOverwrite 
)
overridevirtual

Implements Alignment::AShiftCorrEstimator< T >.

Definition at line 34 of file cuda_shift_corr_estimator.cpp.

37  {
38  // FIXME DS consider tunning the size of the input (e.g. 436x436x50)
39  if (2 != hw.size()) {
40  REPORT_ERROR(ERR_ARG_INCORRECT, "Two GPU streams are needed");
41  }
42  release(); // FIXME DS implement lazy init
43  m_workStream = dynamic_cast<GPU*>(hw.at(0));
44  m_loadStream = dynamic_cast<GPU*>(hw.at(1));
45  if ((nullptr == m_workStream)
46  || (nullptr == m_loadStream)) {
47  REPORT_ERROR(ERR_LOGIC_ERROR, "Instance of GPU is expected");
48  }
49  m_workStream->set();
50  m_loadStream->set();
51  AShiftCorrEstimator<T>::init2D(type, settings, maxShift,
52  includingBatchFT, includingSingleFT, allowDataOvewrite);
53 
54  // synch primitives
55  m_mutex = new std::mutex();
56  m_cv = new std::condition_variable();
57 
58  this->m_isInit = true;
59 }
Mutex mutex
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
virtual void init2D(const std::vector< HW *> &hw, AlignType type, const FFTSettings< T > &dims, size_t maxShift, bool includingBatchFT, bool includingSingleFT, bool allowDataOverwrite)=0
viol type
Incorrect argument received.
Definition: xmipp_error.h:113
void set()
Definition: gpu.cpp:50
Definition: gpu.h:36
Some logical error in the pipeline.
Definition: xmipp_error.h:147

◆ load2DReferenceOneToN() [1/2]

template<typename T >
void Alignment::CudaShiftCorrEstimator< T >::load2DReferenceOneToN ( const std::complex< T > *  h_ref)
overridevirtual

Implements Alignment::AShiftCorrEstimator< T >.

Definition at line 90 of file cuda_shift_corr_estimator.cpp.

90  {
91  auto isReady = (this->m_isInit && (AlignType::OneToN == this->m_type));
92  if ( ! isReady) {
93  REPORT_ERROR(ERR_LOGIC_ERROR, "Not ready to load a reference signal");
94  }
95 
96  m_loadStream->set();
97  auto loadStream = *(cudaStream_t*)m_loadStream->stream();
98  // copy reference to GPU
99  gpuErrchk(cudaMemcpyAsync(m_d_single_FD, h_ref, this->m_settingsInv->fBytesSingle(),
100  cudaMemcpyHostToDevice, loadStream));
101 
102  // update state
103  m_is_d_single_FD_loaded = true;
104 }
#define gpuErrchk(code)
Definition: cuda_asserts.h:31
void * stream() const
Definition: gpu.h:50
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
void set()
Definition: gpu.cpp:50
Some logical error in the pipeline.
Definition: xmipp_error.h:147

◆ load2DReferenceOneToN() [2/2]

template<typename T >
void Alignment::CudaShiftCorrEstimator< T >::load2DReferenceOneToN ( const T *  h_ref)
overridevirtual

Implements Alignment::AShiftEstimator< T >.

Definition at line 107 of file cuda_shift_corr_estimator.cpp.

107  {
108  auto isReady = (this->m_isInit && (AlignType::OneToN == this->m_type) && this->m_includingSingleFT);
109  if ( ! isReady) {
110  REPORT_ERROR(ERR_LOGIC_ERROR, "Not ready to load a reference signal");
111  }
112  m_loadStream->set();
113  m_workStream->set();
114  auto loadStream = *(cudaStream_t*)m_loadStream->stream();
115  auto workStream = *(cudaStream_t*)m_workStream->stream();
116 
117  // copy reference to GPU
118  gpuErrchk(cudaMemcpyAsync(m_d_single_SD, h_ref, this->m_settingsInv->sBytesSingle(),
119  cudaMemcpyHostToDevice, loadStream));
120  m_loadStream->synch();
121 
122  // perform FT
123  CudaFFT<T>::fft(*m_singleToFD, m_d_single_SD, m_d_single_FD);
124 
125  // update state
126  m_is_d_single_FD_loaded = true;
127 }
#define gpuErrchk(code)
Definition: cuda_asserts.h:31
void * stream() const
Definition: gpu.h:50
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
void set()
Definition: gpu.cpp:50
void synch() const
Definition: gpu.cpp:129
std::complex< T > * fft(T *h_inOut)
Definition: cuda_fft.cpp:119
Some logical error in the pipeline.
Definition: xmipp_error.h:147

◆ release()

template<typename T >
void Alignment::CudaShiftCorrEstimator< T >::release ( )
virtual

Reimplemented from Alignment::AShiftCorrEstimator< T >.

Definition at line 130 of file cuda_shift_corr_estimator.cpp.

130  {
131  // device memory
132  gpuErrchk(cudaFree(m_d_single_FD));
133  gpuErrchk(cudaFree(m_d_batch_FD));
134  gpuErrchk(cudaFree(m_d_single_SD));
135  gpuErrchk(cudaFree(m_d_batch_SD_work));
136  if ( ! this->m_allowDataOverwrite) {
137  gpuErrchk(cudaFree(m_d_batch_SD_load));
138  }
139 
140  // host memory
141  delete[] m_h_centers;
142 
143  // FT plans
144  CudaFFT<T>::release(m_singleToFD);
145  CudaFFT<T>::release(m_batchToFD);
146  CudaFFT<T>::release(m_batchToSD);
147 
148  // synch primitives
149  delete m_mutex;
150  delete m_cv;
151 
153 
154  CudaShiftCorrEstimator<T>::setDefault();
155 }
#define gpuErrchk(code)
Definition: cuda_asserts.h:31
void release() final
Definition: cuda_fft.cpp:108

◆ sComputeCorrelations2DOneToN()

template<typename T >
template<bool center>
void Alignment::CudaShiftCorrEstimator< T >::sComputeCorrelations2DOneToN ( const GPU gpu,
std::complex< T > *  d_inOut,
const std::complex< T > *  d_ref,
const Dimensions dims 
)
static

Definition at line 440 of file cuda_shift_corr_estimator.cpp.

444  {
445  if (center) {
446  // we cannot assert xDim, as we don't know if the spatial size was even
447  assert(0 == (dims.y() % 2));
448  }
449  assert(0 < dims.x());
450  assert(0 < dims.y());
451  assert(1 == dims.z());
452  assert(0 < dims.n());
453 
454  // create threads / blocks
455  dim3 dimBlock(64, 1, 1);
456  dim3 dimGrid(
457  std::ceil(dims.x() / (float)dimBlock.x),
458  dims.n(), 1);
459  auto stream = *(cudaStream_t*)gpu.stream();
460  if (std::is_same<T, float>::value) {
461  computeCorrelations2DOneToNKernel<float2, center>
462  <<<dimGrid, dimBlock, 0, stream>>> (
463  (float2*)d_inOut, (float2*)d_ref,
464  dims.x(), dims.y(), dims.n());
465  } else if (std::is_same<T, double>::value) {
466  computeCorrelations2DOneToNKernel<double2, center>
467  <<<dimGrid, dimBlock, 0, stream>>> (
468  (double2*)d_inOut, (double2*)d_ref,
469  dims.x(), dims.y(), dims.n());
470  } else {
471  REPORT_ERROR(ERR_TYPE_INCORRECT, "Not implemented");
472  }
473 }
void * stream() const
Definition: gpu.h:50
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
CUDA_HD constexpr size_t z() const
Definition: dimensions.h:69
CUDA_HD constexpr size_t x() const
Definition: dimensions.h:51
CUDA_HD constexpr size_t y() const
Definition: dimensions.h:60
CUDA_HD constexpr size_t n() const
Definition: dimensions.h:78
Incorrect type received.
Definition: xmipp_error.h:190

The documentation for this class was generated from the following files: