PURIFY
Next-generation radio interferometric imaging
Functions
sdmm_m31_simulation.cc File Reference
#include "purify/config.h"
#include "purify/types.h"
#include <array>
#include <ctime>
#include <memory>
#include <random>
#include <boost/math/special_functions/erf.hpp>
#include "purify/directories.h"
#include "purify/logging.h"
#include "purify/operators.h"
#include "purify/pfitsio.h"
#include "purify/utilities.h"
#include <sopt/power_method.h>
#include <sopt/relative_variation.h>
#include <sopt/sdmm.h>
#include <sopt/utilities.h>
#include <sopt/wavelets.h>
#include <sopt/wavelets/sara.h>
+ Include dependency graph for sdmm_m31_simulation.cc:

Go to the source code of this file.

Functions

int main (int nargs, char const **args)
 

Function Documentation

◆ main()

int main ( int  nargs,
char const **  args 
)

Definition at line 20 of file sdmm_m31_simulation.cc.

20  {
21  using namespace purify;
22 
23  if (nargs != 6) {
24  PURIFY_CRITICAL(" Wrong number of arguments!");
25  return 1;
26  }
27 
28  std::string const fitsfile = image_filename("M31.fits");
29 
30  std::string const kernel = args[1];
31  t_real const over_sample = std::stod(static_cast<std::string>(args[2]));
32  t_int const J = static_cast<t_int>(std::stod(static_cast<std::string>(args[3])));
33  t_real const m_over_n = std::stod(static_cast<std::string>(args[4]));
34  std::string const test_number = static_cast<std::string>(args[5]);
35 
36  std::string const dirty_image_fits =
37  output_filename("M31_dirty_" + kernel + "_" + test_number + ".fits");
38  std::string const results = output_filename("M31_results_" + kernel + "_" + test_number + ".txt");
39 
40  auto sky_model = pfitsio::read2d(fitsfile);
41  auto sky_model_max = sky_model.array().abs().maxCoeff();
42  sky_model = sky_model / sky_model_max;
43  t_int const number_of_vis = std::floor(m_over_n * sky_model.size());
44  t_real const sigma_m = constant::pi / 3;
45 
46  auto uv_data = utilities::random_sample_density(number_of_vis, 0, sigma_m);
47  uv_data.units = utilities::vis_units::radians;
48  PURIFY_MEDIUM_LOG("Number of measurements: {}", uv_data.u.size());
49  auto simulate_measurements = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
51  uv_data.u, uv_data.v, uv_data.w, uv_data.weights, sky_model.cols(), sky_model.rows(), 2,
52  kernels::kernel_from_string.at("kb"), 8, 8),
53  100, 1e-4, Vector<t_complex>::Random(sky_model.size())));
54  uv_data.vis = simulate_measurements * sky_model;
55 
56  auto measurements_transform = std::get<2>(sopt::algorithm::normalise_operator<Vector<t_complex>>(
58  uv_data.u, uv_data.v, uv_data.w, uv_data.weights, sky_model.cols(), sky_model.rows(),
59  over_sample, kernels::kernel_from_string.at(kernel), J, J),
60  100, 1e-4, Vector<t_complex>::Random(sky_model.size())));
61 
62  sopt::wavelets::SARA const sara{
63  std::make_tuple("Dirac", 3u), std::make_tuple("DB1", 3u), std::make_tuple("DB2", 3u),
64  std::make_tuple("DB3", 3u), std::make_tuple("DB4", 3u), std::make_tuple("DB5", 3u),
65  std::make_tuple("DB6", 3u), std::make_tuple("DB7", 3u), std::make_tuple("DB8", 3u)};
66 
67  auto const Psi = sopt::linear_transform<t_complex>(sara, sky_model.rows(), sky_model.cols());
68 
69  // working out value of sigma given SNR of 30
70  t_real sigma = utilities::SNR_to_standard_deviation(uv_data.vis, 30.);
71  // adding noise to visibilities
72  uv_data.vis = utilities::add_noise(uv_data.vis, 0., sigma);
73 
74  Vector<> dimage = (measurements_transform.adjoint() * uv_data.vis).real();
75  t_real const max_val = dimage.array().abs().maxCoeff();
76  dimage = dimage / max_val;
77  Vector<t_complex> initial_estimate = Vector<t_complex>::Zero(dimage.size());
78  pfitsio::write2d(Image<t_real>::Map(dimage.data(), sky_model.rows(), sky_model.cols()),
79  dirty_image_fits);
80 
81  auto const epsilon = utilities::calculate_l2_radius(uv_data.vis.size(), sigma);
82  PURIFY_MEDIUM_LOG("Using epsilon of {}", epsilon);
83  auto const sdmm =
84  sopt::algorithm::SDMM<t_complex>()
85  .itermax(500)
86  .gamma((measurements_transform.adjoint() * uv_data.vis).real().maxCoeff() * 1e-3)
87  .is_converged(sopt::RelativeVariation<t_complex>(1e-3))
88  .conjugate_gradient(100, 1e-3)
89  .append(
90  sopt::proximal::translate(sopt::proximal::L2Ball<t_complex>(epsilon), -uv_data.vis),
91  measurements_transform)
92  .append(sopt::proximal::l1_norm<t_complex>, Psi.adjoint(), Psi)
93  .append(sopt::proximal::positive_quadrant<t_complex>);
94  // Timing reconstruction
95  Vector<t_complex> result;
96  std::clock_t c_start = std::clock();
97  auto const diagnostic = sdmm(result, initial_estimate);
98  if (not diagnostic.good) PURIFY_HIGH_LOG("SDMM did no converge");
99  std::clock_t c_end = std::clock();
100  Image<t_complex> image = Image<t_complex>::Map(result.data(), sky_model.rows(), sky_model.cols());
101  t_real const max_val_final = image.array().abs().maxCoeff();
102  image = image / max_val_final;
103 
104  Vector<t_complex> original = Vector<t_complex>::Map(sky_model.data(), sky_model.size(), 1);
105  Image<t_complex> res = sky_model - image;
106  Vector<t_complex> residual = Vector<t_complex>::Map(res.data(), image.size(), 1);
107 
108  auto snr = 20. * std::log10(original.norm() / residual.norm()); // SNR of reconstruction
109  auto total_time = (c_end - c_start) / CLOCKS_PER_SEC; // total time for solver to run in seconds
110  // writing snr and time to a file
111  std::ofstream out(results);
112  out.precision(13);
113  out << snr << " " << total_time;
114  out.close();
115 
116  return 0;
117 }
#define PURIFY_HIGH_LOG(...)
High priority message.
Definition: logging.h:203
#define PURIFY_CRITICAL(...)
\macro Normal but signigicant condition
Definition: logging.h:188
#define PURIFY_MEDIUM_LOG(...)
Medium priority message.
Definition: logging.h:205
const t_real pi
mathematical constant
Definition: types.h:70
const std::map< std::string, kernel > kernel_from_string
Definition: kernels.h:16
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
void write2d(const Image< t_real > &eigen_image, const pfitsio::header_params &header, const bool &overwrite)
Write image to fits file.
Definition: pfitsio.cc:30
Image< t_complex > read2d(const std::string &fits_name)
Read image from fits file.
Definition: pfitsio.cc:109
t_real SNR_to_standard_deviation(const Vector< t_complex > &y0, const t_real &SNR)
Converts SNR to RMS noise.
Definition: utilities.cc:101
Vector< t_complex > add_noise(const Vector< t_complex > &y0, const t_complex &mean, const t_real &standard_deviation)
Add guassian noise to vector.
Definition: utilities.cc:113
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.
t_real calculate_l2_radius(const t_uint y_size, const t_real &sigma, const t_real &n_sigma, const std::string distirbution)
A function that calculates the l2 ball radius for sopt.
Definition: utilities.cc:75
std::string output_filename(std::string const &filename)
Test output file.
std::string image_filename(std::string const &filename)
Image filename.

References purify::utilities::add_noise(), purify::utilities::calculate_l2_radius(), purify::image_filename(), purify::measurementoperator::init_degrid_operator_2d(), purify::kernels::kernel_from_string, purify::output_filename(), purify::constant::pi, PURIFY_CRITICAL, PURIFY_HIGH_LOG, PURIFY_MEDIUM_LOG, purify::utilities::radians, purify::utilities::random_sample_density(), purify::pfitsio::read2d(), purify::utilities::SNR_to_standard_deviation(), and purify::pfitsio::write2d().