1 #ifndef PURIFY_OPERATORS_H
2 #define PURIFY_OPERATORS_H
4 #include "purify/config.h"
15 #include <sopt/chained_operators.h>
16 #include <sopt/linear_transform.h>
27 #include <sopt/mpi/communicator.h>
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);
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);
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);
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.");
75 interpolation_matrix.reserve(Vector<t_int>::Constant(rows, Ju * Jv));
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_);
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);
90 assert(image_index.at(m) < number_of_images);
91 const STORAGE_INDEX_TYPE index =
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);
101 return interpolation_matrix;
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);
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 "
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.");
134 throw std::runtime_error(
135 "w kernel size must be at least the size of w=0 kernel, must have Ju <= Jw.");
137 Vector<t_int> total_coeffs = Vector<t_int>::Zero(w.size());
138 for (
int i = 0; i < w.size(); i++) {
140 static_cast<t_int
>(Ju),
static_cast<t_int
>(Jw));
141 total_coeffs(i) = Ju_max * Ju_max;
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));
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.");
156 const t_complex
I(0., 1.);
158 const t_uint max_evaluations = 1e8;
159 const t_real relative_error = rel_error;
160 const t_real absolute_error = abs_error;
162 auto const ftkernel_radial = [&](
const t_real l) -> t_real {
return ftkerneluv(l); };
164 std::int64_t coeffs_done = 0;
165 std::int64_t total = 0;
167 #pragma omp parallel for
168 for (t_int m = 0; m < rows; ++m) {
170 const t_real w_val = w(m) - w_stacks.at(image_index.at(m));
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);
176 for (t_int ju = 1; ju < Ju_max + 1; ++ju) {
177 for (t_int jv = 1; jv < Ju_max + 1; ++jv) {
180 const STORAGE_INDEX_TYPE index =
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) *
188 (
u(m) - (kwu + ju)), (
v(m) - (kwv + jv)), w_val, du, oversample_ratio,
189 ftkernel_radial, max_evaluations, absolute_error, relative_error,
192 (
u(m) - (kwu + ju)), (
v(m) - (kwv + jv)), w_val, du, dv, oversample_ratio,
193 ftkernel_radial, ftkernel_radial, max_evaluations, absolute_error,
195 #pragma omp critical(add_eval)
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.);
210 interpolation_matrix.makeCompressed();
211 return interpolation_matrix;
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);
223 template <
class T,
class... ARGS>
225 if (mixing_matrix.rows() * mixing_matrix.cols() < 2)
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");
235 namespace operators {
239 template <
class T,
class... ARGS>
241 const sopt::mpi::Communicator &comm, ARGS &&...args) {
242 Sparse<t_complex> interpolation_matrix_original =
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>>(
248 const std::shared_ptr<const Sparse<t_complex>> adjoint =
249 std::make_shared<const Sparse<t_complex>>(interpolation_matrix->adjoint());
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);
257 distributor.scatter(output);
261 [=](T &output,
const T &input) {
262 if (not comm.is_root()) {
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>>(
284 const std::shared_ptr<const Sparse<t_complex>> adjoint =
285 std::make_shared<const Sparse<t_complex>>(interpolation_matrix->adjoint());
287 return std::make_tuple(
288 [=](T &output,
const T &input) {
289 assert(input.size() > 0);
290 distributor.recv_grid(input, output);
293 [=](T &output,
const T &input) {
300 sopt::OperatorFunction<T> init_broadcaster(
const sopt::mpi::Communicator &comm) {
301 return [=](T &output,
const T &input) { output = comm.broadcast<T>(input).eval(); };
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(); };
311 template <
class T,
class... ARGS>
314 const std::shared_ptr<const Sparse<t_complex>> interpolation_matrix =
315 std::make_shared<const Sparse<t_complex>>(
317 const std::shared_ptr<const Sparse<t_complex>> adjoint =
318 std::make_shared<const Sparse<t_complex>>(interpolation_matrix->adjoint());
320 return std::make_tuple(
321 [=](T &output,
const T &input) {
324 [=](T &output,
const T &input) {
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++) {
346 const t_uint output_index =
348 output(output_index) = S(j, i) * x(input_index);
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++) {
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);
364 return std::make_tuple(direct, indirect);
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; };
375 std::tuple<sopt::OperatorFunction<T>, sopt::OperatorFunction<T>>
init_weights_(
376 const Vector<t_complex> &weights) {
378 auto direct = [=](T &output,
const T &x) {
379 assert(weights.size() == x.size());
380 output = weights.array() * x.array();
382 auto indirect = [=](T &output,
const T &x) {
383 assert(weights.size() == x.size());
384 output = weights.conjugate().array() * x.array();
386 return std::make_tuple(direct, indirect);
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_,
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_) {
400 plan_flag = (FFTW_MEASURE | FFTW_PRESERVE_INPUT);
403 plan_flag = (FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);
407 #ifdef PURIFY_OPENMP_FFTW
411 Vector<typename T::Scalar> src = Vector<t_complex>::Zero(ftsizev_ * ftsizeu_);
412 Vector<typename T::Scalar> dst = Vector<t_complex>::Zero(ftsizev_ * ftsizeu_);
414 const auto del = [](fftw_plan_s *
plan) { fftw_destroy_plan(
plan); };
416 #ifdef PURIFY_OPENMP_FFTW
417 fftw_plan_with_nthreads(omp_get_max_threads());
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),
424 #ifdef PURIFY_OPENMP_FFTW
425 fftw_plan_with_nthreads(omp_get_max_threads());
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),
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());
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());
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());
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());
449 return std::make_tuple(direct, indirect);
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,
457 const t_real &cellx = 1,
const t_real &celly = 1) {
458 sopt::OperatorFunction<T> directZ, indirectZ;
459 sopt::OperatorFunction<T> directFFT, indirectFFT;
461 const Image<t_complex> S =
463 w_mean, cellx, celly) *
464 std::sqrt(imsizex * imsizey) * oversample_ratio;
467 "Constructing Zero Padding "
468 "and Correction Operator: "
472 std::tie(directZ, indirectZ) = purify::operators::init_zero_padding_2d<T>(S, oversample_ratio);
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);
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,
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) =
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");
509 PURIFY_MEDIUM_LOG(
"Mean, w: {}, +/- {}", w_mean, (w.maxCoeff() - w.minCoeff()) * 0.5);
510 std::tie(directG, indirectG) =
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);
519 return std::make_tuple(direct, indirect);
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,
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) =
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;
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");
546 std::tie(directG, indirectG) =
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);
556 return std::make_tuple(direct, indirect);
558 return std::make_tuple(directG, indirectG);
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,
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);
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) =
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");
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,
595 auto direct = sopt::chained_operators<T>(directG, directFZ);
596 auto indirect = sopt::chained_operators<T>(indirectFZ, indirectG);
598 return std::make_tuple(direct, indirect);
604 namespace measurementoperator {
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,
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,
621 return std::make_shared<sopt::LinearTransform<T>>(directDegrid, M, indirectDegrid, N);
627 const t_real &cell_x,
const t_real &cell_y,
const t_real &oversample_ratio = 2,
632 return init_degrid_operator_2d<T>(uv_vis.u, uv_vis.v, uv_vis.w, uv_vis.weights, imsizey, imsizex,
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,
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,
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);
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,
663 const t_uint Ju = 4,
const t_uint Jv = 4,
const bool w_stacking =
false) {
666 return init_degrid_operator_2d<T>(comm, uv_vis.u, uv_vis.v, uv_vis.w, uv_vis.weights, imsizey,
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,
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,
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);
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,
699 const t_uint Ju = 4,
const t_uint Jv = 4,
const bool w_stacking =
false) {
702 return init_degrid_operator_2d_mpi<T>(comm, uv_vis.u, uv_vis.v, uv_vis.w, uv_vis.weights, imsizey,
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,
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,
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);
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,
739 const t_uint Ju = 4,
const t_uint Jv = 4,
const bool w_stacking =
false) {
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,
#define PURIFY_LOW_LOG(...)
Low priority message.
#define PURIFY_HIGH_LOG(...)
High priority message.
#define PURIFY_DEBUG(...)
\macro Output some debugging
#define PURIFY_MEDIUM_LOG(...)
Medium priority message.
const std::vector< t_real > u
data for u coordinate
const std::vector< t_real > v
data for v coordinate
const t_real pi
mathematical constant
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)
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.
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.
std::tuple< sopt::OperatorFunction< T >, sopt::OperatorFunction< T > > init_weights_(const Vector< t_complex > &weights)
Construsts zero padding operator.
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.
std::tuple< sopt::OperatorFunction< T >, sopt::OperatorFunction< T > > init_gridding_matrix_2d(ARGS &&...args)
constructs lambdas that apply degridding matrix with adjoint
fftw_plan
enum for fftw plans
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)
sopt::OperatorFunction< T > init_normalise(const t_real &op_norm)
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.
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)
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.
utilities::vis_params w_stacking(utilities::vis_params const ¶ms, 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.
t_real mod(const t_real &x, const t_real &y)
Mod function modified to wrap circularly for negative numbers.
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)
dde_type
Types of DDEs in purify.
Eigen::SparseMatrix< T, Eigen::RowMajor, I > Sparse
A matrix of a given type.
Sparse< typename T0::Scalar > compress_outer(T0 const &matrix)
Indices of non empty outer indices.