PURIFY
Next-generation radio interferometric imaging
Functions
mpi_measurement_operator.cc File Reference
#include <iomanip>
#include <random>
#include "catch2/catch_all.hpp"
#include "purify/distribute.h"
#include "purify/logging.h"
#include "purify/mpi_utilities.h"
#include "purify/operators.h"
#include "purify/utilities.h"
#include "purify/wproj_operators.h"
#include <sopt/mpi/communicator.h>
#include <sopt/power_method.h>
+ Include dependency graph for mpi_measurement_operator.cc:

Go to the source code of this file.

Functions

 TEST_CASE ("Serial vs Distributed Operator")
 
 TEST_CASE ("Serial vs Distributed Fourier Grid Operator")
 
 TEST_CASE ("Serial vs Distributed Fourier Grid Operator weighted")
 
 TEST_CASE ("Serial vs All to All Fourier Grid Operator weighted")
 
 TEST_CASE ("Standard vs All to All stacking")
 
 TEST_CASE ("Standard vs All to All wproj")
 
 TEST_CASE ("Serial vs Distributed Operator Radial WProjection")
 

Function Documentation

◆ TEST_CASE() [1/7]

TEST_CASE ( "Serial vs All to All Fourier Grid Operator weighted"  )

Definition at line 219 of file mpi_measurement_operator.cc.

219  {
220  // sopt::logging::set_level("debug");
221  // purify::logging::set_level("debug");
222  auto const world = sopt::mpi::Communicator::World();
223 
224  auto const N = 1000;
225  auto uv_serial = utilities::random_sample_density(N, 0, constant::pi / 3);
226  uv_serial.u = world.broadcast(uv_serial.u);
227  uv_serial.v = world.broadcast(uv_serial.v);
228  uv_serial.w = world.broadcast(uv_serial.w);
229  uv_serial.units = utilities::vis_units::radians;
230  uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
231  uv_serial.weights =
232  world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
233 
234  utilities::vis_params uv_mpi;
235  if (world.is_root()) {
236  auto const order =
237  distribute::distribute_measurements(uv_serial, world, distribute::plan::radial);
238  uv_mpi = utilities::regroup_and_scatter(uv_serial, order, world);
239  } else
240  uv_mpi = utilities::scatter_visibilities(world);
241 
242  auto const over_sample = 2;
243  auto const J = 4;
244  auto const kernel = kernels::kernel::kb;
245  auto const width = 128;
246  auto const height = 128;
247  const Vector<t_complex> power_init =
248  world.broadcast(Vector<t_complex>::Random(height * width).eval());
249  const auto op_serial = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
251  uv_serial.u, uv_serial.v, uv_serial.w, uv_serial.weights, height, width, over_sample),
252  100, 1e-4, power_init));
253  // First create an instance of an engine.
254  std::random_device rnd_device;
255  // Specify the engine and distribution.
256  std::mt19937 mersenne_engine(rnd_device()); // Generates random integers
257  std::uniform_int_distribution<t_int> dist(0, world.size() - 1);
258 
259  auto gen = [&dist, &mersenne_engine]() { return dist(mersenne_engine); };
260  std::vector<t_int> image_index(uv_mpi.size());
261  std::generate(image_index.begin(), image_index.end(), gen);
262  std::vector<t_real> w_stacks(world.size(), 0.);
263 
264  const auto op = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
265  purify::measurementoperator::init_degrid_operator_2d_all_to_all<Vector<t_complex>>(
266  world, image_index, w_stacks, uv_mpi.u, uv_mpi.v, uv_mpi.w, uv_mpi.weights, height, width,
267  over_sample),
268  100, 1e-4, power_init));
269 
270  if (world.size() == 1) {
271  REQUIRE(uv_serial.u.isApprox(uv_mpi.u));
272  CHECK(uv_serial.v.isApprox(uv_mpi.v));
273  CHECK(uv_serial.weights.isApprox(uv_mpi.weights));
274  }
275  SECTION("Degridding") {
276  Vector<t_complex> const image =
277  world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
278 
279  auto uv_degrid = uv_serial;
280  if (world.is_root()) {
281  uv_degrid.vis = *op_serial * image;
282  auto const order =
283  distribute::distribute_measurements(uv_degrid, world, distribute::plan::radial);
284  uv_degrid = utilities::regroup_and_scatter(uv_degrid, order, world);
285  } else
286  uv_degrid = utilities::scatter_visibilities(world);
287  Vector<t_complex> const degridded = *op * image;
288  REQUIRE(degridded.size() == uv_degrid.vis.size());
289  REQUIRE(degridded.isApprox(uv_degrid.vis, 1e-4));
290  }
291  SECTION("Gridding") {
292  Vector<t_complex> const gridded = op->adjoint() * uv_mpi.vis;
293  Vector<t_complex> const gridded_serial = op_serial->adjoint() * uv_serial.vis;
294  REQUIRE(gridded.size() == gridded_serial.size());
295  REQUIRE(gridded.isApprox(gridded_serial, 1e-4));
296  }
297 }
#define CHECK(CONDITION, ERROR)
Definition: casa.cc:6
const t_real pi
mathematical constant
Definition: types.h:70
std::vector< t_int > distribute_measurements(Vector< t_real > const &u, Vector< t_real > const &v, Vector< t_real > const &w, t_int const number_of_nodes, distribute::plan const distribution_plan, t_int const &grid_size)
Distribute visiblities into groups.
Definition: distribute.cc:6
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
vis_params scatter_visibilities(vis_params const &params, std::vector< t_int > const &sizes, sopt::mpi::Communicator const &comm)
vis_params regroup_and_scatter(vis_params const &params, std::vector< t_int > const &groups, sopt::mpi::Communicator const &comm)
utilities::vis_params random_sample_density(const t_int vis_num, const t_real mean, const t_real standard_deviation, const t_real rms_w)
Generates a random visibility coverage.

