casacore
Loading...
Searching...
No Matches
UvwFile.h
Go to the documentation of this file.
1#ifndef CASACORE_UVW_FILE_H_
2#define CASACORE_UVW_FILE_H_
3
5
6#include <algorithm>
7#include <cassert>
8#include <limits>
9#include <ostream>
10#include <stdexcept>
11#include <string>
12
13namespace casacore {
14
49class UvwFile {
50 public:
51 UvwFile() noexcept = default;
52
53 UvwFile(UvwFile&& source) noexcept
54 : file_(std::move(source.file_)),
55 n_rows_(source.n_rows_),
63 source.n_rows_ = 0;
64 source.rows_per_block_ = 0;
65 source.active_block_ = 0;
66 source.reference_antenna_ = 0;
67 source.start_antenna_2_ = 0;
68 source.n_antennas_ = 0;
69 source.block_uvws_.clear();
70 source.block_is_changed_ = false;
71 }
72
73 ~UvwFile() noexcept { Close(); }
74
76 Close();
77 file_ = std::move(rhs.file_);
78 n_rows_ = rhs.n_rows_;
79 rows_per_block_ = rhs.rows_per_block_;
80 active_block_ = rhs.active_block_;
81 reference_antenna_ = rhs.reference_antenna_;
82 start_antenna_2_ = rhs.start_antenna_2_;
83 n_antennas_ = rhs.n_antennas_;
84 block_uvws_ = std::move(rhs.block_uvws_);
85 block_is_changed_ = rhs.block_is_changed_;
86 rhs.n_rows_ = 0;
87 rhs.rows_per_block_ = 0;
88 rhs.active_block_ = 0;
89 rhs.reference_antenna_ = 0;
90 rhs.start_antenna_2_ = 0;
91 rhs.n_antennas_ = 0;
92 rhs.block_uvws_.clear();
93 rhs.block_is_changed_ = false;
94 return *this;
95 }
96
100 static UvwFile CreateNew(const std::string& filename) {
101 return UvwFile(filename);
102 }
103
107 static UvwFile OpenExisting(const std::string& filename) {
108 return UvwFile(filename, true);
109 }
110
116 void WriteUvw(uint64_t row, size_t antenna1, size_t antenna2,
117 const double* uvw) {
118 assert(file_.IsOpen());
119 if (row > n_rows_) {
120 throw std::runtime_error(
121 "Uvw data must be written in order (writing row " +
122 std::to_string(row) + ", after writing " + std::to_string(n_rows_) +
123 " rows)");
124 }
125 // The row/block is zero when there's not yet a full block written.
126 if (rows_per_block_ == 0) {
127 if (row == 0) {
128 reference_antenna_ = antenna1;
129 start_antenna_2_ = antenna2;
130 n_antennas_ = std::max(antenna1, antenna2) + 1;
132 block_uvws_[reference_antenna_] = {0.0, 0.0, 0.0};
133 } else if (antenna1 == reference_antenna_ &&
134 antenna2 == start_antenna_2_) {
135 // This baseline is the first baseline of a new block, so the block size
136 // can be determined
138 n_antennas_ = block_uvws_.size();
139 WriteHeader();
140 ActivateBlock(1);
141 } else {
142 n_antennas_ = std::max({antenna1 + 1, antenna2 + 1, n_antennas_});
144 }
145 } else {
146 const uint64_t block = row / rows_per_block_;
147 ActivateBlock(block);
148 }
149 if (antenna1 != antenna2) {
150 if (antenna1 == reference_antenna_) {
151 // baseline = a2 - a1 with a1 = 0
152 const std::array<double, 3> ant2_uvw{uvw[0], uvw[1], uvw[2]};
153 StoreOrCheck(antenna2, ant2_uvw);
154 } else if (antenna2 == reference_antenna_) {
155 // baseline = a2 - a1 with a2 = 0
156 const std::array<double, 3> ant1_uvw{-uvw[0], -uvw[1], -uvw[2]};
157 StoreOrCheck(antenna1, ant1_uvw);
158 } else if (IsSet(antenna1)) {
159 // baseline = a2 - a1. Given a1:
160 // a2 = baseline + a1
161 const std::array<double, 3> ant1_uvw = block_uvws_[antenna1];
162 const std::array<double, 3> ant2_uvw{
163 uvw[0] + ant1_uvw[0], uvw[1] + ant1_uvw[1], uvw[2] + ant1_uvw[2]};
164 StoreOrCheck(antenna2, ant2_uvw);
165 } else if (IsSet(antenna2)) {
166 // baseline = a2 - a1. Given a2:
167 // a1 = a2 - baseline
168 const std::array<double, 3> ant2_uvw = block_uvws_[antenna2];
169 const std::array<double, 3> ant1_uvw{
170 ant2_uvw[0] - uvw[0], ant2_uvw[1] - uvw[1], ant2_uvw[2] - uvw[2]};
171 StoreOrCheck(antenna1, ant1_uvw);
172 } else {
173 throw std::runtime_error(
174 "Baselines are written in a non-ordered way: they need to be "
175 "ordered either by antenna 1 or by antenna 2");
176 }
177 } else {
178 // In the special case of a file with only auto-correlations, the
179 // positions of the antennas can not be established in this case, it's
180 // also not necessary, because a zero uvw can be returned for
181 // auto-correlations. However, it will cause StoreOrCheck() to be
182 // never called, and therefore the block is never written to the file, and
183 // upon read the nr. of rows can not be determined. So, if this is an
184 // auto-correlation that has not yet been written, mark the block as
185 // changed so it gets written.
187 }
188 n_rows_ = std::max(n_rows_, row + 1);
189 }
190
196 void ReadUvw(uint64_t row, size_t antenna1, size_t antenna2, double* uvw) {
197 assert(file_.IsOpen());
198 if (row >= n_rows_ || antenna1 >= n_antennas_ || antenna2 >= n_antennas_) {
199 throw std::runtime_error(
200 "Invalid read for Uvw data: row " + std::to_string(row) +
201 ", baseline (" + std::to_string(antenna1) + ", " +
202 std::to_string(antenna2) + ") was requested. File has only " +
203 std::to_string(n_rows_) + " rows with " +
204 std::to_string(n_antennas_) + " antennas.");
205 }
206 if (rows_per_block_ != 0) {
207 const uint64_t block = row / rows_per_block_;
208 ActivateBlock(block);
209 }
210 uvw[0] = block_uvws_[antenna2][0] - block_uvws_[antenna1][0];
211 uvw[1] = block_uvws_[antenna2][1] - block_uvws_[antenna1][1];
212 uvw[2] = block_uvws_[antenna2][2] - block_uvws_[antenna1][2];
213 }
214
215 void Close() {
216 if (file_.IsOpen()) {
217 // This handles two special cases: i) if only one block of visibilities
218 // is written, no repetition of baseline would have been identified yet.
219 // In that case, we now know the block size. ii) in case only a single
220 // auto-correlation (one antenna) is written without any
221 // cross-correlations, the compressed file will remain empty. We then have
222 // to identify how many rows are really in the MS, which is done by
223 // setting rows_per_block_ to the nr of rows. When reading such an MS, the
224 // fact that n_antennas_ == 1 is then a trigger to use rows_per_block_ as
225 // nrows, instead of the size of the compressed file.
226 if (rows_per_block_ == 0) {
228 n_antennas_ = block_uvws_.size();
229 WriteHeader();
230 } else if (n_antennas_ == 1) {
232 WriteHeader();
233 }
234 if (block_is_changed_) {
236 }
237 file_.Close();
238 }
239 }
240
241 uint64_t NRows() const { return n_rows_; }
242 std::string Filename() const { return file_.Filename(); }
243
244 private:
248 UvwFile(const std::string& filename)
250 sizeof(double) * 3)) {}
251
256 UvwFile(const std::string& filename, bool /*open existing*/)
258 ReadHeader();
259 active_block_ = std::numeric_limits<uint64_t>::max();
260 if (n_antennas_ > 1) {
261 if (file_.NRows() % (n_antennas_ - 1) != 0) {
262 throw std::runtime_error(
263 "Uvw file has an incorrect number of rows (" +
264 std::to_string(file_.NRows()) + ", expecting multiple of " +
265 std::to_string(n_antennas_ - 1) + "): file corrupted?");
266 }
267 const uint64_t n_blocks = file_.NRows() / (n_antennas_ - 1);
268 n_rows_ = n_blocks * rows_per_block_;
269 } else if (n_antennas_ == 1) {
271 }
273 throw std::runtime_error(
274 "Invalid combination of values for n_antenna and reference antenna "
275 "in file: file damaged?");
276 // Setting the size of block_uvws_ here, saves an extra size check in
277 // ActivateBlock().
279 }
280
288 void StoreOrCheck(size_t antenna, const std::array<double, 3>& antenna_uvw) {
289 if (IsSet(antenna)) {
290 if (!AreNear(block_uvws_[antenna], antenna_uvw)) {
291 std::ostringstream msg;
292 msg << "Inconsistent UVW value written for antenna " << antenna
293 << ": old value is " << UvwAsString(block_uvws_[antenna])
294 << ", new value is " << UvwAsString(antenna_uvw) << ".";
295 throw std::runtime_error(msg.str());
296 }
297 } else {
298 if (block_uvws_.size() <= antenna)
299 block_uvws_.resize(antenna + 1, kUnsetPosition);
300 block_uvws_[antenna] = antenna_uvw;
301 block_is_changed_ = true;
302 }
303 }
304
305 void ActivateBlock(size_t block) {
306 if (block != active_block_) {
307 if (block_is_changed_) {
309 }
310
311 active_block_ = block;
313 }
314 }
315
317 const uint64_t block_start_row = (n_antennas_ - 1) * active_block_;
318 if (block_start_row < file_.NRows()) {
319 block_uvws_.clear();
320 for (size_t antenna = 0; antenna != n_antennas_; ++antenna) {
321 if (antenna != reference_antenna_) {
322 const uint64_t row = antenna < reference_antenna_
323 ? block_start_row + antenna
324 : block_start_row + antenna - 1;
325 std::array<double, 3>& uvw = block_uvws_.emplace_back();
326 file_.Read(row, 0, uvw.data(), 3);
327 } else {
328 block_uvws_.emplace_back(std::array<double, 3>{0.0, 0.0, 0.0});
329 }
330 }
331 } else {
332 std::fill(block_uvws_.begin(), block_uvws_.end(), kUnsetPosition);
333 block_uvws_[reference_antenna_] = {0.0, 0.0, 0.0};
334 }
335 }
336
338 if (block_uvws_.size() != n_antennas_)
339 throw std::runtime_error("Trying to write an incomplete UVW block");
340 const uint64_t block_start_row = (n_antennas_ - 1) * active_block_;
341 for (size_t antenna = 0; antenna != n_antennas_; ++antenna) {
342 if (antenna != reference_antenna_) {
343 const uint64_t row = antenna < reference_antenna_
344 ? block_start_row + antenna
345 : block_start_row + antenna - 1;
346 file_.Write(row, 0, block_uvws_[antenna].data(), 3);
347 }
348 }
349 block_is_changed_ = false;
350 }
351
352 void ReadHeader() {
353 unsigned char data[kHeaderSize];
354 file_.ReadHeader(data);
355 if (!std::equal(data, data + 8, kMagicHeaderTag)) {
356 throw std::runtime_error(
357 "The UVW columnar file header not have the expected tag for UVW "
358 "columns: the measurement set may be damaged");
359 }
360 rows_per_block_ = reinterpret_cast<uint64_t&>(data[8]);
361 reference_antenna_ = reinterpret_cast<uint64_t&>(data[16]);
362 n_antennas_ = reinterpret_cast<uint64_t&>(data[24]);
363 }
364
365 void WriteHeader() {
366 unsigned char data[kHeaderSize];
367 std::copy_n(kMagicHeaderTag, 8, data);
368 reinterpret_cast<uint64_t&>(data[8]) = rows_per_block_;
369 reinterpret_cast<uint64_t&>(data[16]) = reference_antenna_;
370 reinterpret_cast<uint64_t&>(data[24]) = n_antennas_;
371 file_.WriteHeader(data);
372 }
373
374 bool IsSet(size_t antenna) const {
375 return block_uvws_.size() > antenna &&
376 block_uvws_[antenna] != kUnsetPosition;
377 }
378 static bool AreNear(std::array<double, 3> a, std::array<double, 3> b) {
379 return AreNear(a[0], b[0]) && AreNear(a[1], b[1]) && AreNear(a[2], b[2]);
380 }
381 static bool AreNear(double a, double b) {
382 const double magnitude = std::max({1e-5, std::fabs(a), std::fabs(b)});
383 return (std::fabs(a - b) / magnitude) < 1e-5;
384 }
385 static std::string UvwAsString(const std::array<double, 3>& uvw) {
386 std::ostringstream str;
387 str << "[" << uvw[0] << ", " << uvw[1] << ", " << uvw[2] << "]";
388 return str.str();
389 }
390
398 constexpr static size_t kHeaderSize = 32;
399 constexpr static const char kMagicHeaderTag[8] = "Uvw-col";
400 constexpr static std::array<double, 3> kUnsetPosition = {
401 std::numeric_limits<double>::max(), std::numeric_limits<double>::max(),
402 std::numeric_limits<double>::max()};
411 uint64_t n_rows_ = 0;
422 uint64_t rows_per_block_ = 0;
423 uint64_t active_block_ = 0;
425 // This value is used to determine the first baseline in the data, which is
426 // the baseline (reference_antenna_, start_antenna_2_).
428 size_t n_antennas_ = 0;
429 // UVW for each antenna in the block
430 std::vector<std::array<double, 3>> block_uvws_;
431 bool block_is_changed_ = false;
432};
433
434} // namespace casacore
435
436#endif
std::string Filename() const
Definition UvwFile.h:242
static constexpr size_t kHeaderSize
The header: char[8] "Uvw-col\0" (=kMagicHeaderTag) uint64_t rows_per_block uint64_t reference_antenna...
Definition UvwFile.h:398
uint64_t active_block_
Definition UvwFile.h:423
static UvwFile OpenExisting(const std::string &filename)
Open an already existing UVW file from disk with the given filename.
Definition UvwFile.h:107
static constexpr const char kMagicHeaderTag[8]
Definition UvwFile.h:399
size_t n_antennas_
Definition UvwFile.h:428
static UvwFile CreateNew(const std::string &filename)
Create a new UVW file on disk with the given filename.
Definition UvwFile.h:100
uint64_t rows_per_block_
A "block" is a contiguous number of baselines that together form one timestep.
Definition UvwFile.h:422
void WriteUvw(uint64_t row, size_t antenna1, size_t antenna2, const double *uvw)
Write a single row to the column.
Definition UvwFile.h:116
bool block_is_changed_
Definition UvwFile.h:431
BufferedColumnarFile file_
Definition UvwFile.h:403
uint64_t n_rows_
Number of rows in the Uvw column.
Definition UvwFile.h:411
static bool AreNear(std::array< double, 3 > a, std::array< double, 3 > b)
Definition UvwFile.h:378
std::vector< std::array< double, 3 > > block_uvws_
UVW for each antenna in the block.
Definition UvwFile.h:430
uint64_t NRows() const
Definition UvwFile.h:241
static bool AreNear(double a, double b)
Definition UvwFile.h:381
void StoreOrCheck(size_t antenna, const std::array< double, 3 > &antenna_uvw)
If this block does not have a value for the specified antenna, store the uvw value for it.
Definition UvwFile.h:288
bool IsSet(size_t antenna) const
Definition UvwFile.h:374
void ReadHeader()
Definition UvwFile.h:352
UvwFile(const std::string &filename)
Create a new file on disk.
Definition UvwFile.h:248
static constexpr std::array< double, 3 > kUnsetPosition
Definition UvwFile.h:400
UvwFile & operator=(UvwFile &&rhs)
Definition UvwFile.h:75
size_t reference_antenna_
Definition UvwFile.h:424
static std::string UvwAsString(const std::array< double, 3 > &uvw)
Definition UvwFile.h:385
void ReadActiveBlock()
Definition UvwFile.h:316
UvwFile(const std::string &filename, bool)
Open an existing file from disk.
Definition UvwFile.h:256
UvwFile() noexcept=default
size_t start_antenna_2_
This value is used to determine the first baseline in the data, which is the baseline (reference_ante...
Definition UvwFile.h:427
void ReadUvw(uint64_t row, size_t antenna1, size_t antenna2, double *uvw)
Read a single row.
Definition UvwFile.h:196
void WriteActiveBlock()
Definition UvwFile.h:337
~UvwFile() noexcept
Definition UvwFile.h:73
void WriteHeader()
Definition UvwFile.h:365
void ActivateBlock(size_t block)
Definition UvwFile.h:305
this file contains all the compiler specific defines
Definition mainpage.dox:28
void move(TYPE *target, int npixels) const
VarBufferedColumnarFile< 100 *1024 > BufferedColumnarFile
Define real & complex conjugation for non-complex types and put comparisons into std namespace.
Definition Complex.h:350