WSClean
wstackinggridder.h
1 //
2 // This file was written by AndrĂ© Offringa and is published
3 // under the GPL 3 license.
4 //
5 
6 #ifndef WSTACKING_GRIDDER_H
7 #define WSTACKING_GRIDDER_H
8 
9 #ifndef AVOID_CASACORE
10 #include "../multibanddata.h"
11 #endif
12 
13 // Forward declare boost::mutex to avoid header inclusion
14 namespace boost
15 {
16  class mutex;
17 }
18 
19 #include <cmath>
20 #include <cstring>
21 #include <complex>
22 #include <vector>
23 #include <stack>
24 
25 class ImageBufferAllocator;
26 
83 {
89  public:
92  enum GridModeEnum {
93 
96 
104 
111  RectangularKernel
112  };
113 
132  WStackingGridder(size_t width, size_t height, double pixelSizeX, double pixelSizeY, size_t fftThreadCount, ImageBufferAllocator* allocator, size_t kernelSize = 7, size_t overSamplingFactor = 63);
133 
134  WStackingGridder(const WStackingGridder&) = delete;
135 
136  WStackingGridder& operator=(const WStackingGridder&) = delete;
137 
139  ~WStackingGridder();
140 
170  void PrepareWLayers(size_t nWLayers, double maxMem, double minW, double maxW);
171 
172 #ifndef AVOID_CASACORE
173 
182  void PrepareBand(const MultiBandData &bandData)
183  {
184  _bandData = bandData;
185  }
186 #endif // AVOID_CASACORE
187 
195  size_t WToLayer(double wInLambda) const
196  {
197  if(_nWLayers == 1)
198  return 0;
199  else {
200  if(_isComplex)
201  return size_t(round((wInLambda + _maxW) * (_nWLayers-1) / (_maxW + _maxW)));
202  else
203  return size_t(round((fabs(wInLambda) - _minW) * (_nWLayers-1) / (_maxW - _minW)));
204  }
205  }
206 
213  double LayerToW(size_t layer) const
214  {
215  if(_nWLayers == 1)
216  return 0.0;
217  else {
218  if(_isComplex)
219  return layer * (_maxW + _maxW) / (_nWLayers-1) - _maxW;
220  else
221  return layer * (_maxW - _minW) / (_nWLayers-1) + _minW;
222  }
223  }
224 
229  size_t NWLayers() const { return _nWLayers; }
230 
238  bool IsInLayerRange(double wInLambda) const
239  {
240  size_t layer = WToLayer(wInLambda);
241  return layer >= layerRangeStart(_curLayerRangeIndex) && layer < layerRangeStart(_curLayerRangeIndex+1);
242  }
243 
244 
257  bool IsInLayerRange(double wStart, double wEnd) const
258  {
259  size_t
260  rangeStart = layerRangeStart(_curLayerRangeIndex),
261  rangeEnd = layerRangeStart(_curLayerRangeIndex+1),
262  l1 = WToLayer(wStart);
263  if(l1 >= rangeStart && l1 < rangeEnd)
264  return true;
265  size_t l2 = WToLayer(wEnd);
266  return ((l2 >= rangeStart && l2 < rangeEnd) // l2 is within the range
267  || (l1 < rangeStart && l2 >= rangeEnd) // l1 is before, l2 is after range
268  || (l2 < rangeStart && l1 >= rangeEnd) // l2 is before, l1 is after range
269  );
270  }
271 
277  size_t NPasses() const
278  {
279  return _nPasses;
280  }
281 
282 #ifndef AVOID_CASACORE
283 
300  void AddData(const std::complex<float>* data, size_t dataDescId, double uInM, double vInM, double wInM);
301 #endif
302 
311  void AddDataSample(std::complex<float> sample, double uInLambda, double vInLambda, double wInLambda);
312 
319  void StartInversionPass(size_t passIndex);
320 
327  void FinishInversionPass();
328 
337  void FinalizeImage(double multiplicationFactor, bool correctFFTFactor);
338 
352  void InitializePrediction(const double *image)
353  {
354  initializePrediction(image, _imageData);
355  }
356 
365  void InitializePrediction(const double *real, const double *imaginary)
366  {
367  initializePrediction(real, _imageData);
368  initializePrediction(imaginary, _imageDataImaginary);
369  }
370 
377  void StartPredictionPass(size_t passIndex);
378 
379 #ifndef AVOID_CASACORE
380 
396  void SampleData(std::complex<float>* data, size_t dataDescId, double uInM, double vInM, double wInM);
397 #endif
398 
410  void SampleDataSample(std::complex<double>& value, double uInLambda, double vInLambda, double wInLambda);
411 
422  void SampleDataSample(std::complex<float>& value, double uInLambda, double vInLambda, double wInLambda)
423  {
424  std::complex<double> doubleValue;
425  SampleDataSample(doubleValue, uInLambda, vInLambda, wInLambda);
426  value = doubleValue;
427  }
428 
438  double *RealImage() { return _imageData[0]; }
439 
444  double *ImaginaryImage() { return _imageDataImaginary[0]; }
445 
460  size_t NFFTThreads() const { return _nFFTThreads; }
461 
467  void SetNFFTThreads(size_t nfftThreads) { _nFFTThreads = nfftThreads; }
468 
473  enum GridModeEnum GridMode() const { return _gridMode; }
474 
479  void SetGridMode(enum GridModeEnum mode) {
480  if(mode != _gridMode)
481  {
482  _gridMode = mode;
483  if(_gridMode != NearestNeighbourGridding)
484  makeKernels();
485  }
486  }
487 
494  bool IsComplex() const { return _isComplex; }
495 
501  void SetIsComplex(bool isComplex) { _isComplex = isComplex; }
502 
503  //void SetImageConjugatePart(bool imageConjugatePart) { _imageConjugatePart = imageConjugatePart; }
504 
518  void SetDenormalPhaseCentre(double dl, double dm) { _phaseCentreDL = dl; _phaseCentreDM = dm; }
519 
527  void GetGriddingCorrectionImage(double* image) const;
528 
545  void ReplaceRealImageBuffer(double* newBuffer);
546 
553  void ReplaceImaginaryImageBuffer(double* newBuffer);
554 
563  const std::complex<double>* GetGriddedUVLayer(size_t layerIndex) const
564  {
565  return _layeredUVData[layerIndex];
566  }
567 
575  void GetKaiserBesselKernel(double* kernel, size_t n, bool multiplyWithSinc);
576 
582  size_t Width() const { return _width; }
583 
589  size_t Height() const { return _height; }
590 
596  double PixelSizeX() const { return _pixelSizeX; }
597 
603  double PixelSizeY() const { return _pixelSizeY; }
604 
609  ImageBufferAllocator* Allocator() const { return _imageBufferAllocator; }
610  private:
611  size_t layerRangeStart(size_t layerRangeIndex) const
612  {
613  return (_nWLayers * layerRangeIndex) / _nPasses;
614  }
615  template<bool IsComplexImpl>
616  void projectOnImageAndCorrect(const std::complex<double> *source, double w, size_t threadIndex);
617  template<bool IsComplexImpl>
618  void copyImageToLayerAndInverseCorrect(std::complex<double> *dest, double w);
619  void initializeSqrtLMLookupTable();
620  void initializeSqrtLMLookupTableForSampling();
621  void initializeLayeredUVData(size_t n);
622  void freeLayeredUVData() { initializeLayeredUVData(0); }
623  void fftToImageThreadFunction(boost::mutex *mutex, std::stack<size_t> *tasks, size_t threadIndex);
624  void fftToUVThreadFunction(boost::mutex *mutex, std::stack<size_t> *tasks);
625  void finalizeImage(double multiplicationFactor, std::vector<double*>& dataArray);
626  void initializePrediction(const double *image, std::vector<double*>& dataArray);
627 
628  void makeKernels();
638  void makeKaiserBesselKernel(std::vector<double> &kernel, double alpha, size_t overSamplingFactor, bool withSinc=true);
639 
640  void makeRectangularKernel(std::vector<double> &kernel, size_t overSamplingFactor);
641 
642  double bessel0(double x, double precision);
643  template<bool Inverse>
644  void correctImageForKernel(double *image) const;
645 
646  const size_t _width, _height;
647  const double _pixelSizeX, _pixelSizeY;
648  size_t _nWLayers, _nPasses, _curLayerRangeIndex;
649  double _minW, _maxW, _phaseCentreDL, _phaseCentreDM;
650  bool _isComplex, _imageConjugatePart;
651 #ifndef AVOID_CASACORE
652  MultiBandData _bandData;
653 #endif
654 
655  enum GridModeEnum _gridMode;
656  size_t _overSamplingFactor, _kernelSize;
657  std::vector<double> _1dKernel;
658  std::vector<std::vector<double>> _griddingKernels;
659 
660  std::vector<std::complex<double>*> _layeredUVData;
661  std::vector<double*> _imageData, _imageDataImaginary;
662  std::vector<double> _sqrtLMLookupTable;
663  size_t _nFFTThreads;
664  ImageBufferAllocator* _imageBufferAllocator;
665 };
666 
667 #endif
double PixelSizeX() const
Get angular width of single pixel in radians.
Definition: wstackinggridder.h:596
Definition: wstackinggridder.h:14
void SetDenormalPhaseCentre(double dl, double dm)
Setup the gridder for images with a shifted phase centre.
Definition: wstackinggridder.h:518
size_t NWLayers() const
Number of w-layers, as specified in PrepareWLayers().
Definition: wstackinggridder.h:229
double PixelSizeY() const
Get angular height of single pixel in radians.
Definition: wstackinggridder.h:603
GridModeEnum
Gridding modes that are supported for interpolating samples on the uv-grid.
Definition: wstackinggridder.h:92
Simple method that places/samples a visibility on the nearest uv-cell.
Definition: wstackinggridder.h:95
void SampleDataSample(std::complex< float > &value, double uInLambda, double vInLambda, double wInLambda)
Predict the value of a single visibility.
Definition: wstackinggridder.h:422
void PrepareBand(const MultiBandData &bandData)
Initialize the inversion/prediction stage with a given band.
Definition: wstackinggridder.h:182
double * ImaginaryImage()
Get the imaginary part of a complex image after inversion.
Definition: wstackinggridder.h:444
void SetIsComplex(bool isComplex)
Setup the gridder for real or complex images.
Definition: wstackinggridder.h:501
size_t NPasses() const
Number of passes that are required when not all the w-layers fit in memory at once.
Definition: wstackinggridder.h:277
size_t NFFTThreads() const
Get the number of threads used when performing the FFTs.
Definition: wstackinggridder.h:460
Contains information about a set of bands.
Definition: multibanddata.h:18
size_t Height() const
Get height of image as specified during construction.
Definition: wstackinggridder.h:589
This class grids and/or samples visibilities to/from UV space.
Definition: wstackinggridder.h:82
void SetGridMode(enum GridModeEnum mode)
Set the kernel function and its interpolation method used for gridding.
Definition: wstackinggridder.h:479
const std::complex< double > * GetGriddedUVLayer(size_t layerIndex) const
Retrieve a gridded uv layer.
Definition: wstackinggridder.h:563
void InitializePrediction(const double *real, const double *imaginary)
Complex alternative for InitializePrediction(const double*).
Definition: wstackinggridder.h:365
double LayerToW(size_t layer) const
Calculate the central w-value for the given w-layer index.
Definition: wstackinggridder.h:213
void InitializePrediction(const double *image)
Initialize gridder for prediction and specify image to predict for.
Definition: wstackinggridder.h:352
double * RealImage()
Get the image result of inversion.
Definition: wstackinggridder.h:438
bool IsInLayerRange(double wStart, double wEnd) const
Determine whether any samples within the specified w-value range should be gridded in this pass...
Definition: wstackinggridder.h:257
bool IsComplex() const
Whether the image produced by inversion or used by prediction is complex.
Definition: wstackinggridder.h:494
Interpolate with a Kaiser-Bessel kernel.
Definition: wstackinggridder.h:103
size_t WToLayer(double wInLambda) const
Calculate on which layer this w-value belongs.
Definition: wstackinggridder.h:195
bool IsInLayerRange(double wInLambda) const
Determine whether specified w-value should be gridded in this pass.
Definition: wstackinggridder.h:238
size_t Width() const
Get width of image as specified during construction.
Definition: wstackinggridder.h:582
ImageBufferAllocator * Allocator() const
The ImageBufferAllocator of this gridder.
Definition: wstackinggridder.h:609
void SetNFFTThreads(size_t nfftThreads)
Set the number of threads used to perform the FFTs.
Definition: wstackinggridder.h:467