19 const t_uint M = 1000;
20 const t_real oversample_ratio = 2;
21 const t_uint imsizex = 128;
22 const t_uint imsizey = 128;
23 const t_uint N = imsizex * imsizey;
24 const t_uint ftsizev = std::floor(imsizey * oversample_ratio);
25 const t_uint ftsizeu = std::floor(imsizex * oversample_ratio);
28 const t_uint power_iters = 100;
29 const t_real power_tol = 1e-9;
31 const std::string& weighting_type =
"natural";
33 auto u = Vector<t_real>::Random(M);
34 auto v = Vector<t_real>::Random(M);
39 uv_vis.
weights = Vector<t_complex>::Random(M);
40 uv_vis.
vis = Vector<t_complex>::Random(M);
41 uv_vis.
units = utilities::vis_units::pixels;
42 std::function<t_real(t_real)> kbu, kbv, ftkbu, ftkbv;
43 std::tie(kbu, kbv, ftkbu, ftkbv) =
46 const Vector<t_complex> input = Vector<t_complex>::Random(ftsizev * ftsizeu);
47 Vector<t_complex> output;
48 Vector<t_complex> new_input;
49 sopt::OperatorFunction<af::array> direct_gpu_fft, indirect_gpu_fft;
50 std::tie(direct_gpu_fft, indirect_gpu_fft) =
51 gpu::operators::init_af_FFT_2d(imsizey, imsizex, oversample_ratio);
52 sopt::OperatorFunction<Vector<t_complex>> fft =
53 gpu::host_wrapper(direct_gpu_fft, input.size(), input.size());
54 sopt::OperatorFunction<Vector<t_complex>> ifft =
55 gpu::host_wrapper(indirect_gpu_fft, input.size(), input.size());
57 ifft(new_input, output);
58 CAPTURE(input.transpose().array() / new_input.transpose().array());
59 CHECK(input.isApprox(new_input, 1e-6));
60 sopt::OperatorFunction<Vector<t_complex>> direct_fft, indirect_fft;
61 std::tie(direct_fft, indirect_fft) =
62 operators::init_FFT_2d<Vector<t_complex>>(imsizey, imsizex, oversample_ratio);
63 const Vector<t_complex>
direct_input = Vector<t_complex>::Random(ftsizev * ftsizeu);
64 const Vector<t_complex>
indirect_input = Vector<t_complex>::Random(ftsizev * ftsizeu);
65 Vector<t_complex> output_new;
66 Vector<t_complex> output_old;
69 CHECK(output_old.isApprox(output_new, 1e-6));
72 CHECK(output_old.isApprox(output_new, 1e-6));
75 sopt::OperatorFunction<af::array> direct_gpu_G, indirect_gpu_G;
76 std::tie(direct_gpu_G, indirect_gpu_G) = gpu::operators::init_af_gridding_matrix_2d(
77 uv_vis.
u, uv_vis.
v, Vector<t_complex>::Constant(M, 1.), imsizey, imsizex, oversample_ratio,
79 const sopt::OperatorFunction<Vector<t_complex>> gpu_direct_G =
80 gpu::host_wrapper(direct_gpu_G, ftsizeu * ftsizev, M);
81 const sopt::OperatorFunction<Vector<t_complex>> gpu_indirect_G =
82 gpu::host_wrapper(indirect_gpu_G, M, ftsizeu * ftsizev);
83 sopt::OperatorFunction<Vector<t_complex>> direct_G, indirect_G;
84 std::tie(direct_G, indirect_G) = operators::init_gridding_matrix_2d<Vector<t_complex>>(
85 uv_vis.
u, uv_vis.
v, Vector<t_complex>::Constant(M, 1.), imsizey, imsizex, oversample_ratio,
87 const Vector<t_complex>
direct_input = Vector<t_complex>::Random(ftsizev * ftsizeu);
88 const Vector<t_complex>
indirect_input = Vector<t_complex>::Random(M);
89 Vector<t_complex> output_new;
90 Vector<t_complex> output_old;
93 CHECK(output_new.isApprox(output_old, 1e-6));
96 CHECK(output_new.isApprox(output_old, 1e-6));
98 SECTION(
"Zero Padding") {
99 const Image<t_complex> S =
101 CHECK(imsizex == S.cols());
102 CHECK(imsizey == S.rows());
103 sopt::OperatorFunction<Vector<t_complex>> directZ, indirectZ;
104 std::tie(directZ, indirectZ) =
105 operators::init_zero_padding_2d<Vector<t_complex>>(S, oversample_ratio);
106 sopt::OperatorFunction<af::array> directZgpu, indirectZgpu;
107 std::tie(directZgpu, indirectZgpu) =
108 gpu::operators::init_af_zero_padding_2d(S.cast<
t_complexf>(), oversample_ratio);
109 sopt::OperatorFunction<Vector<t_complex>> directZ_gpu =
110 gpu::host_wrapper(directZgpu, imsizex * imsizey, ftsizeu * ftsizev);
111 sopt::OperatorFunction<Vector<t_complex>> indirectZ_gpu =
112 gpu::host_wrapper(indirectZgpu, ftsizeu * ftsizev, imsizex * imsizey);
113 const Vector<t_complex>
direct_input = Vector<t_complex>::Random(imsizex * imsizey);
114 Vector<t_complex> direct_output_old;
115 Vector<t_complex> direct_output_new;
118 CHECK(direct_output_new.size() == ftsizeu * ftsizev);
119 CHECK(direct_output_old.isApprox(direct_output_new, 1e-6));
120 const Vector<t_complex>
indirect_input = Vector<t_complex>::Random(ftsizeu * ftsizev);
121 Vector<t_complex> indirect_output_old;
122 Vector<t_complex> indirect_output_new;
125 CHECK(indirect_output_new.size() == imsizex * imsizey);
126 CHECK(indirect_output_old.isApprox(indirect_output_new, 1e-6));
128 SECTION(
"Serial Operator") {
129 const auto measure_op = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
131 uv_vis.
u, uv_vis.
v, uv_vis.
w, uv_vis.
weights, imsizey, imsizex, oversample_ratio,
133 power_iters, power_tol, Vector<t_complex>::Random(imsizex * imsizey)));
135 const auto measure_op_gpu = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
137 uv_vis.
weights, imsizey, imsizex,
138 oversample_ratio,
kernel, Ju, Jv),
139 power_iters, power_tol, Vector<t_complex>::Random(imsizex * imsizey)));
140 const Vector<t_complex>
direct_input = Vector<t_complex>::Random(imsizex * imsizey);
141 const Vector<t_complex> direct_output = *measure_op_gpu *
direct_input;
142 CHECK(direct_output.size() == M);
143 const Vector<t_complex>
indirect_input = Vector<t_complex>::Random(M);
144 const Vector<t_complex> indirect_output = measure_op_gpu->adjoint() *
indirect_input;
145 CHECK(indirect_output.size() == imsizex * imsizey);
146 SECTION(
"Power Method") {
147 auto op_norm = std::get<0>(sopt::algorithm::power_method<Vector<t_complex>>(
148 *measure_op, power_iters, power_tol, Vector<t_complex>::Random(imsizex * imsizey)));
149 CHECK(std::abs(op_norm - 1.) < power_tol);
152 const Vector<t_complex> input = Vector<t_complex>::Random(imsizex * imsizey);
153 const Vector<t_complex> expected_output = *measure_op * input;
154 const Vector<t_complex> actual_output = *measure_op_gpu * input;
155 CHECK(expected_output.size() == actual_output.size());
156 CHECK(actual_output.isApprox(expected_output, 1e-4));
159 const Vector<t_complex> input = Vector<t_complex>::Random(M);
160 const Vector<t_complex> expected_output = measure_op->adjoint() * input;
161 const Vector<t_complex> actual_output = measure_op_gpu->adjoint() * input;
162 CHECK(expected_output.size() == actual_output.size());
163 CHECK(actual_output.isApprox(expected_output, 1e-4));
#define CHECK(CONDITION, ERROR)
const std::vector< t_complex > indirect_input
data for gridding input
const std::vector< t_real > u
data for u coordinate
const std::vector< t_real > v
data for v coordinate
const std::vector< t_complex > direct_input
data for degridding input
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)
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::complex< float > t_complexf
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)
Vector< t_complex > weights