References CHECK, purify::distribute::distribute_measurements(), purify::measurementoperator::init_degrid_operator_2d(), purify::kernels::kb, purify::constant::pi, purify::distribute::radial, purify::utilities::radians, purify::utilities::random_sample_density(), purify::utilities::regroup_and_scatter(), and purify::utilities::scatter_visibilities().

◆ TEST_CASE() [2/7]

TEST_CASE ( "Serial vs Distributed Fourier Grid Operator weighted"  )

Definition at line 151 of file mpi_measurement_operator.cc.

151  {
152  // sopt::logging::set_level("debug");
153  // purify::logging::set_level("debug");
154  auto const world = sopt::mpi::Communicator::World();
155 
156  auto const N = 1000;
157  auto uv_serial = utilities::random_sample_density(N, 0, constant::pi / 3);
158  uv_serial.u = world.broadcast(uv_serial.u);
159  uv_serial.v = world.broadcast(uv_serial.v);
160  uv_serial.w = world.broadcast(uv_serial.w);
161  uv_serial.units = utilities::vis_units::radians;
162  uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
163  uv_serial.weights =
164  world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
165 
166  utilities::vis_params uv_mpi;
167  if (world.is_root()) {
168  auto const order =
169  distribute::distribute_measurements(uv_serial, world, distribute::plan::radial);
170  uv_mpi = utilities::regroup_and_scatter(uv_serial, order, world);
171  } else
172  uv_mpi = utilities::scatter_visibilities(world);
173 
174  auto const over_sample = 2;
175  auto const J = 4;
176  auto const kernel = kernels::kernel::kb;
177  auto const width = 128;
178  auto const height = 128;
179  const Vector<t_complex> power_init =
180  world.broadcast(Vector<t_complex>::Random(height * width).eval());
181  const auto op_serial = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
183  uv_serial.u, uv_serial.v, uv_serial.w, uv_serial.weights, height, width, over_sample),
184  100, 1e-4, power_init));
185  const auto op = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
186  purify::measurementoperator::init_degrid_operator_2d_mpi<Vector<t_complex>>(
187  world, uv_mpi.u, uv_mpi.v, uv_mpi.w, uv_mpi.weights, height, width, over_sample),
188  100, 1e-4, power_init));
189 
190  if (world.size() == 1) {
191  REQUIRE(uv_serial.u.isApprox(uv_mpi.u));
192  CHECK(uv_serial.v.isApprox(uv_mpi.v));
193  CHECK(uv_serial.weights.isApprox(uv_mpi.weights));
194  }
195  SECTION("Degridding") {
196  Vector<t_complex> const image =
197  world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
198 
199  auto uv_degrid = uv_serial;
200  if (world.is_root()) {
201  uv_degrid.vis = *op_serial * image;
202  auto const order =
203  distribute::distribute_measurements(uv_degrid, world, distribute::plan::radial);
204  uv_degrid = utilities::regroup_and_scatter(uv_degrid, order, world);
205  } else
206  uv_degrid = utilities::scatter_visibilities(world);
207  Vector<t_complex> const degridded = *op * image;
208  REQUIRE(degridded.size() == uv_degrid.vis.size());
209  REQUIRE(degridded.isApprox(uv_degrid.vis, 1e-4));
210  }
211  SECTION("Gridding") {
212  Vector<t_complex> const gridded = op->adjoint() * uv_mpi.vis;
213  Vector<t_complex> const gridded_serial = op_serial->adjoint() * uv_serial.vis;
214  REQUIRE(gridded.size() == gridded_serial.size());
215  REQUIRE(gridded.isApprox(gridded_serial, 1e-4));
216  }
217 }

