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.