PURIFY
Next-generation radio interferometric imaging
uvw_utilities.cc
Go to the documentation of this file.
1 #include "purify/uvw_utilities.h"
2 #include "purify/config.h"
3 #ifdef PURIFY_H5
4 #include "purify/h5reader.h"
5 #endif
6 #include <fstream>
7 #include <random>
8 #include <sys/stat.h>
9 #include "purify/logging.h"
10 #include "purify/operators.h"
11 
12 namespace purify {
13 namespace utilities {
14 
15 bool has_suffix(const std::string &str, const std::string &suff) {
16  return str.size() >= suff.size() && str.compare(str.size() - suff.size(), suff.size(), suff) == 0;
17 }
18 
19 Matrix<t_real> generate_antennas(const t_uint N, const t_real scale) {
20  Matrix<t_real> B = Matrix<t_real>::Zero(N, 3);
21  const t_real mean = 0;
22  const t_real standard_deviation = scale;
23  auto sample = [&mean, &standard_deviation]() {
24  std::random_device rd;
25  std::mt19937_64 rng(rd());
26  t_real output = 4 * standard_deviation + mean;
27  static std::normal_distribution<> normal_dist(mean, standard_deviation);
28  // ensures that all sample points are within bounds
29  while (std::abs(output - mean) > 3 * standard_deviation) {
30  output = normal_dist(rng);
31  }
32  if (output != output) PURIFY_DEBUG("New random-sample density: {}", output);
33  return output;
34  };
35  for (t_uint i = 0; i < N; i++) {
36  B(i, 0) = sample();
37  B(i, 1) = sample();
38  B(i, 2) = sample();
39  }
40  return B * scale;
41 }
42 
43 utilities::vis_params antenna_to_coverage(const Matrix<t_real> &B, const t_real frequency,
44  const t_real times, const t_real theta_ra,
45  const t_real phi_dec, const t_real latitude) {
46  return antenna_to_coverage(B, std::vector<t_real>(1, frequency), std::vector<t_real>(1, times),
47  theta_ra, phi_dec, latitude);
48 }
49 
50 utilities::vis_params antenna_to_coverage(const Matrix<t_real> &B, const t_real frequency,
51  const std::vector<t_real> &times, const t_real theta_ra,
52  const t_real phi_dec, const t_real latitude) {
53  return antenna_to_coverage(B, std::vector<t_real>(1, frequency), times, theta_ra, phi_dec,
54  latitude);
55 }
56 
58  const std::vector<t_real> &frequency, const t_real times,
59  const t_real theta_ra, const t_real phi_dec,
60  const t_real latitude) {
61  return antenna_to_coverage(B, frequency, std::vector<t_real>(1, times), theta_ra, phi_dec,
62  latitude);
63 }
64 
66  const std::vector<t_real> &frequencies,
67  const std::vector<t_real> times, const t_real theta_ra,
68  const t_real phi_dec, const t_real latitude) {
69  auto const position_angle_RA_function = [theta_ra](const t_real t) -> t_real {
70  return theta_ra + constant::omega_e * t;
71  };
72  auto const position_angle_DEC_function = [phi_dec](const t_real t) -> t_real { return phi_dec; };
73  return antenna_to_coverage_general<std::function<t_real(t_real)>>(
74  B, frequencies, times, position_angle_RA_function, position_angle_DEC_function, latitude);
75 }
76 
77 Matrix<t_real> read_ant_positions(const std::string &pos_name) {
78  /*
79  Reads an csv file with x, y, z (meters) and returns the vectors as a matrix (x, y, z) cols.
80 
81  vis_name:: name of input text file containing [x, y, z] (separated by ' ').
82  */
83  std::ifstream pos_file(pos_name);
84  pos_file.precision(13);
85  t_int row = 0;
86  std::string line;
87  // counts size of pos file
88  while (std::getline(pos_file, line)) ++row;
89  if (row < 1) throw std::runtime_error("No positions in the file: " + pos_name);
90  Matrix<t_real> B = Matrix<t_real>::Zero(row, 3);
91 
92  pos_file.clear();
93  pos_file.seekg(0);
94  // reads in vis file
95  for (row = 0; row < B.rows(); ++row) {
96  B(row, 0) = streamtoreal(pos_file);
97  B(row, 1) = streamtoreal(pos_file);
98  B(row, 2) = streamtoreal(pos_file);
99  }
100 
101  return B;
102 }
103 
104 utilities::vis_params random_sample_density(const t_int vis_num, const t_real mean,
105  const t_real standard_deviation, const t_real rms_w) {
106  /*
107  Generates a random sampling density for visibility coverage
108  vis_num:: number of visibilities
109  mean:: mean of distribution
110  standard_deviation:: standard deviation of distirbution
111  */
112  auto sample = [&mean, &standard_deviation]() {
113  std::random_device rd;
114  std::mt19937_64 rng(rd());
115  t_real output = 4 * standard_deviation + mean;
116  static std::normal_distribution<> normal_dist(mean, standard_deviation);
117  // ensures that all sample points are within bounds
118  while (std::abs(output - mean) > 3 * standard_deviation) {
119  output = normal_dist(rng);
120  }
121  if (output != output) PURIFY_DEBUG("New random-sample density: {}", output);
122  return output;
123  };
124 
125  utilities::vis_params uv_vis;
126  uv_vis.u = Vector<t_real>::Zero(vis_num);
127  uv_vis.v = Vector<t_real>::Zero(vis_num);
128  uv_vis.w = Vector<t_real>::Zero(vis_num);
129  // #pragma omp parallel for
130  for (t_uint i = 0; i < vis_num; i++) {
131  uv_vis.u(i) = sample();
132  uv_vis.v(i) = sample();
133  uv_vis.w(i) = sample();
134  }
135  uv_vis.w = uv_vis.w / standard_deviation * rms_w;
136  uv_vis.weights = Vector<t_complex>::Constant(vis_num, 1);
137  uv_vis.vis = Vector<t_complex>::Constant(vis_num, 1);
138  uv_vis.ra = 0;
139  uv_vis.dec = 0;
140  uv_vis.average_frequency = 0;
141  return uv_vis;
142 }
143 
144 utilities::vis_params read_visibility(const std::vector<std::string> &names, const bool w_term) {
145  utilities::vis_params output = read_visibility(names.at(0), w_term);
146  if (names.size() == 1) return output;
147  for (int i = 1; i < names.size(); i++) output = read_visibility(names.at(i), output);
148  return output;
149 }
150 utilities::vis_params read_visibility(const std::string &vis_name2,
151  const utilities::vis_params &uv1) {
152  const bool w_term = not uv1.w.isZero(0);
153 
154  const auto uv2 = read_visibility(vis_name2, w_term);
156  uv.u = Vector<t_real>::Zero(uv1.size() + uv2.size());
157  uv.v = Vector<t_real>::Zero(uv1.size() + uv2.size());
158  uv.w = Vector<t_real>::Zero(uv1.size() + uv2.size());
159  uv.vis = Vector<t_complex>::Zero(uv1.size() + uv2.size());
160  uv.weights = Vector<t_complex>::Zero(uv1.size() + uv2.size());
161  uv.u.segment(0, uv1.size()) = uv1.u;
162  uv.v.segment(0, uv1.size()) = uv1.v;
163  uv.w.segment(0, uv1.size()) = uv1.w;
164  uv.vis.segment(0, uv1.size()) = uv1.vis;
165  uv.weights.segment(0, uv1.size()) = uv1.weights;
166  uv.u.segment(uv1.size(), uv2.size()) = uv2.u;
167  uv.v.segment(uv1.size(), uv2.size()) = uv2.v;
168  uv.w.segment(uv1.size(), uv2.size()) = uv2.w;
169  uv.vis.segment(uv1.size(), uv2.size()) = uv2.vis;
170  uv.weights.segment(uv1.size(), uv2.size()) = uv2.weights;
171  return uv;
172 }
173 
175 t_real streamtoreal(std::ifstream &stream) {
176  std::string input;
177  stream >> input;
178  return std::stod(input);
179 }
180 
181 utilities::vis_params read_visibility_csv(const std::string &vis_name, const bool w_term) {
182  /*
183  Reads an csv file with u, v, visibilities and returns the vectors.
184 
185  vis_name:: name of input text file containing [u, v, real(V), imag(V)] (separated by ' ').
186  */
187  std::ifstream vis_file(vis_name);
188  if (vis_file) {
189  PURIFY_LOW_LOG("File {} successfully opened", vis_name);
190  } else {
191  throw std::runtime_error("Could not open file " + vis_name);
192  }
193  vis_file.precision(13);
194  t_int row = 0;
195  std::string line;
196  // counts size of vis file
197  while (std::getline(vis_file, line)) ++row;
198  Vector<t_real> utemp = Vector<t_real>::Zero(row);
199  Vector<t_real> vtemp = Vector<t_real>::Zero(row);
200  Vector<t_real> wtemp = Vector<t_real>::Zero(row);
201  Vector<t_complex> vistemp = Vector<t_complex>::Zero(row);
202  Vector<t_complex> weightstemp = Vector<t_complex>::Zero(row);
203 
204  vis_file.clear();
205  vis_file.seekg(0);
206  // reads in vis file
207  t_real real;
208  t_real imag;
209  t_real entry;
210  for (row = 0; row < vistemp.size(); ++row) {
211  utemp(row) = streamtoreal(vis_file);
212  vtemp(row) = streamtoreal(vis_file);
213  if (w_term) {
214  wtemp(row) = streamtoreal(vis_file);
215  }
216  real = streamtoreal(vis_file);
217  imag = streamtoreal(vis_file);
218  entry = streamtoreal(vis_file);
219  vistemp(row) = t_complex(real, imag);
220  weightstemp(row) = 1 / entry;
221  }
222  utilities::vis_params uv_vis;
223  uv_vis.u = utemp;
224  uv_vis.v = -vtemp; // found that a reflection is needed for the orientation of the gridded image
225  // to be correct
226  uv_vis.w = wtemp;
227  uv_vis.vis = vistemp;
228  uv_vis.weights = weightstemp;
229  uv_vis.ra = 0;
230  uv_vis.dec = 0;
231  uv_vis.average_frequency = 0;
232 
233  return uv_vis;
234 }
235 
236 utilities::vis_params read_visibility(const std::string &vis_name, const bool w_term) {
237 #ifdef PURIFY_H5
238  if (has_suffix(vis_name, ".h5")) return H5::read_visibility(vis_name, w_term);
239 #endif
240  return read_visibility_csv(vis_name, w_term);
241 }
242 
243 void write_visibility(const utilities::vis_params &uv_vis, const std::string &file_name,
244  const bool w_term) {
245  /*
246  writes visibilities to output text file (currently ignores w-component)
247  uv_vis:: input uv data
248  file_name:: name of output text file
249  */
250  std::ofstream out(file_name);
251  out.precision(13);
252  for (t_int i = 0; i < uv_vis.u.size(); ++i) {
253  out << uv_vis.u(i) << " " << -uv_vis.v(i) << " ";
254  if (w_term) out << uv_vis.w(i) << " ";
255  out << std::real(uv_vis.vis(i)) << " " << std::imag(uv_vis.vis(i)) << " "
256  << 1. / std::real(uv_vis.weights(i)) << std::endl;
257  }
258  out.close();
259 }
260 
261 utilities::vis_params set_cell_size(const utilities::vis_params &uv_vis, const t_real &max_u,
262  const t_real &max_v, const t_real &input_cell_size_u,
263  const t_real &input_cell_size_v) {
264  /*
265  Converts the units of visibilities to units of 2 * pi, while scaling for the size of a pixel
266  (cell_size)
267 
268  uv_vis:: visibilities
269  cell_size:: size of a pixel in arcseconds
270  */
271 
272  utilities::vis_params scaled_vis = uv_vis;
273  t_real cell_size_u = input_cell_size_u;
274  t_real cell_size_v = input_cell_size_v;
275  if (cell_size_u == 0 and cell_size_v == 0) {
276  cell_size_u = (180 * 3600) / max_u / constant::pi / 3; // Calculate cell size if not given one
277 
278  cell_size_v = (180 * 3600) / max_v / constant::pi / 3; // Calculate cell size if not given one
279  // PURIFY_MEDIUM_LOG("PSF has a FWHM of {} by {} arcseconds", cell_size_u * 3, cell_size_v * 3);
280  }
281  if (cell_size_v == 0) {
282  cell_size_v = cell_size_u;
283  }
284 
285  PURIFY_MEDIUM_LOG("Using a pixel size of {} by {} arcseconds", cell_size_u, cell_size_v);
286  t_real scale_factor_u = 1;
287  t_real scale_factor_v = 1;
288  if (uv_vis.units == utilities::vis_units::lambda) {
289  scale_factor_u = 180 * 3600 / cell_size_u / constant::pi;
290  scale_factor_v = 180 * 3600 / cell_size_v / constant::pi;
291  scaled_vis.w = uv_vis.w;
292  }
293  if (uv_vis.units == utilities::vis_units::radians) {
294  scale_factor_u = 180 * 3600 / constant::pi;
295  scale_factor_v = 180 * 3600 / constant::pi;
296  scaled_vis.w = uv_vis.w;
297  }
298  scaled_vis.u = uv_vis.u / scale_factor_u * 2 * constant::pi;
299  scaled_vis.v = uv_vis.v / scale_factor_v * 2 * constant::pi;
300 
302  return scaled_vis;
303 }
304 utilities::vis_params set_cell_size(const utilities::vis_params &uv_vis, const t_real &cell_size_u,
305  const t_real &cell_size_v) {
306  const t_real max_u = std::sqrt((uv_vis.u.array() * uv_vis.u.array()).maxCoeff());
307  const t_real max_v = std::sqrt((uv_vis.v.array() * uv_vis.v.array()).maxCoeff());
308  return set_cell_size(uv_vis, max_u, max_v, cell_size_u, cell_size_v);
309 }
310 
311 utilities::vis_params uv_scale(const utilities::vis_params &uv_vis, const t_int &sizex,
312  const t_int &sizey) {
313  /*
314  scales the uv coordinates from being in units of 2 * pi to units of pixels.
315  */
316  utilities::vis_params scaled_vis;
317  scaled_vis.u = uv_vis.u / (2 * constant::pi) * sizex;
318  scaled_vis.v = uv_vis.v / (2 * constant::pi) * sizey;
319  scaled_vis.vis = uv_vis.vis;
320  scaled_vis.weights = uv_vis.weights;
321  for (t_int i = 0; i < uv_vis.u.size(); ++i) {
322  // scaled_vis.u(i) = utilities::mod(scaled_vis.u(i), sizex);
323  // scaled_vis.v(i) = utilities::mod(scaled_vis.v(i), sizey);
324  }
325  scaled_vis.w = uv_vis.w;
326  scaled_vis.units = utilities::vis_units::pixels;
327  scaled_vis.ra = uv_vis.ra;
328  scaled_vis.dec = uv_vis.dec;
329  scaled_vis.average_frequency = uv_vis.average_frequency;
330  return scaled_vis;
331 }
333  const t_real cell_y, const t_real imsizex,
334  const t_real imsizey, const t_real oversample_ratio) {
335  t_real du = 1;
336  t_real dv = 1;
337  if (uv_vis.units == utilities::vis_units::lambda) {
338  du = widefield::pixel_to_lambda(cell_x, imsizex, oversample_ratio);
339  dv = widefield::pixel_to_lambda(cell_y, imsizey, oversample_ratio);
340  }
341  if (uv_vis.units == utilities::vis_units::radians) {
342  du = constant::pi / std::floor(imsizex * oversample_ratio);
343  dv = constant::pi / std::floor(imsizey * oversample_ratio);
344  }
345  auto out = uv_vis;
346  out.u = uv_vis.u / du;
347  out.v = uv_vis.v / dv;
348  out.units = utilities::vis_units::pixels;
349  return out;
350 }
351 
353  utilities::vis_params output = uv_vis;
354 #pragma omp parallel for
355  for (t_uint i = 0; i < output.size(); i++) {
356  if (uv_vis.w(i) < 0) {
357  output.w(i) = -uv_vis.w(i);
358  output.v(i) = -uv_vis.v(i);
359  output.u(i) = -uv_vis.u(i);
360  output.vis(i) = std::conj(uv_vis.vis(i));
361  }
362  assert(output.w(i) >= 0);
363  }
364  return output;
365 }
366 } // namespace utilities
367 } // namespace purify
#define PURIFY_LOW_LOG(...)
Low priority message.
Definition: logging.h:207
#define PURIFY_DEBUG(...)
\macro Output some debugging
Definition: logging.h:197
#define PURIFY_MEDIUM_LOG(...)
Medium priority message.
Definition: logging.h:205
utilities::vis_params read_visibility(const std::string &vis_name, const bool w_term)
Reads an HDF5 file with u,v visibilities, constructs a vis_params object and returns it.
Definition: h5reader.h:166
const t_real pi
mathematical constant
Definition: types.h:70
const t_real omega_e
angular velocity of the earth rad/s
Definition: types.h:74
void write_visibility(const utilities::vis_params &uv_vis, const std::string &file_name, const bool w_term)
Writes visibilities to txt.
utilities::vis_params antenna_to_coverage(const Matrix< t_real > &B, const t_real frequency, const t_real times, const t_real theta_ra, const t_real phi_dec, const t_real latitude)
Provided antenna positions generate a coverage for a fixed frequency a fixed time.
Matrix< t_real > generate_antennas(const t_uint N, const t_real scale)
Generate guassianly distributed (sigma = scale) antenna positions.
utilities::vis_params antenna_to_coverage_general(const Matrix< t_real > &B, const std::vector< t_real > &frequencies, const std::vector< t_real > &times, const F &position_angle_RA_function, const F &position_angle_DEC_function, const t_real latitude)
utilities::vis_params convert_to_pixels(const utilities::vis_params &uv_vis, const t_real cell_x, const t_real cell_y, const t_real imsizex, const t_real imsizey, const t_real oversample_ratio)
Converts u and v coordaintes to units of pixels.
utilities::vis_params uv_scale(const utilities::vis_params &uv_vis, const t_int &sizex, const t_int &sizey)
scales the visibilities to units of pixels
K::Scalar mean(const K x)
Calculate mean of vector.
Definition: utilities.h:21
t_real streamtoreal(std::ifstream &stream)
Reading reals from visibility file (including nan's and inf's)
Matrix< t_real > read_ant_positions(const std::string &pos_name)
Read in a text file of antenna positions into a matrix [x, y ,z].
bool has_suffix(const std::string &str, const std::string &suff)
utilities::vis_params conjugate_w(const utilities::vis_params &uv_vis)
reflects visibilities into the w >= 0 domain
utilities::vis_params read_visibility(const std::vector< std::string > &names, const bool w_term)
Read visibility files from name of vector.
utilities::vis_params set_cell_size(const sopt::mpi::Communicator &comm, utilities::vis_params const &uv_vis, const t_real &cell_x, const t_real &cell_y)
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 standard_deviation(const K x)
Calculates the standard deviation of a vector.
Definition: utilities.h:34
utilities::vis_params read_visibility_csv(const std::string &vis_name, const bool w_term)
Reads in visibility csv file.
t_real pixel_to_lambda(const t_real cell, const t_uint imsize, const t_real oversample_ratio)
return factors to convert between arcsecond pixel size image space and lambda for uv space
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