References CHECK, purify::distribute::distribute_measurements(), purify::measurementoperator::init_degrid_operator_2d(), purify::kernels::kb, purify::constant::pi, purify::distribute::radial, purify::utilities::radians, purify::utilities::random_sample_density(), purify::utilities::regroup_and_scatter(), and purify::utilities::scatter_visibilities().

◆ TEST_CASE() [3/7]

TEST_CASE ( "Serial vs Distributed Fourier Grid Operator"  )

Definition at line 84 of file mpi_measurement_operator.cc.

84  {
85  auto const world = sopt::mpi::Communicator::World();
86 
87  auto const N = 1000;
88  auto uv_serial = utilities::random_sample_density(N, 0, constant::pi / 3);
89  uv_serial.u = world.broadcast(uv_serial.u);
90  uv_serial.v = world.broadcast(uv_serial.v);
91  uv_serial.w = world.broadcast(uv_serial.w);
92  uv_serial.units = utilities::vis_units::radians;
93  uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
94  uv_serial.weights =
95  world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
96 
97  utilities::vis_params uv_mpi;
98  if (world.is_root()) {
99  auto const order =
100  distribute::distribute_measurements(uv_serial, world, distribute::plan::radial);
101  uv_mpi = utilities::regroup_and_scatter(uv_serial, order, world);
102  } else
103  uv_mpi = utilities::scatter_visibilities(world);
104 
105  auto const over_sample = 2;
106  auto const J = 4;
107  auto const kernel = kernels::kernel::kb;
108  auto const width = 128;
109  auto const height = 128;
110  const Vector<t_complex> power_init =
111  world.broadcast(Vector<t_complex>::Random(height * width).eval());
112  const auto op_serial = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
114  uv_serial.u, uv_serial.v, uv_serial.w, uv_serial.weights, height, width, over_sample),
115  100, 1e-4, power_init));
116 
117  const auto op = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
118  purify::measurementoperator::init_degrid_operator_2d_mpi<Vector<t_complex>>(
119  world, uv_mpi.u, uv_mpi.v, uv_mpi.w, uv_mpi.weights, height, width, over_sample),
120  100, 1e-4, power_init));
121 
122  if (uv_serial.u.size() == uv_mpi.u.size()) {
123  REQUIRE(uv_serial.u.isApprox(uv_mpi.u));
124  CHECK(uv_serial.v.isApprox(uv_mpi.v));
125  CHECK(uv_serial.weights.isApprox(uv_mpi.weights));
126  }
127  SECTION("Degridding") {
128  Vector<t_complex> const image =
129  world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
130 
131  auto uv_degrid = uv_serial;
132  if (world.is_root()) {
133  uv_degrid.vis = *op_serial * image;
134  auto const order =
135  distribute::distribute_measurements(uv_degrid, world, distribute::plan::radial);
136  uv_degrid = utilities::regroup_and_scatter(uv_degrid, order, world);
137  } else
138  uv_degrid = utilities::scatter_visibilities(world);
139  Vector<t_complex> const degridded = *op * image;
140  REQUIRE(degridded.size() == uv_degrid.vis.size());
141  REQUIRE(degridded.isApprox(uv_degrid.vis, 1e-4));
142  }
143  SECTION("Gridding") {
144  Vector<t_complex> const gridded = op->adjoint() * uv_mpi.vis;
145  Vector<t_complex> const gridded_serial = op_serial->adjoint() * uv_serial.vis;
146  REQUIRE(gridded.size() == gridded_serial.size());
147  REQUIRE(gridded.isApprox(gridded_serial, 1e-4));
148  }
149 }

