PURIFY
Next-generation radio interferometric imaging
operators.h
Go to the documentation of this file.
1 #ifndef PURIFY_OPERATORS_H
2 #define PURIFY_OPERATORS_H
3 
4 #include "purify/config.h"
5 #include "purify/types.h"
6 #include <iostream>
7 #include <tuple>
8 #include <type_traits>
9 #include "purify/kernels.h"
10 #include "purify/logging.h"
11 #include "purify/utilities.h"
12 #include "purify/uvw_utilities.h"
15 #include <sopt/chained_operators.h>
16 #include <sopt/linear_transform.h>
17 
18 #include "purify/fly_operators.h"
19 
20 #include <fftw3.h>
21 
22 #ifdef PURIFY_MPI
25 #include "purify/IndexMapping.h"
26 #include "purify/mpi_utilities.h"
27 #include <sopt/mpi/communicator.h>
28 #endif
29 
30 #include "purify/fly_operators.h"
31 
32 namespace purify {
33 
34 namespace details {
35 
37 Sparse<t_complex> init_gridding_matrix_2d(const Vector<t_real> &u, const Vector<t_real> &v,
38  const Vector<t_complex> &weights, const t_uint &imsizey_,
39  const t_uint &imsizex_, const t_real &oversample_ratio,
40  const std::function<t_real(t_real)> kernelu,
41  const std::function<t_real(t_real)> kernelv,
42  const t_uint Ju = 4, const t_uint Jv = 4);
44 Sparse<t_complex> init_gridding_matrix_2d(const Vector<t_real> &u, const Vector<t_real> &v,
45  const Vector<t_real> &w, const Vector<t_complex> &weights,
46  const t_uint imsizey_, const t_uint imsizex_,
47  const t_real oversample_ratio,
48  const std::function<t_real(t_real)> &ftkerneluv,
49  const std::function<t_real(t_real)> &kerneluv,
50  const t_uint Ju, const t_uint Jw, const t_real cellx,
51  const t_real celly, const t_real abs_error,
52  const t_real rel_error, const dde_type dde);
53 
55 template <class STORAGE_INDEX_TYPE = t_int>
57  const t_uint number_of_images, const std::vector<t_int> &image_index, const Vector<t_real> &u,
58  const Vector<t_real> &v, const Vector<t_complex> &weights, const t_uint &imsizey_,
59  const t_uint &imsizex_, const t_real &oversample_ratio,
60  const std::function<t_real(t_real)> kernelu, const std::function<t_real(t_real)> kernelv,
61  const t_uint Ju, const t_uint Jv) {
62  if (std::any_of(image_index.begin(), image_index.end(), [&number_of_images](int index) {
63  return index < 0 or index > (number_of_images - 1);
64  }))
65  throw std::runtime_error("Image index is out of bounds");
66  const t_uint ftsizev_ = std::floor(imsizey_ * oversample_ratio);
67  const t_uint ftsizeu_ = std::floor(imsizex_ * oversample_ratio);
68  const t_uint rows = u.size();
69  const STORAGE_INDEX_TYPE cols = ftsizeu_ * ftsizev_ * number_of_images;
70  if (u.size() != v.size())
71  throw std::runtime_error(
72  "Size of u and v vectors are not the same for creating gridding matrix.");
73 
74  Sparse<t_complex, STORAGE_INDEX_TYPE> interpolation_matrix(rows, cols);
75  interpolation_matrix.reserve(Vector<t_int>::Constant(rows, Ju * Jv));
76 
77  const t_complex I(0, 1);
78  const t_int ju_max = std::min(Ju, ftsizeu_);
79  const t_int jv_max = std::min(Jv, ftsizev_);
80  // If I collapse this for loop there is a crash when using MPI... Sparse<>::insert() doesn't work
81  // right
82 #pragma omp parallel for
83  for (t_int m = 0; m < rows; ++m) {
84  for (t_int ju = 1; ju < ju_max + 1; ++ju) {
85  for (t_int jv = 1; jv < jv_max + 1; ++jv) {
86  const t_real k_u = std::floor(u(m) - ju_max * 0.5);
87  const t_real k_v = std::floor(v(m) - jv_max * 0.5);
88  const t_uint q = utilities::mod(k_u + ju, ftsizeu_);
89  const t_uint p = utilities::mod(k_v + jv, ftsizev_);
90  assert(image_index.at(m) < number_of_images);
91  const STORAGE_INDEX_TYPE index =
92  static_cast<STORAGE_INDEX_TYPE>(utilities::sub2ind(p, q, ftsizev_, ftsizeu_)) +
93  static_cast<STORAGE_INDEX_TYPE>(image_index.at(m)) *
94  static_cast<STORAGE_INDEX_TYPE>(ftsizev_ * ftsizeu_);
95  interpolation_matrix.insert(static_cast<STORAGE_INDEX_TYPE>(m), index) =
96  std::exp(-2 * constant::pi * I * ((k_u + ju) * 0.5 + (k_v + jv) * 0.5)) *
97  kernelu(u(m) - (k_u + ju)) * kernelv(v(m) - (k_v + jv)) * weights(m);
98  }
99  }
100  }
101  return interpolation_matrix;
102 }
104 template <class STORAGE_INDEX_TYPE = t_int>
106  const t_uint number_of_images, const std::vector<t_int> &image_index,
107  const std::vector<t_real> &w_stacks, const Vector<t_real> &u, const Vector<t_real> &v,
108  const Vector<t_real> &w, const Vector<t_complex> &weights, const t_uint imsizey_,
109  const t_uint imsizex_, const t_real oversample_ratio,
110  const std::function<t_real(t_real)> &ftkerneluv, const std::function<t_real(t_real)> &kerneluv,
111  const t_uint Ju, const t_uint Jw, const t_real cellx, const t_real celly,
112  const t_real abs_error, const t_real rel_error, const dde_type dde) {
113  const t_uint ftsizev_ = std::floor(imsizey_ * oversample_ratio);
114  const t_uint ftsizeu_ = std::floor(imsizex_ * oversample_ratio);
115  const t_real du = widefield::pixel_to_lambda(cellx, imsizex_, oversample_ratio);
116  const t_real dv = widefield::pixel_to_lambda(celly, imsizey_, oversample_ratio);
117  PURIFY_HIGH_LOG("du x du: {}, {}", du, dv);
118  if (std::abs(du - dv) > 1e-6)
119  throw std::runtime_error(
120  "Field of view along l and m is not the same, this assumption is required for "
121  "w-projection.");
122  const t_uint rows = u.size();
123  const STORAGE_INDEX_TYPE cols = ftsizeu_ * ftsizev_ * number_of_images;
124  if (u.size() != v.size())
125  throw std::runtime_error(
126  "Size of u and v vectors are not the same for creating gridding matrix.");
127  if (u.size() != w.size())
128  throw std::runtime_error(
129  "Size of u and w vectors are not the same for creating gridding matrix.");
130  if (u.size() != weights.size())
131  throw std::runtime_error(
132  "Size of u and w vectors are not the same for creating gridding matrix.");
133  if (Ju > Jw)
134  throw std::runtime_error(
135  "w kernel size must be at least the size of w=0 kernel, must have Ju <= Jw.");
136  // count gridding coefficients with variable support size
137  Vector<t_int> total_coeffs = Vector<t_int>::Zero(w.size());
138  for (int i = 0; i < w.size(); i++) {
139  const t_int Ju_max = widefield::w_support(w(i) - w_stacks.at(image_index.at(i)), du,
140  static_cast<t_int>(Ju), static_cast<t_int>(Jw));
141  total_coeffs(i) = Ju_max * Ju_max;
142  }
143  const t_real num_of_coeffs = total_coeffs.array().cast<t_real>().sum();
144  PURIFY_HIGH_LOG("Using {} rows (coefficients per a row {}), and memory of {} MegaBytes",
145  total_coeffs.size(), total_coeffs.array().cast<t_real>().mean(),
146  16. * num_of_coeffs / std::pow(10., 6));
147  Sparse<t_complex, STORAGE_INDEX_TYPE> interpolation_matrix(static_cast<STORAGE_INDEX_TYPE>(rows),
148  cols);
149  try {
150  interpolation_matrix.reserve(total_coeffs);
151  } catch (std::bad_alloc e) {
152  throw std::runtime_error(
153  "Not enough memory for coefficients, choose upper limit on support size Jw.");
154  }
155 
156  const t_complex I(0., 1.);
157 
158  const t_uint max_evaluations = 1e8;
159  const t_real relative_error = rel_error;
160  const t_real absolute_error = abs_error;
161 
162  auto const ftkernel_radial = [&](const t_real l) -> t_real { return ftkerneluv(l); };
163 
164  std::int64_t coeffs_done = 0;
165  std::int64_t total = 0;
166 
167 #pragma omp parallel for
168  for (t_int m = 0; m < rows; ++m) {
169  // w_projection convolution setup
170  const t_real w_val = w(m) - w_stacks.at(image_index.at(m));
171  const t_int Ju_max = widefield::w_support(w_val, du, Ju, Jw);
172  t_uint evaluations = 0;
173  const t_int kwu = std::floor(u(m) - Ju_max * 0.5);
174  const t_int kwv = std::floor(v(m) - Ju_max * 0.5);
175 
176  for (t_int ju = 1; ju < Ju_max + 1; ++ju) {
177  for (t_int jv = 1; jv < Ju_max + 1; ++jv) {
178  const t_uint q = utilities::mod(kwu + ju, ftsizeu_);
179  const t_uint p = utilities::mod(kwv + jv, ftsizev_);
180  const STORAGE_INDEX_TYPE index =
181  static_cast<STORAGE_INDEX_TYPE>(utilities::sub2ind(p, q, ftsizev_, ftsizeu_)) +
182  static_cast<STORAGE_INDEX_TYPE>(image_index.at(m)) *
183  static_cast<STORAGE_INDEX_TYPE>(ftsizev_ * ftsizeu_);
184  interpolation_matrix.insert(static_cast<STORAGE_INDEX_TYPE>(m), index) =
185  std::exp(-2 * constant::pi * I * ((kwu + ju) * 0.5 + (kwv + jv) * 0.5)) * weights(m) *
186  ((dde == dde_type::wkernel_radial)
188  (u(m) - (kwu + ju)), (v(m) - (kwv + jv)), w_val, du, oversample_ratio,
189  ftkernel_radial, max_evaluations, absolute_error, relative_error,
190  (du > 1.) ? integration::method::p : integration::method::h, evaluations)
192  (u(m) - (kwu + ju)), (v(m) - (kwv + jv)), w_val, du, dv, oversample_ratio,
193  ftkernel_radial, ftkernel_radial, max_evaluations, absolute_error,
194  relative_error, integration::method::h, evaluations));
195 #pragma omp critical(add_eval)
196  {
197  coeffs_done++;
198  if (num_of_coeffs > 100) {
199  if ((coeffs_done % (static_cast<t_int>(num_of_coeffs / 100)) == 0)) {
201  "w = {}, support = {}x{}, coeffs: {} of {}, {}%", w_val, Ju_max, Ju_max,
202  coeffs_done, num_of_coeffs,
203  static_cast<t_real>(coeffs_done) / static_cast<t_real>(num_of_coeffs) * 100.);
204  }
205  }
206  }
207  }
208  }
209  }
210  interpolation_matrix.makeCompressed();
211  return interpolation_matrix;
212 }
213 
216 Image<t_complex> init_correction2d(const t_real &oversample_ratio, const t_uint &imsizey_,
217  const t_uint &imsizex_,
218  const std::function<t_real(t_real)> ftkernelu,
219  const std::function<t_real(t_real)> ftkernelv,
220  const t_real &w_mean, const t_real &cellx, const t_real &celly);
221 
223 template <class T, class... ARGS>
224 Sparse<t_complex> init_gridding_matrix_2d(const Sparse<T> &mixing_matrix, ARGS &&...args) {
225  if (mixing_matrix.rows() * mixing_matrix.cols() < 2)
226  return init_gridding_matrix_2d(std::forward<ARGS>(args)...);
227  const Sparse<t_complex> G = init_gridding_matrix_2d(std::forward<ARGS>(args)...);
228  if (mixing_matrix.cols() != G.rows())
229  throw std::runtime_error(
230  "The columns of the mixing matrix do not match the number of visibilities");
231  return mixing_matrix * init_gridding_matrix_2d(std::forward<ARGS>(args)...);
232 };
233 } // namespace details
234 
235 namespace operators {
236 
237 #ifdef PURIFY_MPI
239 template <class T, class... ARGS>
240 std::tuple<sopt::OperatorFunction<T>, sopt::OperatorFunction<T>> init_gridding_matrix_2d(
241  const sopt::mpi::Communicator &comm, ARGS &&...args) {
242  Sparse<t_complex> interpolation_matrix_original =
243  details::init_gridding_matrix_2d(std::forward<ARGS>(args)...);
244  const DistributeSparseVector distributor(interpolation_matrix_original, comm);
245  const std::shared_ptr<const Sparse<t_complex>> interpolation_matrix =
246  std::make_shared<const Sparse<t_complex>>(
247  purify::compress_outer(interpolation_matrix_original));
248  const std::shared_ptr<const Sparse<t_complex>> adjoint =
249  std::make_shared<const Sparse<t_complex>>(interpolation_matrix->adjoint());
250 
251  return std::make_tuple(
252  [=](T &output, const T &input) {
253  if (comm.is_root()) {
254  assert(input.size() > 0);
255  distributor.scatter(input, output);
256  } else {
257  distributor.scatter(output);
258  }
259  output = utilities::sparse_multiply_matrix(*interpolation_matrix, output);
260  },
261  [=](T &output, const T &input) {
262  if (not comm.is_root()) {
263  distributor.gather(utilities::sparse_multiply_matrix(*adjoint, input));
264  } else {
265  distributor.gather(utilities::sparse_multiply_matrix(*adjoint, input), output);
266  }
267  });
268 }
269 
271 template <class T, class STORAGE_INDEX_TYPE, class... ARGS>
272 std::tuple<sopt::OperatorFunction<T>, sopt::OperatorFunction<T>> init_gridding_matrix_2d_all_to_all(
273  const sopt::mpi::Communicator &comm, const STORAGE_INDEX_TYPE local_grid_size,
274  const STORAGE_INDEX_TYPE start_index, const t_uint number_of_images,
275  const std::vector<t_int> &image_index, ARGS &&...args) {
276  Sparse<t_complex, STORAGE_INDEX_TYPE> interpolation_matrix_original =
277  details::init_gridding_matrix_2d<STORAGE_INDEX_TYPE>(number_of_images, image_index,
278  std::forward<ARGS>(args)...);
279  const AllToAllSparseVector<STORAGE_INDEX_TYPE> distributor(interpolation_matrix_original,
280  local_grid_size, start_index, comm);
281  const std::shared_ptr<const Sparse<t_complex>> interpolation_matrix =
282  std::make_shared<const Sparse<t_complex>>(
283  purify::compress_outer(interpolation_matrix_original));
284  const std::shared_ptr<const Sparse<t_complex>> adjoint =
285  std::make_shared<const Sparse<t_complex>>(interpolation_matrix->adjoint());
286 
287  return std::make_tuple(
288  [=](T &output, const T &input) {
289  assert(input.size() > 0);
290  distributor.recv_grid(input, output);
291  output = utilities::sparse_multiply_matrix(*interpolation_matrix, output);
292  },
293  [=](T &output, const T &input) {
294  distributor.send_grid(utilities::sparse_multiply_matrix(*adjoint, input), output);
295  });
296 }
297 
299 template <class T>
300 sopt::OperatorFunction<T> init_broadcaster(const sopt::mpi::Communicator &comm) {
301  return [=](T &output, const T &input) { output = comm.broadcast<T>(input).eval(); };
302 }
303 
305 template <class T>
306 sopt::OperatorFunction<T> init_all_sum_all(const sopt::mpi::Communicator &comm) {
307  return [=](T &output, const T &input) { output = comm.all_sum_all<T>(input).eval(); };
308 }
309 #endif
311 template <class T, class... ARGS>
312 std::tuple<sopt::OperatorFunction<T>, sopt::OperatorFunction<T>> init_gridding_matrix_2d(
313  ARGS &&...args) {
314  const std::shared_ptr<const Sparse<t_complex>> interpolation_matrix =
315  std::make_shared<const Sparse<t_complex>>(
316  details::init_gridding_matrix_2d(std::forward<ARGS>(args)...));
317  const std::shared_ptr<const Sparse<t_complex>> adjoint =
318  std::make_shared<const Sparse<t_complex>>(interpolation_matrix->adjoint());
319 
320  return std::make_tuple(
321  [=](T &output, const T &input) {
322  output = utilities::sparse_multiply_matrix(*interpolation_matrix, input);
323  },
324  [=](T &output, const T &input) {
325  output = utilities::sparse_multiply_matrix(*adjoint, input);
326  });
327 }
328 
330 template <class T>
331 std::tuple<sopt::OperatorFunction<T>, sopt::OperatorFunction<T>> init_zero_padding_2d(
332  const Image<typename T::Scalar> &S, const t_real &oversample_ratio) {
333  const t_uint imsizex_ = S.cols();
334  const t_uint imsizey_ = S.rows();
335  const t_uint ftsizeu_ = std::floor(imsizex_ * oversample_ratio);
336  const t_uint ftsizev_ = std::floor(imsizey_ * oversample_ratio);
337  const t_uint x_start = std::floor(ftsizeu_ * 0.5 - imsizex_ * 0.5);
338  const t_uint y_start = std::floor(ftsizev_ * 0.5 - imsizey_ * 0.5);
339  auto direct = [=](T &output, const T &x) {
340  assert(x.size() == imsizex_ * imsizey_);
341  output = Vector<t_complex>::Zero(ftsizeu_ * ftsizev_);
342 #pragma omp parallel for collapse(2)
343  for (t_uint j = 0; j < imsizey_; j++) {
344  for (t_uint i = 0; i < imsizex_; i++) {
345  const t_uint input_index = utilities::sub2ind(j, i, imsizey_, imsizex_);
346  const t_uint output_index =
347  utilities::sub2ind(y_start + j, x_start + i, ftsizev_, ftsizeu_);
348  output(output_index) = S(j, i) * x(input_index);
349  }
350  }
351  };
352  auto indirect = [=](T &output, const T &x) {
353  assert(x.size() == ftsizeu_ * ftsizev_);
354  output = T::Zero(imsizey_ * imsizex_);
355 #pragma omp parallel for collapse(2)
356  for (t_uint j = 0; j < imsizey_; j++) {
357  for (t_uint i = 0; i < imsizex_; i++) {
358  const t_uint output_index = utilities::sub2ind(j, i, imsizey_, imsizex_);
359  const t_uint input_index = utilities::sub2ind(y_start + j, x_start + i, ftsizev_, ftsizeu_);
360  output(output_index) = std::conj(S(j, i)) * x(input_index);
361  }
362  }
363  };
364  return std::make_tuple(direct, indirect);
365 }
366 
367 template <class T>
368 sopt::OperatorFunction<T> init_normalise(const t_real &op_norm) {
369  if (not(op_norm > 0)) throw std::runtime_error("Operator norm is not greater than zero.");
370  return [=](T &output, const T &x) { output = x / op_norm; };
371 }
372 
374 template <class T>
375 std::tuple<sopt::OperatorFunction<T>, sopt::OperatorFunction<T>> init_weights_(
376  const Vector<t_complex> &weights) {
377  PURIFY_DEBUG("Calculating weights: W");
378  auto direct = [=](T &output, const T &x) {
379  assert(weights.size() == x.size());
380  output = weights.array() * x.array();
381  };
382  auto indirect = [=](T &output, const T &x) {
383  assert(weights.size() == x.size());
384  output = weights.conjugate().array() * x.array();
385  };
386  return std::make_tuple(direct, indirect);
387 }
389 enum class fftw_plan { estimate, measure };
391 template <class T>
392 std::tuple<sopt::OperatorFunction<T>, sopt::OperatorFunction<T>> init_FFT_2d(
393  const t_uint &imsizey_, const t_uint &imsizex_, const t_real &oversample_factor_,
394  const fftw_plan fftw_plan_flag_ = fftw_plan::measure) {
395  t_int const ftsizeu_ = std::floor(imsizex_ * oversample_factor_);
396  t_int const ftsizev_ = std::floor(imsizey_ * oversample_factor_);
397  t_int plan_flag = (FFTW_MEASURE | FFTW_PRESERVE_INPUT);
398  switch (fftw_plan_flag_) {
399  case (fftw_plan::measure):
400  plan_flag = (FFTW_MEASURE | FFTW_PRESERVE_INPUT);
401  break;
402  case (fftw_plan::estimate):
403  plan_flag = (FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);
404  break;
405  }
406 
407 #ifdef PURIFY_OPENMP_FFTW
408  PURIFY_LOW_LOG("Using OpenMP threading with FFTW.");
409  fftw_init_threads();
410 #endif
411  Vector<typename T::Scalar> src = Vector<t_complex>::Zero(ftsizev_ * ftsizeu_);
412  Vector<typename T::Scalar> dst = Vector<t_complex>::Zero(ftsizev_ * ftsizeu_);
413  // creating plans
414  const auto del = [](fftw_plan_s *plan) { fftw_destroy_plan(plan); };
415  // fftw plan with threads needs to be used before each fftw_plan is created
416 #ifdef PURIFY_OPENMP_FFTW
417  fftw_plan_with_nthreads(omp_get_max_threads());
418 #endif
419  const std::shared_ptr<fftw_plan_s> m_plan_forward(
420  fftw_plan_dft_2d(ftsizev_, ftsizeu_, reinterpret_cast<fftw_complex *>(src.data()),
421  reinterpret_cast<fftw_complex *>(dst.data()), FFTW_FORWARD, plan_flag),
422  del);
423  // fftw plan with threads needs to be used before each fftw_plan is created
424 #ifdef PURIFY_OPENMP_FFTW
425  fftw_plan_with_nthreads(omp_get_max_threads());
426 #endif
427  const std::shared_ptr<fftw_plan_s> m_plan_inverse(
428  fftw_plan_dft_2d(ftsizev_, ftsizeu_, reinterpret_cast<fftw_complex *>(src.data()),
429  reinterpret_cast<fftw_complex *>(dst.data()), FFTW_BACKWARD, plan_flag),
430  del);
431  auto const direct = [m_plan_forward, ftsizeu_, ftsizev_](T &output, const T &input) {
432  assert(input.size() == ftsizev_ * ftsizeu_);
433  output = Matrix<typename T::Scalar>::Zero(input.rows(), input.cols());
434  fftw_execute_dft(
435  m_plan_forward.get(),
436  const_cast<fftw_complex *>(reinterpret_cast<const fftw_complex *>(input.data())),
437  reinterpret_cast<fftw_complex *>(output.data()));
438  output /= std::sqrt(output.size());
439  };
440  auto const indirect = [m_plan_inverse, ftsizeu_, ftsizev_](T &output, const T &input) {
441  assert(input.size() == ftsizev_ * ftsizeu_);
442  output = Matrix<typename T::Scalar>::Zero(input.rows(), input.cols());
443  fftw_execute_dft(
444  m_plan_inverse.get(),
445  const_cast<fftw_complex *>(reinterpret_cast<const fftw_complex *>(input.data())),
446  reinterpret_cast<fftw_complex *>(output.data()));
447  output /= std::sqrt(output.size());
448  };
449  return std::make_tuple(direct, indirect);
450 }
451 
452 template <class T>
453 std::tuple<sopt::OperatorFunction<T>, sopt::OperatorFunction<T>> base_padding_and_FFT_2d(
454  const std::function<t_real(t_real)> &ftkernelu, const std::function<t_real(t_real)> &ftkernelv,
455  const t_uint &imsizey, const t_uint &imsizex, const t_real &oversample_ratio = 2,
456  const fftw_plan &ft_plan = fftw_plan::measure, const t_real &w_mean = 0,
457  const t_real &cellx = 1, const t_real &celly = 1) {
458  sopt::OperatorFunction<T> directZ, indirectZ;
459  sopt::OperatorFunction<T> directFFT, indirectFFT;
460 
461  const Image<t_complex> S =
462  purify::details::init_correction2d(oversample_ratio, imsizey, imsizex, ftkernelu, ftkernelv,
463  w_mean, cellx, celly) *
464  std::sqrt(imsizex * imsizey) * oversample_ratio;
465  PURIFY_LOW_LOG("Building Measurement Operator: WGFZDB");
467  "Constructing Zero Padding "
468  "and Correction Operator: "
469  "ZDB");
470  PURIFY_MEDIUM_LOG("Image size (width, height): {} x {}", imsizex, imsizey);
471  PURIFY_MEDIUM_LOG("Oversampling Factor: {}", oversample_ratio);
472  std::tie(directZ, indirectZ) = purify::operators::init_zero_padding_2d<T>(S, oversample_ratio);
473  PURIFY_LOW_LOG("Constructing FFT operator: F");
474  switch (ft_plan) {
475  case fftw_plan::measure:
476  PURIFY_MEDIUM_LOG("Measuring Plans...");
477  break;
478  case fftw_plan::estimate:
479  PURIFY_MEDIUM_LOG("Estimating Plans...");
480  break;
481  }
482  std::tie(directFFT, indirectFFT) =
483  purify::operators::init_FFT_2d<T>(imsizey, imsizex, oversample_ratio, ft_plan);
484  auto direct = sopt::chained_operators<T>(directFFT, directZ);
485  auto indirect = sopt::chained_operators<T>(indirectZ, indirectFFT);
486  return std::make_tuple(direct, indirect);
487 }
488 
489 template <class T>
490 std::tuple<sopt::OperatorFunction<T>, sopt::OperatorFunction<T>> base_degrid_operator_2d(
491  const Vector<t_real> &u, const Vector<t_real> &v, const Vector<t_real> &w,
492  const Vector<t_complex> &weights, const t_uint &imsizey, const t_uint &imsizex,
493  const t_real &oversample_ratio = 2, const kernels::kernel kernel = kernels::kernel::kb,
494  const t_uint Ju = 4, const t_uint Jv = 4, const fftw_plan &ft_plan = fftw_plan::measure,
495  const bool w_stacking = false, const t_real &cellx = 1, const t_real &celly = 1,
496  const bool on_the_fly = true) {
497  std::function<t_real(t_real)> kernelu, kernelv, ftkernelu, ftkernelv;
498  std::tie(kernelu, kernelv, ftkernelu, ftkernelv) =
499  purify::create_kernels(kernel, Ju, Jv, imsizey, imsizex, oversample_ratio);
500  sopt::OperatorFunction<T> directFZ, indirectFZ;
501  t_real const w_mean = w_stacking ? w.array().mean() : 0.;
502  std::tie(directFZ, indirectFZ) = base_padding_and_FFT_2d<T>(
503  ftkernelu, ftkernelv, imsizey, imsizex, oversample_ratio, ft_plan, w_mean, cellx, celly);
504  sopt::OperatorFunction<T> directG, indirectG;
505  PURIFY_MEDIUM_LOG("FoV (width, height): {} deg x {} deg", imsizex * cellx / (60. * 60.),
506  imsizey * celly / (60. * 60.));
507  PURIFY_LOW_LOG("Constructing Weighting and Gridding Operators: WG");
508  PURIFY_MEDIUM_LOG("Number of visibilities: {}", u.size());
509  PURIFY_MEDIUM_LOG("Mean, w: {}, +/- {}", w_mean, (w.maxCoeff() - w.minCoeff()) * 0.5);
510  std::tie(directG, indirectG) =
511  (on_the_fly)
512  ? purify::operators::init_on_the_fly_gridding_matrix_2d<T>(
513  u, v, weights, imsizey, imsizex, oversample_ratio, kernelu, Ju, 4e5)
514  : purify::operators::init_gridding_matrix_2d<T>(
515  u, v, weights, imsizey, imsizex, oversample_ratio, kernelv, kernelu, Ju, Jv);
516  auto direct = sopt::chained_operators<T>(directG, directFZ);
517  auto indirect = sopt::chained_operators<T>(indirectFZ, indirectG);
518  PURIFY_LOW_LOG("Finished consturction of Φ.");
519  return std::make_tuple(direct, indirect);
520 }
521 
522 #ifdef PURIFY_MPI
523 template <class T>
524 std::tuple<sopt::OperatorFunction<T>, sopt::OperatorFunction<T>> base_mpi_degrid_operator_2d(
525  const sopt::mpi::Communicator &comm, const Vector<t_real> &u, const Vector<t_real> &v,
526  const Vector<t_real> &w, const Vector<t_complex> &weights, const t_uint &imsizey,
527  const t_uint &imsizex, const t_real oversample_ratio = 2,
528  const kernels::kernel kernel = kernels::kernel::kb, const t_uint Ju = 4, const t_uint Jv = 4,
530  const bool w_stacking = false, const t_real &cellx = 1, const t_real &celly = 1,
531  const bool on_the_fly = true) {
532  std::function<t_real(t_real)> kernelu, kernelv, ftkernelu, ftkernelv;
533  std::tie(kernelu, kernelv, ftkernelu, ftkernelv) =
534  purify::create_kernels(kernel, Ju, Jv, imsizey, imsizex, oversample_ratio);
535  sopt::OperatorFunction<T> directFZ, indirectFZ;
536  std::tie(directFZ, indirectFZ) = base_padding_and_FFT_2d<T>(
537  ftkernelu, ftkernelv, imsizey, imsizex, oversample_ratio, ft_plan, 0., cellx, celly);
538  sopt::OperatorFunction<T> directG, indirectG;
539  if (w_stacking == true)
540  throw std::runtime_error(
541  "w-term correction not supported for this measurement operator or MPI method.");
542  PURIFY_MEDIUM_LOG("FoV (width, height): {} deg x {} deg", imsizex * cellx / (60. * 60.),
543  imsizey * celly / (60. * 60.));
544  PURIFY_LOW_LOG("Constructing Weighting and MPI Gridding Operators: WG");
545  PURIFY_MEDIUM_LOG("Number of visibilities: {}", u.size());
546  std::tie(directG, indirectG) =
547  (on_the_fly)
548  ? purify::operators::init_on_the_fly_gridding_matrix_2d<T>(
549  comm, u, v, weights, imsizey, imsizex, oversample_ratio, kernelu, Ju, 4e5)
550  : purify::operators::init_gridding_matrix_2d<T>(
551  comm, u, v, weights, imsizey, imsizex, oversample_ratio, kernelv, kernelu, Ju, Jv);
552  auto direct = sopt::chained_operators<T>(directG, directFZ);
553  auto indirect = sopt::chained_operators<T>(indirectFZ, indirectG);
554  PURIFY_LOW_LOG("Finished consturction of Φ.");
555  if (comm.is_root())
556  return std::make_tuple(direct, indirect);
557  else
558  return std::make_tuple(directG, indirectG);
559 }
560 template <class T>
561 std::tuple<sopt::OperatorFunction<T>, sopt::OperatorFunction<T>>
562 base_mpi_all_to_all_degrid_operator_2d(
563  const sopt::mpi::Communicator &comm, const std::vector<t_int> &image_index,
564  const std::vector<t_real> &w_stacks, const Vector<t_real> &u, const Vector<t_real> &v,
565  const Vector<t_real> &w, const Vector<t_complex> &weights, const t_uint &imsizey,
566  const t_uint &imsizex, const t_real oversample_ratio = 2,
567  const kernels::kernel kernel = kernels::kernel::kb, const t_uint Ju = 4, const t_uint Jv = 4,
569  const bool w_stacking = false, const t_real cellx = 1, const t_real celly = 1) {
570  const t_uint number_of_images = comm.size();
571  if (std::any_of(image_index.begin(), image_index.end(), [&number_of_images](int index) {
572  return index < 0 or index > (number_of_images - 1);
573  }))
574  throw std::runtime_error("Image index is out of bounds");
575  std::function<t_real(t_real)> kernelu, kernelv, ftkernelu, ftkernelv;
576  std::tie(kernelu, kernelv, ftkernelu, ftkernelv) =
577  purify::create_kernels(kernel, Ju, Jv, imsizey, imsizex, oversample_ratio);
578  sopt::OperatorFunction<T> directFZ, indirectFZ;
579  t_real const w_mean = w_stacking ? w_stacks.at(comm.rank()) : 0.;
580  std::tie(directFZ, indirectFZ) = base_padding_and_FFT_2d<T>(
581  ftkernelu, ftkernelv, imsizey, imsizex, oversample_ratio, ft_plan, w_mean, cellx, celly);
582  sopt::OperatorFunction<T> directG, indirectG;
583  PURIFY_MEDIUM_LOG("FoV (width, height): {} deg x {} deg", imsizex * cellx / (60. * 60.),
584  imsizey * celly / (60. * 60.));
585  PURIFY_LOW_LOG("Constructing Weighting and MPI Gridding Operators: WG");
586  PURIFY_MEDIUM_LOG("Number of visibilities: {}", u.size());
587  const t_int local_grid_size =
588  std::floor(imsizex * oversample_ratio) * std::floor(imsizex * oversample_ratio);
589  std::tie(directG, indirectG) =
590  purify::operators::init_gridding_matrix_2d_all_to_all<T, std::int64_t>(
591  comm, static_cast<std::int64_t>(local_grid_size),
592  static_cast<std::int64_t>(comm.rank()) * static_cast<std::int64_t>(local_grid_size),
593  number_of_images, image_index, u, v, weights, imsizey, imsizex, oversample_ratio, kernelv,
594  kernelu, Ju, Jv);
595  auto direct = sopt::chained_operators<T>(directG, directFZ);
596  auto indirect = sopt::chained_operators<T>(indirectFZ, indirectG);
597  PURIFY_LOW_LOG("Finished consturction of Φ.");
598  return std::make_tuple(direct, indirect);
599 }
600 #endif
601 
602 } // namespace operators
603 
604 namespace measurementoperator {
605 
607 template <class T>
608 std::shared_ptr<sopt::LinearTransform<T>> init_degrid_operator_2d(
609  const Vector<t_real> &u, const Vector<t_real> &v, const Vector<t_real> &w,
610  const Vector<t_complex> &weights, const t_uint &imsizey, const t_uint &imsizex,
611  const t_real &oversample_ratio = 2, const kernels::kernel kernel = kernels::kernel::kb,
612  const t_uint Ju = 4, const t_uint Jv = 4, const bool w_stacking = false,
613  const t_real &cellx = 1, const t_real &celly = 1) {
615  std::array<t_int, 3> N = {0, 1, static_cast<t_int>(imsizey * imsizex)};
616  std::array<t_int, 3> M = {0, 1, static_cast<t_int>(u.size())};
617  sopt::OperatorFunction<T> directDegrid, indirectDegrid;
618  std::tie(directDegrid, indirectDegrid) = purify::operators::base_degrid_operator_2d<T>(
619  u, v, w, weights, imsizey, imsizex, oversample_ratio, kernel, Ju, Jv, ft_plan, w_stacking,
620  cellx, celly);
621  return std::make_shared<sopt::LinearTransform<T>>(directDegrid, M, indirectDegrid, N);
622 }
623 
624 template <class T>
625 std::shared_ptr<sopt::LinearTransform<T>> init_degrid_operator_2d(
626  const utilities::vis_params &uv_vis_input, const t_uint &imsizey, const t_uint &imsizex,
627  const t_real &cell_x, const t_real &cell_y, const t_real &oversample_ratio = 2,
628  const kernels::kernel kernel = kernels::kernel::kb, const t_uint Ju = 4, const t_uint Jv = 4,
629  const bool w_stacking = false) {
630  const auto uv_vis = utilities::convert_to_pixels(uv_vis_input, cell_x, cell_y, imsizex, imsizey,
631  oversample_ratio);
632  return init_degrid_operator_2d<T>(uv_vis.u, uv_vis.v, uv_vis.w, uv_vis.weights, imsizey, imsizex,
633  oversample_ratio, kernel, Ju, Jv, w_stacking, cell_x, cell_y);
634 }
635 
636 #ifdef PURIFY_MPI
638 template <class T>
639 std::shared_ptr<sopt::LinearTransform<T>> init_degrid_operator_2d(
640  const sopt::mpi::Communicator &comm, const Vector<t_real> &u, const Vector<t_real> &v,
641  const Vector<t_real> &w, const Vector<t_complex> &weights, const t_uint &imsizey,
642  const t_uint &imsizex, const t_real &oversample_ratio = 2,
643  const kernels::kernel kernel = kernels::kernel::kb, const t_uint Ju = 4, const t_uint Jv = 4,
644  const bool w_stacking = false, const t_real &cellx = 1, const t_real &celly = 1) {
646  std::array<t_int, 3> N = {0, 1, static_cast<t_int>(imsizey * imsizex)};
647  std::array<t_int, 3> M = {0, 1, static_cast<t_int>(u.size())};
648  sopt::OperatorFunction<T> directDegrid, indirectDegrid;
649  std::tie(directDegrid, indirectDegrid) = purify::operators::base_degrid_operator_2d<T>(
650  u, v, w, weights, imsizey, imsizex, oversample_ratio, kernel, Ju, Jv, ft_plan, w_stacking,
651  cellx, celly);
652  const auto allsumall = purify::operators::init_all_sum_all<T>(comm);
653  auto direct = directDegrid;
654  auto indirect = sopt::chained_operators<T>(allsumall, indirectDegrid);
655  return std::make_shared<sopt::LinearTransform<T>>(direct, M, indirect, N);
656 }
657 
658 template <class T>
659 std::shared_ptr<sopt::LinearTransform<T>> init_degrid_operator_2d(
660  const sopt::mpi::Communicator &comm, const utilities::vis_params &uv_vis_input,
661  const t_uint &imsizey, const t_uint &imsizex, const t_real &cell_x, const t_real &cell_y,
662  const t_real &oversample_ratio = 2, const kernels::kernel kernel = kernels::kernel::kb,
663  const t_uint Ju = 4, const t_uint Jv = 4, const bool w_stacking = false) {
664  const auto uv_vis = utilities::convert_to_pixels(uv_vis_input, cell_x, cell_y, imsizex, imsizey,
665  oversample_ratio);
666  return init_degrid_operator_2d<T>(comm, uv_vis.u, uv_vis.v, uv_vis.w, uv_vis.weights, imsizey,
667  imsizex, oversample_ratio, kernel, Ju, Jv, w_stacking, cell_x,
668  cell_y);
669 }
670 
673 template <class T>
674 std::shared_ptr<sopt::LinearTransform<T>> init_degrid_operator_2d_mpi(
675  const sopt::mpi::Communicator &comm, const Vector<t_real> &u, const Vector<t_real> &v,
676  const Vector<t_real> &w, const Vector<t_complex> &weights, const t_uint &imsizey,
677  const t_uint &imsizex, const t_real &oversample_ratio = 2,
678  const kernels::kernel kernel = kernels::kernel::kb, const t_uint Ju = 4, const t_uint Jv = 4,
679  const bool w_stacking = false, const t_real &cellx = 1, const t_real &celly = 1) {
681  std::array<t_int, 3> N = {0, 1, static_cast<t_int>(imsizey * imsizex)};
682  std::array<t_int, 3> M = {0, 1, static_cast<t_int>(u.size())};
683  auto Broadcast = purify::operators::init_broadcaster<T>(comm);
684  sopt::OperatorFunction<T> directDegrid, indirectDegrid;
685  std::tie(directDegrid, indirectDegrid) = purify::operators::base_mpi_degrid_operator_2d<T>(
686  comm, u, v, w, weights, imsizey, imsizex, oversample_ratio, kernel, Ju, Jv, ft_plan,
687  w_stacking, cellx, celly);
688 
689  auto direct = directDegrid;
690  auto indirect = sopt::chained_operators<T>(Broadcast, indirectDegrid);
691  return std::make_shared<sopt::LinearTransform<T>>(direct, M, indirect, N);
692 }
693 
694 template <class T>
695 std::shared_ptr<sopt::LinearTransform<T>> init_degrid_operator_2d_mpi(
696  const sopt::mpi::Communicator &comm, const utilities::vis_params &uv_vis_input,
697  const t_uint &imsizey, const t_uint &imsizex, const t_real &cell_x, const t_real &cell_y,
698  const t_real oversample_ratio = 2, const kernels::kernel kernel = kernels::kernel::kb,
699  const t_uint Ju = 4, const t_uint Jv = 4, const bool w_stacking = false) {
700  const auto uv_vis = utilities::convert_to_pixels(uv_vis_input, cell_x, cell_y, imsizex, imsizey,
701  oversample_ratio);
702  return init_degrid_operator_2d_mpi<T>(comm, uv_vis.u, uv_vis.v, uv_vis.w, uv_vis.weights, imsizey,
703  imsizex, oversample_ratio, kernel, Ju, Jv, w_stacking,
704  cell_x, cell_y);
705 }
706 
709 template <class T>
710 std::shared_ptr<sopt::LinearTransform<T>> init_degrid_operator_2d_all_to_all(
711  const sopt::mpi::Communicator &comm, const std::vector<t_int> &image_index,
712  const std::vector<t_real> &w_stacks, const Vector<t_real> &u, const Vector<t_real> &v,
713  const Vector<t_real> &w, const Vector<t_complex> &weights, const t_uint imsizey,
714  const t_uint imsizex, const t_real oversample_ratio = 2,
715  const kernels::kernel kernel = kernels::kernel::kb, const t_uint Ju = 4, const t_uint Jv = 4,
716  const bool w_stacking = false, const t_real cellx = 1, const t_real celly = 1) {
718  std::array<t_int, 3> N = {0, 1, static_cast<t_int>(imsizey * imsizex)};
719  std::array<t_int, 3> M = {0, 1, static_cast<t_int>(u.size())};
720  auto Broadcast = purify::operators::init_broadcaster<T>(comm);
721  sopt::OperatorFunction<T> directDegrid, indirectDegrid;
722  std::tie(directDegrid, indirectDegrid) =
723  purify::operators::base_mpi_all_to_all_degrid_operator_2d<T>(
724  comm, image_index, w_stacks, u, v, w, weights, imsizey, imsizex, oversample_ratio, kernel,
725  Ju, Jv, ft_plan, w_stacking, cellx, celly);
726 
727  const auto allsumall = purify::operators::init_all_sum_all<T>(comm);
728  auto direct = directDegrid;
729  auto indirect = sopt::chained_operators<T>(allsumall, indirectDegrid);
730  return std::make_shared<sopt::LinearTransform<T>>(direct, M, indirect, N);
731 }
732 
733 template <class T>
734 std::shared_ptr<sopt::LinearTransform<T>> init_degrid_operator_2d_all_to_all(
735  const sopt::mpi::Communicator &comm, const std::vector<t_int> &image_index,
736  const std::vector<t_real> &w_stacks, const utilities::vis_params &uv_vis_input,
737  const t_uint imsizey, const t_uint imsizex, const t_real cell_x, const t_real cell_y,
738  const t_real oversample_ratio = 2, const kernels::kernel kernel = kernels::kernel::kb,
739  const t_uint Ju = 4, const t_uint Jv = 4, const bool w_stacking = false) {
740  const auto uv_vis = utilities::convert_to_pixels(uv_vis_input, cell_x, cell_y, imsizex, imsizey,
741  oversample_ratio);
742  return init_degrid_operator_2d_all_to_all<T>(
743  comm, image_index, w_stacks, uv_vis.u, uv_vis.v, uv_vis.w, uv_vis.weights, imsizey, imsizex,
744  oversample_ratio, kernel, Ju, Jv, w_stacking, cell_x, cell_y);
745 }
746 #endif
747 
748 } // namespace measurementoperator
749 
750 }; // namespace purify
751 #endif
#define PURIFY_LOW_LOG(...)
Low priority message.
Definition: logging.h:207
#define PURIFY_HIGH_LOG(...)
High priority message.
Definition: logging.h:203
#define PURIFY_DEBUG(...)
\macro Output some debugging
Definition: logging.h:197
#define PURIFY_MEDIUM_LOG(...)
Medium priority message.
Definition: logging.h:205
const std::vector< t_real > u
data for u coordinate
Definition: operators.cc:18
const std::vector< t_real > v
data for v coordinate
Definition: operators.cc:20
const t_real pi
mathematical constant
Definition: types.h:70
Image< t_complex > init_correction2d(const t_real &oversample_ratio, const t_uint &imsizey_, const t_uint &imsizex_, const std::function< t_real(t_real)> ftkernelu, const std::function< t_real(t_real)> ftkernelv, const t_real &w_mean, const t_real &cellx, const t_real &celly)
Definition: operators.cc:47
Sparse< t_complex > init_gridding_matrix_2d(const Vector< t_real > &u, const Vector< t_real > &v, const Vector< t_complex > &weights, const t_uint &imsizey_, const t_uint &imsizex_, const t_real &oversample_ratio, const std::function< t_real(t_real)> kernelu, const std::function< t_real(t_real)> kernelv, const t_uint Ju, const t_uint Jv)
Construct gridding matrix.
Definition: operators.cc:7
std::shared_ptr< sopt::LinearTransform< T > > init_degrid_operator_2d(const Vector< t_real > &u, const Vector< t_real > &v, const Vector< t_real > &w, const Vector< t_complex > &weights, const t_uint &imsizey, const t_uint &imsizex, const t_real &oversample_ratio=2, const kernels::kernel kernel=kernels::kernel::kb, const t_uint Ju=4, const t_uint Jv=4, const bool w_stacking=false, const t_real &cellx=1, const t_real &celly=1)
Returns linear transform that is the standard degridding operator.
Definition: operators.h:608
std::tuple< sopt::OperatorFunction< T >, sopt::OperatorFunction< T > > init_weights_(const Vector< t_complex > &weights)
Construsts zero padding operator.
Definition: operators.h:375
std::tuple< sopt::OperatorFunction< T >, sopt::OperatorFunction< T > > init_zero_padding_2d(const Image< typename T::Scalar > &S, const t_real &oversample_ratio)
Construsts zero padding operator.
Definition: operators.h:331
std::tuple< sopt::OperatorFunction< T >, sopt::OperatorFunction< T > > init_gridding_matrix_2d(ARGS &&...args)
constructs lambdas that apply degridding matrix with adjoint
Definition: operators.h:312
fftw_plan
enum for fftw plans
Definition: operators.h:389
std::tuple< sopt::OperatorFunction< T >, sopt::OperatorFunction< T > > base_padding_and_FFT_2d(const std::function< t_real(t_real)> &ftkernelu, const std::function< t_real(t_real)> &ftkernelv, const t_uint &imsizey, const t_uint &imsizex, const t_real &oversample_ratio=2, const fftw_plan &ft_plan=fftw_plan::measure, const t_real &w_mean=0, const t_real &cellx=1, const t_real &celly=1)
Definition: operators.h:453
sopt::OperatorFunction< T > init_normalise(const t_real &op_norm)
Definition: operators.h:368
std::tuple< sopt::OperatorFunction< T >, sopt::OperatorFunction< T > > init_FFT_2d(const t_uint &imsizey_, const t_uint &imsizex_, const t_real &oversample_factor_, const fftw_plan fftw_plan_flag_=fftw_plan::measure)
Construsts FFT operator.
Definition: operators.h:392
std::tuple< sopt::OperatorFunction< T >, sopt::OperatorFunction< T > > base_degrid_operator_2d(const Vector< t_real > &u, const Vector< t_real > &v, const Vector< t_real > &w, const Vector< t_complex > &weights, const t_uint &imsizey, const t_uint &imsizex, const t_real &oversample_ratio=2, const kernels::kernel kernel=kernels::kernel::kb, const t_uint Ju=4, const t_uint Jv=4, const fftw_plan &ft_plan=fftw_plan::measure, const bool w_stacking=false, const t_real &cellx=1, const t_real &celly=1, const bool on_the_fly=true)
Definition: operators.h:490
t_complex exact_w_projection_integration_1d(const t_real u, const t_real v, const t_real w, const t_real du, const t_real oversample_ratio, const std::function< t_complex(t_real)> &ftkerneluv, const t_uint &max_evaluations, const t_real &absolute_error, const t_real &relative_error, const integration::method method, t_uint &evaluations)
t_complex exact_w_projection_integration(const t_real u, const t_real v, const t_real w, const t_real du, const t_real dv, const t_real oversample_ratio, const std::function< t_complex(t_real)> &ftkernelu, const std::function< t_complex(t_real)> &ftkernelv, const t_uint &max_evaluations, const t_real &absolute_error, const t_real &relative_error, const integration::method method, t_uint &evaluations)
numerical integration of chirp and kernel in image domain
std::enable_if< std::is_same< typename T0::Scalar, typename T1::Scalar >::value and T0::IsRowMajor, Vector< typename T0::Scalar > >::type sparse_multiply_matrix(const Eigen::SparseMatrixBase< T0 > &M, const Eigen::MatrixBase< T1 > &x)
Parallel multiplication with a sparse matrix and vector.
Definition: utilities.h:67
utilities::vis_params w_stacking(utilities::vis_params const &params, sopt::mpi::Communicator const &comm, const t_int iters, const std::function< t_real(t_real)> &cost, const t_real k_means_rel_diff)
utilities::vis_params convert_to_pixels(const utilities::vis_params &uv_vis, const t_real cell_x, const t_real cell_y, const t_real imsizex, const t_real imsizey, const t_real oversample_ratio)
Converts u and v coordaintes to units of pixels.
t_int sub2ind(const t_int &row, const t_int &col, const t_int &rows, const t_int &cols)
Converts from subscript to index for matrix.
Definition: utilities.cc:12
t_real mod(const t_real &x, const t_real &y)
Mod function modified to wrap circularly for negative numbers.
Definition: utilities.cc:41
t_int w_support(const t_real w, const t_real du, const t_int min, const t_int max)
estimate support size of w given u resolution du
t_real pixel_to_lambda(const t_real cell, const t_uint imsize, const t_real oversample_ratio)
return factors to convert between arcsecond pixel size image space and lambda for uv space
std::tuple< std::function< t_real(t_real)>, std::function< t_real(t_real)>, std::function< t_real(t_real)>, std::function< t_real(t_real)> > create_kernels(const kernels::kernel kernel_name_, const t_uint Ju_, const t_uint Jv_, const t_real imsizey_, const t_real imsizex_, const t_real oversample_ratio)
Definition: kernels.cc:249
dde_type
Types of DDEs in purify.
Definition: types.h:59
Eigen::SparseMatrix< T, Eigen::RowMajor, I > Sparse
A matrix of a given type.
Definition: types.h:40
Sparse< typename T0::Scalar > compress_outer(T0 const &matrix)
Indices of non empty outer indices.
Definition: IndexMapping.h:71