3 #include "catch2/catch_all.hpp"
10 #include <sopt/mpi/communicator.h>
11 #include <sopt/power_method.h>
12 #ifdef PURIFY_ARRAYFIRE
19 auto const world = sopt::mpi::Communicator::World();
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);
27 uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
29 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
32 if (world.is_root()) {
39 auto const over_sample = 2;
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));
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));
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));
61 SECTION(
"Degridding") {
62 Vector<t_complex>
const image =
63 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
65 auto uv_degrid = uv_serial;
66 if (world.is_root()) {
67 uv_degrid.vis = *op_serial * image;
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));
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));
84 TEST_CASE(
"Serial vs Distributed Fourier Grid Operator") {
85 auto const world = sopt::mpi::Communicator::World();
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);
93 uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
95 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
98 if (world.is_root()) {
105 auto const over_sample = 2;
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));
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));
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));
127 SECTION(
"Degridding") {
128 Vector<t_complex>
const image =
129 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
131 auto uv_degrid = uv_serial;
132 if (world.is_root()) {
133 uv_degrid.vis = *op_serial * image;
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));
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));
151 TEST_CASE(
"Serial vs Distributed Fourier Grid Operator weighted") {
154 auto const world = sopt::mpi::Communicator::World();
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);
162 uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
164 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
167 if (world.is_root()) {
174 auto const over_sample = 2;
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));
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));
195 SECTION(
"Degridding") {
196 Vector<t_complex>
const image =
197 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
199 auto uv_degrid = uv_serial;
200 if (world.is_root()) {
201 uv_degrid.vis = *op_serial * image;
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));
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));
219 TEST_CASE(
"Serial vs All to All Fourier Grid Operator weighted") {
222 auto const world = sopt::mpi::Communicator::World();
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);
230 uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
232 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
235 if (world.is_root()) {
242 auto const over_sample = 2;
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));
254 std::random_device rnd_device;
256 std::mt19937 mersenne_engine(rnd_device());
257 std::uniform_int_distribution<t_int> dist(0, world.size() - 1);
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.);
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,
268 100, 1e-4, power_init));
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));
275 SECTION(
"Degridding") {
276 Vector<t_complex>
const image =
277 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
279 auto uv_degrid = uv_serial;
280 if (world.is_root()) {
281 uv_degrid.vis = *op_serial * image;
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));
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));
302 auto const world = sopt::mpi::Communicator::World();
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);
310 uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
312 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
315 if (world.is_root()) {
322 auto const over_sample = 2;
325 auto const width = 128;
326 auto const height = 128;
327 auto const cell_size = 1;
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());
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));
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,
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));
352 SECTION(
"Degridding") {
353 Vector<t_complex>
const image =
354 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
356 const Vector<t_complex> degridded = *op_stack * image;
357 auto uv_degrid = uv_mpi;
358 uv_degrid.vis = *op * image;
360 REQUIRE(degridded.size() == uv_degrid.vis.size());
361 REQUIRE(degridded.isApprox(uv_degrid.vis, 1e-4));
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));
373 auto const world = sopt::mpi::Communicator::World();
376 const t_real w_rms = 100;
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);
382 uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
384 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
387 if (world.is_root()) {
394 auto const over_sample = 2;
397 auto const width = 128;
398 auto const height = 128;
399 auto const cell_size = 60;
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());
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,
413 100, 1e-4, power_init));
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,
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));
425 SECTION(
"Degridding") {
426 Vector<t_complex>
const image =
427 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
429 const Vector<t_complex> degridded = *op_wproj * image;
430 auto uv_degrid = uv_mpi;
431 uv_degrid.vis = *op_wproj_all * image;
433 REQUIRE(degridded.size() == uv_degrid.vis.size());
434 REQUIRE(degridded.isApprox(uv_degrid.vis, 1e-4));
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));
443 #ifdef PURIFY_ARRAYFIRE
444 TEST_CASE(
"Serial vs Distributed GPU Fourier Grid Operator weighted") {
448 auto const world = sopt::mpi::Communicator::World();
451 uv_serial.u = world.broadcast(uv_serial.u);
452 uv_serial.v = world.broadcast(uv_serial.v);
453 uv_serial.w = world.broadcast(uv_serial.w);
455 uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
457 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
460 if (world.is_root()) {
467 auto const over_sample = 2;
470 auto const width = 128;
471 auto const height = 128;
472 const Vector<t_complex> power_init =
473 world.broadcast(Vector<t_complex>::Random(height * width).eval());
474 const auto op_serial = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
476 uv_serial.u, uv_serial.v, uv_serial.w, uv_serial.weights, height, width, over_sample),
477 100, 1e-4, power_init));
478 const auto op = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
479 purify::gpu::measurementoperator::init_degrid_operator_2d_mpi(
480 world, uv_mpi.u, uv_mpi.v, uv_mpi.w, uv_mpi.weights, height, width, over_sample),
481 100, 1e-4, power_init));
483 if (world.size() == 1) {
484 REQUIRE(uv_serial.u.isApprox(uv_mpi.u));
485 CHECK(uv_serial.v.isApprox(uv_mpi.v));
486 CHECK(uv_serial.weights.isApprox(uv_mpi.weights));
488 SECTION(
"Power Method") {
489 auto op_norm = std::get<0>(sopt::algorithm::power_method<Vector<t_complex>>(
490 *op, 100, 1e-4, Vector<t_complex>::Random(width * height)));
491 CHECK(std::abs(op_norm - 1.) < 1e-4);
492 auto op_norm_old = std::get<0>(sopt::algorithm::power_method<Vector<t_complex>>(
493 *op_serial, 100, 1e-4, Vector<t_complex>::Random(width * height)));
494 CHECK(std::abs(op_norm_old - 1.) < 1e-4);
496 SECTION(
"Degridding") {
497 Vector<t_complex>
const image =
498 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
500 auto uv_degrid = uv_serial;
501 if (world.is_root()) {
502 uv_degrid.vis = *op_serial * image;
508 Vector<t_complex>
const degridded = *op * image;
509 REQUIRE(degridded.size() == uv_degrid.vis.size());
510 REQUIRE(degridded.isApprox(uv_degrid.vis, 1e-4));
512 SECTION(
"Gridding") {
513 Vector<t_complex>
const gridded = op->adjoint() * uv_mpi.vis;
514 Vector<t_complex>
const gridded_serial = op_serial->adjoint() * uv_serial.vis;
515 REQUIRE(gridded.size() == gridded_serial.size());
516 REQUIRE(gridded.isApprox(gridded_serial, 1e-4));
519 TEST_CASE(
"Serial vs Distributed GPU Operator weighted") {
523 auto const world = sopt::mpi::Communicator::World();
526 uv_serial.u = world.broadcast(uv_serial.u);
527 uv_serial.v = world.broadcast(uv_serial.v);
528 uv_serial.w = world.broadcast(uv_serial.w);
530 uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
532 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
535 if (world.is_root()) {
542 auto const over_sample = 2;
545 auto const width = 128;
546 auto const height = 128;
547 const auto op_serial = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
549 uv_serial.u, uv_serial.v, uv_serial.w, uv_serial.weights, height, width, over_sample),
550 100, 1e-4, Vector<t_complex>::Random(height * width)));
551 const auto op = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
553 world, uv_mpi.u, uv_mpi.v, uv_mpi.w, uv_mpi.weights, height, width, over_sample),
554 100, 1e-4, world.broadcast(Vector<t_complex>::Random(height * width).eval())));
556 if (world.size() == 1) {
557 REQUIRE(uv_serial.u.isApprox(uv_mpi.u));
558 CHECK(uv_serial.v.isApprox(uv_mpi.v));
559 CHECK(uv_serial.weights.isApprox(uv_mpi.weights));
561 SECTION(
"Power Method") {
562 auto op_norm = std::get<0>(sopt::algorithm::power_method<Vector<t_complex>>(
563 *op, 100, 1e-4, Vector<t_complex>::Random(width * height)));
564 CHECK(std::abs(op_norm - 1.) < 1e-4);
565 auto op_norm_old = std::get<0>(sopt::algorithm::power_method<Vector<t_complex>>(
566 *op_serial, 100, 1e-4, Vector<t_complex>::Random(width * height)));
567 CHECK(std::abs(op_norm_old - 1.) < 1e-4);
569 SECTION(
"Degridding") {
570 Vector<t_complex>
const image =
571 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
573 auto uv_degrid = uv_serial;
574 if (world.is_root()) {
575 uv_degrid.vis = *op_serial * image;
581 Vector<t_complex>
const degridded = *op * image;
582 REQUIRE(degridded.size() == uv_degrid.vis.size());
583 REQUIRE(degridded.isApprox(uv_degrid.vis, 1e-4));
585 SECTION(
"Gridding") {
586 Vector<t_complex>
const gridded = op->adjoint() * uv_mpi.vis;
587 Vector<t_complex>
const gridded_serial = op_serial->adjoint() * uv_serial.vis;
588 REQUIRE(gridded.size() == gridded_serial.size());
589 REQUIRE(gridded.isApprox(gridded_serial, 1e-4));
592 TEST_CASE(
"Serial vs Distributed GPU Operator Radial WProjection") {
593 auto const world = sopt::mpi::Communicator::World();
597 uv_serial.u = world.broadcast(uv_serial.u);
598 uv_serial.v = world.broadcast(uv_serial.v);
599 uv_serial.w = world.broadcast(Vector<t_real>::Zero(uv_serial.size()).eval());
601 uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
603 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
606 if (world.is_root()) {
613 auto const over_sample = 2;
616 auto const width = 128;
617 auto const height = 128;
618 const t_real cellx = 1;
619 const t_real celly = 1;
620 const t_real abs_error = 1e-6;
621 const t_real rel_error = 1e-8;
622 const Vector<t_complex> power_init =
623 world.broadcast(Vector<t_complex>::Random(height * width).eval());
624 const auto op_serial = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
626 uv_serial, height, width, cellx, celly, over_sample,
kernel, J, 4,
true, abs_error,
628 10000, 1e-5, power_init);
630 const auto op = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
632 over_sample,
kernel, J, 4,
true, abs_error,
634 10000, 1e-5, power_init);
636 if (uv_serial.u.size() == uv_mpi.u.size()) {
637 REQUIRE(uv_serial.u.isApprox(uv_mpi.u));
638 CHECK(uv_serial.v.isApprox(uv_mpi.v));
639 CHECK(uv_serial.weights.isApprox(uv_mpi.weights));
641 SECTION(
"Degridding") {
642 Vector<t_complex>
const image =
643 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
645 auto uv_degrid = uv_serial;
646 if (world.is_root()) {
647 uv_degrid.vis = *op_serial * image;
653 Vector<t_complex>
const degridded = *op * image;
654 REQUIRE(degridded.size() == uv_degrid.vis.size());
655 REQUIRE(degridded.isApprox(uv_degrid.vis, 1e-4));
657 SECTION(
"Gridding") {
658 Vector<t_complex>
const gridded = op->adjoint() * uv_mpi.vis;
659 Vector<t_complex>
const gridded_serial = op_serial->adjoint() * uv_serial.vis;
660 REQUIRE(gridded.size() == gridded_serial.size());
661 REQUIRE(gridded.isApprox(gridded_serial, 1e-4));
666 TEST_CASE(
"Serial vs Distributed Operator Radial WProjection") {
667 auto const world = sopt::mpi::Communicator::World();
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());
675 uv_serial.vis = world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
677 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(uv_serial.u.size()));
680 if (world.is_root()) {
687 auto const over_sample = 2;
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,
702 10000, 1e-5, power_init));
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,
708 10000, 1e-5, power_init));
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));
715 SECTION(
"Degridding") {
716 Vector<t_complex>
const image =
717 world.broadcast<Vector<t_complex>>(Vector<t_complex>::Random(width * height));
719 auto uv_degrid = uv_serial;
720 if (world.is_root()) {
721 uv_degrid.vis = *op_serial * image;
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));
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));
#define CHECK(CONDITION, ERROR)
TEST_CASE("Serial vs Distributed Operator")
const t_real pi
mathematical constant
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
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.
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< vis_params, std::vector< t_int > > regroup_and_all_to_all(vis_params const ¶ms, const std::vector< t_int > &image_index, std::vector< t_int > const &groups, sopt::mpi::Communicator const &comm)
vis_params scatter_visibilities(vis_params const ¶ms, std::vector< t_int > const &sizes, sopt::mpi::Communicator const &comm)
vis_params regroup_and_scatter(vis_params const ¶ms, 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.