References CHECK, purify::distribute::distribute_measurements(), purify::measurementoperator::init_degrid_operator_2d(), purify::kernels::kb, purify::constant::pi, purify::distribute::radial, purify::utilities::radians, purify::utilities::random_sample_density(), purify::utilities::regroup_and_scatter(), and purify::utilities::scatter_visibilities().

◆ TEST_CASE() [4/7]

TEST_CASE ( "Serial vs Distributed Operator Radial WProjection"  )

Definition at line 666 of file mpi_measurement_operator.cc.

666  {
667  auto const world = sopt::mpi::Communicator::World();
668 
669  auto const N = 1000;
670  auto uv_serial = utilities::random_sample_density(N, 0, constant::pi / 3);
671  uv_serial.u = world.broadcast(uv_serial.u);
672  uv_serial.v = world.broadcast(uv_serial.v);
673  uv_serial.w = world.broadcast(Vector<t_real>::Zero(uv_serial.size()).eval());
674  uv_serial.units = utilities::vis_units::radians;
675  uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
676  uv_serial.weights =
677  world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
678 
679  utilities::vis_params uv_mpi;
680  if (world.is_root()) {
681  auto const order =
682  distribute::distribute_measurements(uv_serial, world, distribute::plan::radial);
683  uv_mpi = utilities::regroup_and_scatter(uv_serial, order, world);
684  } else
685  uv_mpi = utilities::scatter_visibilities(world);
686 
687  auto const over_sample = 2;
688  auto const J = 4;
689  auto const kernel = kernels::kernel::kb;
690  auto const width = 128;
691  auto const height = 128;
692  const t_real cellx = 1;
693  const t_real celly = 1;
694  const t_real abs_error = 1e-8;
695  const t_real rel_error = 1e-8;
696  const Vector<t_complex> power_init =
697  world.broadcast(Vector<t_complex>::Random(height * width).eval());
698  const auto op_serial = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
700  uv_serial, height, width, cellx, celly, over_sample, kernel, J, 4, true, abs_error,
701  rel_error, dde_type::wkernel_radial),
702  10000, 1e-5, power_init));
703 
704  const auto op = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
706  world, uv_mpi, height, width, cellx, celly, over_sample, kernel, J, 4, true, abs_error,
707  rel_error, dde_type::wkernel_radial),
708  10000, 1e-5, power_init));
709 
710  if (uv_serial.u.size() == uv_mpi.u.size()) {
711  REQUIRE(uv_serial.u.isApprox(uv_mpi.u));
712  CHECK(uv_serial.v.isApprox(uv_mpi.v));
713  CHECK(uv_serial.weights.isApprox(uv_mpi.weights));
714  }
715  SECTION("Degridding") {
716  Vector<t_complex> const image =
717  world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
718 
719  auto uv_degrid = uv_serial;
720  if (world.is_root()) {
721  uv_degrid.vis = *op_serial * image;
722  auto const order =
723  distribute::distribute_measurements(uv_degrid, world, distribute::plan::radial);
724  uv_degrid = utilities::regroup_and_scatter(uv_degrid, order, world);
725  } else
726  uv_degrid = utilities::scatter_visibilities(world);
727  Vector<t_complex> const degridded = *op * image;
728  REQUIRE(degridded.size() == uv_degrid.vis.size());
729  REQUIRE(degridded.isApprox(uv_degrid.vis, 1e-4));
730  }
731  SECTION("Gridding") {
732  Vector<t_complex> const gridded = op->adjoint() * uv_mpi.vis;
733  Vector<t_complex> const gridded_serial = op_serial->adjoint() * uv_serial.vis;
734  REQUIRE(gridded.size() == gridded_serial.size());
735  REQUIRE(gridded.isApprox(gridded_serial, 1e-4));
736  }
737 }

