PURIFY
Next-generation radio interferometric imaging
wproj_utilities.cc
Go to the documentation of this file.
2 
3 namespace purify {
4 namespace utilities {
5 vis_params sort_by_w(const vis_params &uv_data) {
6  vis_params output = uv_data;
7  std::vector<t_uint> ind;
8  for (t_uint i = 0; i < uv_data.size(); i++) ind.push_back(i);
9  std::sort(ind.begin(), ind.end(),
10  [&](const t_uint a, const t_uint b) { return uv_data.w(a) < uv_data.w(b); });
11  for (t_uint i = 0; i < uv_data.size(); i++) {
12  output.u(i) = uv_data.u(ind.at(i));
13  output.v(i) = uv_data.v(ind.at(i));
14  output.w(i) = uv_data.w(ind.at(i));
15  output.weights(i) = uv_data.weights(ind.at(i));
16  output.vis(i) = uv_data.vis(ind.at(i));
17  }
18  return output;
19 }
20 } // namespace utilities
21 namespace wproj_utilities {
22 std::vector<t_uint> w_rows(const Sparse<t_complex> &w_degrider) {
23  std::set<t_uint> w_rows_set;
24  for (t_int k = 0; k < w_degrider.outerSize(); ++k) {
25  t_uint index = 0;
26  for (Sparse<t_complex>::InnerIterator it(w_degrider, k); it; ++it) {
27  index++;
28  if (index > 0) {
29  w_rows_set.insert(it.col());
30  }
31  }
32  }
33  std::vector<t_uint> w_rows(w_rows_set.begin(), w_rows_set.end());
34  std::sort(w_rows.begin(), w_rows.end());
35  return w_rows;
36 }
37 std::tuple<t_real, t_real> fov_cosines(t_real const &cell_x, t_real const &cell_y,
38  t_uint const &x_size, t_uint const &y_size) {
39  // celly:: size of y pixel in arcseconds
40  // cellx:: size of x pixel in arcseconds
41  // x_size:: number of pixels along x-axis
42  // y_size:: number of pixels along y-axis
43  const t_real pi = constant::pi;
44  const t_real theta_FoV_L = cell_x * x_size;
45  const t_real theta_FoV_M = cell_y * y_size;
46  const t_real L = 2 * std::sin(pi / 180. * theta_FoV_L / (60. * 60.) * 0.5);
47  const t_real M = 2 * std::sin(pi / 180. * theta_FoV_M / (60. * 60.) * 0.5);
48  return std::make_tuple(L, M);
49 }
50 
51 Matrix<t_complex> generate_dde(const std::function<t_complex(t_real, t_real)> &dde,
52  const t_real &cell_x, const t_real &cell_y, const t_uint &x_size,
53  const t_uint &y_size) {
54  // celly:: size of y pixel in arcseconds
55  // cellx:: size of x pixel in arcseconds
56  // x_size:: number of pixels along x-axis
57  // y_size:: number of pixels along y-axis
58  auto const LM = fov_cosines(cell_x, cell_y, x_size, y_size);
59 
60  const t_real L = std::get<0>(LM);
61  const t_real M = std::get<1>(LM);
62 
63  const t_real delt_x = L / x_size;
64  const t_real delt_y = M / y_size;
65  Image<t_complex> chirp(y_size, x_size);
66 
67  for (t_int l = 0; l < x_size; ++l)
68  for (t_int m = 0; m < y_size; ++m) {
69  const t_real x = (l + 0.5 - x_size * 0.5) * delt_x;
70  const t_real y = (m + 0.5 - y_size * 0.5) * delt_y;
71  chirp(l, m) = dde(y, x);
72  }
73 
74  return chirp;
75 }
76 Matrix<t_complex> generate_chirp(const std::function<t_complex(t_real, t_real)> &dde,
77  const t_real &w_rate, const t_real &cell_x, const t_real &cell_y,
78  const t_uint &x_size, const t_uint &y_size) {
79  // return chirp image fourier transform for w component
80  // w:: w-term in units of lambda
81  // celly:: size of y pixel in arcseconds
82  // cellx:: size of x pixel in arcseconds
83  // x_size:: number of pixels along x-axis
84  // y_size:: number of pixels along y-axis
85  const t_real nz = y_size * x_size;
86  const t_complex I(0, 1);
87  const t_real pi = constant::pi;
88  const auto chirp = [=](const t_real &y, const t_real &x) {
89  return dde(y, x) * (std::exp(-2 * pi * I * w_rate * (std::sqrt(1 - x * x - y * y) - 1))) / nz;
90  };
91  auto primary_beam = [=](const t_real &x, const t_real &y) {
92  return 1. / std::sqrt(1 - x * x - y * y);
93  };
94  const auto chirp_approx = [=](const t_real &y, const t_real &x) {
95  return dde(y, x) * (std::exp(2 * pi * I * w_rate * (x * x + y * y))) / nz;
96  };
97  return generate_dde(chirp, cell_x, cell_y, x_size, y_size);
98 }
99 Matrix<t_complex> generate_chirp(const t_real &w_rate, const t_real &cell_x, const t_real &cell_y,
100  const t_uint &x_size, const t_uint &y_size) {
101  // return chirp image fourier transform for w component
102  // w:: w-term in units of lambda
103  // celly:: size of y pixel in arcseconds
104  // cellx:: size of x pixel in arcseconds
105  // x_size:: number of pixels along x-axis
106  // y_size:: number of pixels along y-axis
107  return generate_chirp([](const t_real &, const t_real &) { return 1.; }, w_rate, cell_x, cell_y,
108  x_size, y_size);
109 }
110 Sparse<t_complex> create_chirp_row(const t_real &w_rate, const t_real &cell_x, const t_real &cell_y,
111  const t_uint &ftsizev, const t_uint &ftsizeu,
112  const t_real &energy_fraction,
113  const sopt::OperatorFunction<Vector<t_complex>> &fftop) {
114  const Matrix<t_complex> chirp =
115  wproj_utilities::generate_chirp(w_rate, cell_x, cell_y, ftsizeu, ftsizev);
116  return create_chirp_row(Vector<t_complex>::Map(chirp.data(), chirp.size()), energy_fraction,
117  fftop);
118 }
119 Sparse<t_complex> create_chirp_row(const Vector<t_complex> &chirp_image,
120  const t_real &energy_fraction,
121  const sopt::OperatorFunction<Vector<t_complex>> &fftop) {
122  Vector<t_complex> chirp;
123 #pragma omp critical(fft)
124  fftop(chirp, chirp_image);
125  chirp *= std::sqrt(chirp.size());
126  const t_real thres = wproj_utilities::sparsify_row_dense_thres(chirp, energy_fraction);
127  assert(chirp.norm() > 0);
128  const t_real row_max = chirp.cwiseAbs().maxCoeff();
129  return convert_sparse(chirp, thres).transpose();
130 }
131 
133  const t_uint &y_size, const Vector<t_real> &w_components,
134  const t_real &cell_x, const t_real &cell_y,
135  const t_real &energy_fraction_chirp,
136  const t_real &energy_fraction_wproj,
137  const expansions::series series, const t_uint order,
138  const t_real &interpolation_error) {
139  const t_uint Npix = x_size * y_size;
140  const t_uint Nvis = w_components.size();
141 
142  PURIFY_HIGH_LOG("Spread of w components {} ",
143  std::sqrt(std::pow(w_components.norm(), 2) / Nvis -
144  std::pow(w_components.array().mean(), 2)));
145  PURIFY_HIGH_LOG("Mean of w components {} ", w_components.array().mean());
146  PURIFY_HIGH_LOG("Hard-thresholding of the chirp kernels: energy [{}] ", energy_fraction_chirp);
147  PURIFY_HIGH_LOG("Hard-thresholding of the rows of G: energy [{}] ", energy_fraction_wproj);
148 
149  const auto ft_plan = operators::fftw_plan::measure;
150  const auto fftop_ = operators::init_FFT_2d<Vector<t_complex>>(y_size, x_size, 1., ft_plan);
151  Sparse<t_complex> GW(Nvis, Npix);
152 
153  t_uint counts = 0;
154  t_uint total_non_zero = 0;
155  GW.reserve(G.nonZeros() * 1e3);
156 #pragma omp parallel for
157  for (t_int m = 0; m < G.rows(); m++) {
158  const Sparse<t_complex> chirp =
159  create_chirp_row(w_components(m), cell_x, cell_y, x_size, y_size, energy_fraction_chirp,
160  std::get<0>(fftop_));
161 
162  Sparse<t_complex> kernel = row_wise_sparse_convolution(G.row(m), chirp, x_size, y_size);
163  const t_real thres = sparsify_row_thres(kernel, energy_fraction_wproj);
164  kernel.prune([&](const t_uint &i, const t_uint &j, const t_complex &value) {
165  return std::abs(value) > thres;
166  });
167  assert(kernel.cols() > 0);
168  assert(kernel.rows() == 1);
169 #pragma omp critical
170  GW.row(m) = kernel;
171 #pragma omp critical
172  counts++;
173 #pragma omp critical
174  total_non_zero += kernel.nonZeros();
175 #pragma omp critical
176  // if(counts % 100 == 0) {
177  PURIFY_DEBUG("Row {} of {}", counts, GW.rows());
178  PURIFY_DEBUG("With {} entries non zero, which is {} entries per a row.", total_non_zero,
179  static_cast<t_real>(total_non_zero) / counts);
180  //}
181  }
182  assert(GW.nonZeros() > 0);
183  PURIFY_DEBUG("\nBuilding the rows of GW.. DONE!\n");
184  PURIFY_DEBUG("DONE - With {} entries non zero, which is {} entries per a row.", GW.nonZeros(),
185  static_cast<t_real>(GW.nonZeros()) / GW.rows());
186  GW.makeCompressed();
187  return GW;
188 }
189 
190 t_real snr_metric(const Image<t_real> &model, const Image<t_real> &solution) {
191  /*
192  Returns SNR of the estimated model image
193  */
194  t_real nm = model.matrix().norm();
195  t_real ndiff = (model - solution).matrix().norm();
196  t_real val = 20 * std::log10(nm / ndiff);
197  return val;
198 }
199 t_real mr_metric(const Image<t_real> &model, const Image<t_real> &solution) {
200  /*
201  Returns SNR of the estimated model image
202  */
203  t_int Npix = model.rows() * model.cols();
204  Image<t_real> model_ = model.array() + 1e-10;
205  Image<t_real> solution_ = solution.array() + 1e-10;
206  Image<t_real> model_sol = model_.matrix().cwiseQuotient(solution_.matrix());
207  Image<t_real> sol_model = solution_.matrix().cwiseQuotient(model_.matrix());
208  Image<t_real> min_ratio = sol_model.matrix().cwiseMin(model_sol.matrix());
209  t_real val = min_ratio.array().sum() / Npix;
210  return val;
211 }
212 
213 Sparse<t_complex> generate_vect(const t_uint &x_size, const t_uint &y_size, const t_real &sigma,
214  const t_real &mean) {
215  // t_real sigma = 3;
216  // const t_real pi = constant::pi;
217  t_int W = x_size;
218  Matrix<t_complex> chirp = Image<t_complex>::Zero(y_size, x_size);
219  // t_real mean = 0;
220  t_complex I(0, 1);
221  t_real step = W / 2;
222 
223  // t_complex sum = 0.0; // For accumulating the kernel values
224  for (int x = 0; x < W; ++x) {
225  for (int y = 0; y < W; ++y) {
226  t_int xx = x - step;
227  xx = xx * xx;
228  t_int yy = y - step;
229  yy = yy * yy;
230  t_complex val =
231  exp(-0.5 * (xx / (sigma * sigma) +
232  yy / (sigma * sigma))); //* std::exp(- 2 * pi * I * (x * 0.5 + y * 0.5));
233  if (std::abs(val) > 1e-5)
234  chirp(x, y) = val;
235  else
236  chirp(x, y) = 0.0;
237  }
238  }
239 
240  chirp.resize(x_size * y_size, 1);
241  Sparse<t_complex> chirp_ = chirp.sparseView(1e-5, 1);
242  return chirp_;
243 }
244 
245 } // namespace wproj_utilities
246 } // namespace purify
#define PURIFY_HIGH_LOG(...)
High priority message.
Definition: logging.h:203
#define PURIFY_DEBUG(...)
\macro Output some debugging
Definition: logging.h:197
const t_real pi
mathematical constant
Definition: types.h:70
K::Scalar mean(const K x)
Calculate mean of vector.
Definition: utilities.h:21
vis_params sort_by_w(const vis_params &uv_data)
Sort visibilities to be from w_max to w_min.
series
Type of series approximation.
Definition: types.h:64
std::vector< t_uint > w_rows(const Sparse< t_complex > &w_degrider)
t_real snr_metric(const Image< t_real > &model, const Image< t_real > &solution)
SNR calculation.
Matrix< t_complex > generate_chirp(const std::function< t_complex(t_real, t_real)> &dde, const t_real &w_rate, const t_real &cell_x, const t_real &cell_y, const t_uint &x_size, const t_uint &y_size)
t_real sparsify_row_thres(const Eigen::SparseMatrixBase< T > &row, const t_real &energy)
Returns threshold to keep a fraction of energy in the sparse row.
std::tuple< t_real, t_real > fov_cosines(t_real const &cell_x, t_real const &cell_y, t_uint const &x_size, t_uint const &y_size)
Work out max L and M directional cosines from image parameters.
t_real sparsify_row_dense_thres(const Eigen::MatrixBase< T > &row, const t_real &energy)
Returns threshold to keep a fraction of energy in the dense row.
Sparse< t_complex > create_chirp_row(const t_real &w_rate, const t_real &cell_x, const t_real &cell_y, const t_uint &ftsizev, const t_uint &ftsizeu, const t_real &energy_fraction, const sopt::OperatorFunction< Vector< t_complex >> &fftop)
Generates row of chirp matrix from image of chirp.
Sparse< t_complex > convert_sparse(const Eigen::MatrixBase< T > &M, const t_real &threshold=0.)
Convert from dense to sparse.
Matrix< t_complex > generate_dde(const std::function< t_complex(t_real, t_real)> &dde, const t_real &cell_x, const t_real &cell_y, const t_uint &x_size, const t_uint &y_size)
Generate image of DDE for A or W projection.
Sparse< t_complex > generate_vect(const t_uint &x_size, const t_uint &y_size, const t_real &sigma, const t_real &mean)
Genereates an image of a Gaussian as a sparse matrice.
t_real mr_metric(const Image< t_real > &model, const Image< t_real > &solution)
MR calculation.
Sparse< t_complex > row_wise_sparse_convolution(const Sparse< t_complex > &Grid_, const Sparse< T > &chirp_, const t_uint &x_size, const t_uint &y_size)
Sparse< t_complex > wprojection_matrix(const Sparse< t_complex > &G, const t_uint &x_size, const t_uint &y_size, const Vector< t_real > &w_components, const t_real &cell_x, const t_real &cell_y, const t_real &energy_fraction_chirp, const t_real &energy_fraction_wproj, const expansions::series series, const t_uint order, const t_real &interpolation_error)
Produce Gridding matrix convovled with chirp matrix for wprojection.
Eigen::SparseMatrix< T, Eigen::RowMajor, I > Sparse
A matrix of a given type.
Definition: types.h:40
Vector< t_complex > vis
Definition: uvw_utilities.h:22
t_uint size() const
return number of measurements
Definition: uvw_utilities.h:54
Vector< t_complex > weights
Definition: uvw_utilities.h:23