References CHECK, purify::distribute::distribute_measurements(), purify::measurementoperator::init_degrid_operator_2d(), purify::kernels::kb, purify::constant::pi, purify::distribute::radial, purify::utilities::radians, purify::utilities::random_sample_density(), purify::utilities::regroup_and_scatter(), purify::utilities::scatter_visibilities(), and purify::wkernel_radial.

◆ TEST_CASE() [5/7]

TEST_CASE ( "Serial vs Distributed Operator"  )

Definition at line 18 of file mpi_measurement_operator.cc.

18  {
19  auto const world = sopt::mpi::Communicator::World();
20 
21  auto const N = 1000;
22  auto uv_serial = utilities::random_sample_density(N, 0, constant::pi / 3);
23  uv_serial.u = world.broadcast(uv_serial.u);
24  uv_serial.v = world.broadcast(uv_serial.v);
25  uv_serial.w = world.broadcast(uv_serial.w);
26  uv_serial.units = utilities::vis_units::radians;
27  uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
28  uv_serial.weights =
29  world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
30 
31  utilities::vis_params uv_mpi;
32  if (world.is_root()) {
33  auto const order =
34  distribute::distribute_measurements(uv_serial, world, distribute::plan::radial);
35  uv_mpi = utilities::regroup_and_scatter(uv_serial, order, world);
36  } else
37  uv_mpi = utilities::scatter_visibilities(world);
38 
39  auto const over_sample = 2;
40  auto const J = 4;
41  auto const kernel = kernels::kernel::kb;
42  auto const width = 128;
43  auto const height = 128;
44  const Vector<t_complex> power_init =
45  world.broadcast(Vector<t_complex>::Random(height * width).eval());
46  const auto op_serial = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
48  uv_serial.u, uv_serial.v, uv_serial.w, uv_serial.weights, height, width, over_sample),
49  100, 1e-4, power_init));
50 
51  const auto op = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
53  world, uv_mpi.u, uv_mpi.v, uv_mpi.w, uv_mpi.weights, height, width, over_sample),
54  100, 1e-4, power_init));
55 
56  if (uv_serial.u.size() == uv_mpi.u.size()) {
57  REQUIRE(uv_serial.u.isApprox(uv_mpi.u));
58  CHECK(uv_serial.v.isApprox(uv_mpi.v));
59  CHECK(uv_serial.weights.isApprox(uv_mpi.weights));
60  }
61  SECTION("Degridding") {
62  Vector<t_complex> const image =
63  world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
64 
65  auto uv_degrid = uv_serial;
66  if (world.is_root()) {
67  uv_degrid.vis = *op_serial * image;
68  auto const order =
69  distribute::distribute_measurements(uv_degrid, world, distribute::plan::radial);
70  uv_degrid = utilities::regroup_and_scatter(uv_degrid, order, world);
71  } else
72  uv_degrid = utilities::scatter_visibilities(world);
73  Vector<t_complex> const degridded = *op * image;
74  REQUIRE(degridded.size() == uv_degrid.vis.size());
75  REQUIRE(degridded.isApprox(uv_degrid.vis, 1e-4));
76  }
77  SECTION("Gridding") {
78  Vector<t_complex> const gridded = op->adjoint() * uv_mpi.vis;
79  Vector<t_complex> const gridded_serial = op_serial->adjoint() * uv_serial.vis;
80  REQUIRE(gridded.size() == gridded_serial.size());
81  REQUIRE(gridded.isApprox(gridded_serial, 1e-4));
82  }
83 }

References CHECK, purify::distribute::distribute_measurements(), purify::measurementoperator::init_degrid_operator_2d(), purify::kernels::kb, purify::constant::pi, purify::distribute::radial, purify::utilities::radians, purify::utilities::random_sample_density(), purify::utilities::regroup_and_scatter(), and purify::utilities::scatter_visibilities().

◆ TEST_CASE() [6/7]

TEST_CASE ( "Standard vs All to All stacking"  )

Definition at line 299 of file mpi_measurement_operator.cc.

299  {
300  // sopt::logging::set_level("debug");
301  // purify::logging::set_level("debug");
302  auto const world = sopt::mpi::Communicator::World();
303 
304  auto const N = 1000;
305  auto uv_serial = utilities::random_sample_density(N, 0, constant::pi / 3, 100);
306  uv_serial.u = world.broadcast(uv_serial.u);
307  uv_serial.v = world.broadcast(uv_serial.v);
308  uv_serial.w = world.broadcast(uv_serial.w);
309  uv_serial.units = utilities::vis_units::radians;
310  uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
311  uv_serial.weights =
312  world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
313 
314  utilities::vis_params uv_mpi;
315  if (world.is_root()) {
316  auto const order =
317  distribute::distribute_measurements(uv_serial, world, distribute::plan::radial);
318  uv_mpi = utilities::regroup_and_scatter(uv_serial, order, world);
319  } else
320  uv_mpi = utilities::scatter_visibilities(world);
321 
322  auto const over_sample = 2;
323  auto const J = 4;
324  auto const kernel = kernels::kernel::kb;
325  auto const width = 128;
326  auto const height = 128;
327  auto const cell_size = 1;
328  // First create an instance of an engine.
329  const auto kmeans = distribute::kmeans_algo(uv_mpi.w, world.size(), 100, world);
330  const std::vector<t_int> image_index = std::get<0>(kmeans);
331  const std::vector<t_real> w_stacks = std::get<1>(kmeans);
332  const Vector<t_complex> power_init =
333  world.broadcast(Vector<t_complex>::Random(height * width).eval());
334 
335  const auto uv_stacks = utilities::regroup_and_all_to_all(uv_mpi, image_index, world);
336  // standard operator
337  const auto op_stack = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
339  world, uv_stacks, height, width, cell_size, cell_size, over_sample, kernel, J, J, true),
340  100, 1e-4, power_init));
341  // all to all operator
342  const auto op = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
343  purify::measurementoperator::init_degrid_operator_2d_all_to_all<Vector<t_complex>>(
344  world, image_index, w_stacks, uv_mpi, height, width, cell_size, cell_size, over_sample,
345  kernel, J, J, true),
346  100, 1e-4, power_init));
347  if (world.size() == 1) {
348  REQUIRE(uv_serial.u.isApprox(uv_mpi.u));
349  CHECK(uv_serial.v.isApprox(uv_mpi.v));
350  CHECK(uv_serial.weights.isApprox(uv_mpi.weights));
351  }
352  SECTION("Degridding") {
353  Vector<t_complex> const image =
354  world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
355 
356  const Vector<t_complex> degridded = *op_stack * image;
357  auto uv_degrid = uv_mpi;
358  uv_degrid.vis = *op * image;
359  uv_degrid = utilities::regroup_and_all_to_all(uv_degrid, image_index, world);
360  REQUIRE(degridded.size() == uv_degrid.vis.size());
361  REQUIRE(degridded.isApprox(uv_degrid.vis, 1e-4));
362  }
363  SECTION("Gridding") {
364  Vector<t_complex> const gridded = op->adjoint() * uv_mpi.vis;
365  Vector<t_complex> const gridded_serial = op_stack->adjoint() * uv_stacks.vis;
366  REQUIRE(gridded.size() == gridded_serial.size());
367  REQUIRE(gridded.isApprox(gridded_serial, 1e-4));
368  }
369 }
std::tuple< std::vector< t_int >, std::vector< t_real > > kmeans_algo(const Vector< t_real > &w, const t_int number_of_nodes, const t_int iters, const std::function< t_real(t_real)> &cost, const t_real rel_diff)
patition w terms using k-means
Definition: distribute.cc:103
std::tuple< vis_params, std::vector< t_int > > regroup_and_all_to_all(vis_params const &params, const std::vector< t_int > &image_index, std::vector< t_int > const &groups, sopt::mpi::Communicator const &comm)

References CHECK, purify::distribute::distribute_measurements(), purify::measurementoperator::init_degrid_operator_2d(), purify::kernels::kb, purify::distribute::kmeans_algo(), purify::constant::pi, purify::distribute::radial, purify::utilities::radians, purify::utilities::random_sample_density(), purify::utilities::regroup_and_all_to_all(), purify::utilities::regroup_and_scatter(), and purify::utilities::scatter_visibilities().

◆ TEST_CASE() [7/7]

TEST_CASE ( "Standard vs All to All wproj"  )

Definition at line 370 of file mpi_measurement_operator.cc.

370  {
371  // sopt::logging::set_level("debug");
372  // purify::logging::set_level("debug");
373  auto const world = sopt::mpi::Communicator::World();
374 
375  auto const N = 1000;
376  const t_real w_rms = 100;
377  auto uv_serial = utilities::random_sample_density(N, 0, constant::pi / 3, w_rms);
378  uv_serial.u = world.broadcast(uv_serial.u);
379  uv_serial.v = world.broadcast(uv_serial.v);
380  uv_serial.w = world.broadcast(uv_serial.w);
381  uv_serial.units = utilities::vis_units::radians;
382  uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
383  uv_serial.weights =
384  world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
385 
386  utilities::vis_params uv_mpi;
387  if (world.is_root()) {
388  auto const order =
389  distribute::distribute_measurements(uv_serial, world, distribute::plan::radial);
390  uv_mpi = utilities::regroup_and_scatter(uv_serial, order, world);
391  } else
392  uv_mpi = utilities::scatter_visibilities(world);
393 
394  auto const over_sample = 2;
395  auto const J = 4;
396  auto const kernel = kernels::kernel::kb;
397  auto const width = 128;
398  auto const height = 128;
399  auto const cell_size = 60;
400  // First create an instance of an engine.
401  const auto kmeans = distribute::kmeans_algo(uv_mpi.w, world.size(), 100, world);
402  const std::vector<t_int> image_index = std::get<0>(kmeans);
403  const std::vector<t_real> w_stacks = std::get<1>(kmeans);
404  const Vector<t_complex> power_init =
405  world.broadcast(Vector<t_complex>::Random(height * width).eval());
406 
407  const auto uv_stacks = utilities::regroup_and_all_to_all(uv_mpi, image_index, world);
408  // standard operator
409  const auto op_wproj = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
411  world, uv_stacks, height, width, cell_size, cell_size, over_sample, kernel, J, 100, true,
412  1e-8, 1e-8, dde_type::wkernel_radial),
413  100, 1e-4, power_init));
414  // all to all operator
415  const auto op_wproj_all = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
416  purify::measurementoperator::init_degrid_operator_2d_all_to_all<Vector<t_complex>>(
417  world, image_index, w_stacks, uv_mpi, height, width, cell_size, cell_size, over_sample,
418  kernel, J, 100, true, 1e-8, 1e-8, dde_type::wkernel_radial),
419  100, 1e-4, power_init));
420  if (world.size() == 1) {
421  REQUIRE(uv_serial.u.isApprox(uv_mpi.u));
422  CHECK(uv_serial.v.isApprox(uv_mpi.v));
423  CHECK(uv_serial.weights.isApprox(uv_mpi.weights));
424  }
425  SECTION("Degridding") {
426  Vector<t_complex> const image =
427  world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
428 
429  const Vector<t_complex> degridded = *op_wproj * image;
430  auto uv_degrid = uv_mpi;
431  uv_degrid.vis = *op_wproj_all * image;
432  uv_degrid = utilities::regroup_and_all_to_all(uv_degrid, image_index, world);
433  REQUIRE(degridded.size() == uv_degrid.vis.size());
434  REQUIRE(degridded.isApprox(uv_degrid.vis, 1e-4));
435  }
436  SECTION("Gridding") {
437  Vector<t_complex> const gridded = op_wproj_all->adjoint() * uv_mpi.vis;
438  Vector<t_complex> const gridded_serial = op_wproj->adjoint() * uv_stacks.vis;
439  REQUIRE(gridded.size() == gridded_serial.size());
440  REQUIRE(gridded.isApprox(gridded_serial, 1e-4));
441  }
442 }

References CHECK, purify::distribute::distribute_measurements(), purify::measurementoperator::init_degrid_operator_2d(), purify::kernels::kb, purify::distribute::kmeans_algo(), purify::constant::pi, purify::distribute::radial, purify::utilities::radians, purify::utilities::random_sample_density(), purify::utilities::regroup_and_all_to_all(), purify::utilities::regroup_and_scatter(), purify::utilities::scatter_visibilities(), and purify::wkernel_radial.