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_),
61 block_uvws_(std::move(source.block_uvws_)),
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_});
143 }
144 } else {
145 const uint64_t block = row / rows_per_block_;
146 ActivateBlock(block);
147 }
148 if (antenna1 != antenna2) {
149 if (antenna1 == reference_antenna_) {
150 // baseline = a2 - a1 with a1 = 0
151 const std::array<double, 3> ant2_uvw{uvw[0], uvw[1], uvw[2]};
152 StoreOrCheck(antenna2, ant2_uvw);
153 } else if (antenna2 == reference_antenna_) {
154 // baseline = a2 - a1 with a2 = 0
155 const std::array<double, 3> ant1_uvw{-uvw[0], -uvw[1], -uvw[2]};
156 StoreOrCheck(antenna1, ant1_uvw);
157 } else if (IsSet(antenna1)) {
158 // baseline = a2 - a1. Given a1:
159 // a2 = baseline + a1
160 const std::array<double, 3> ant1_uvw = block_uvws_[antenna1];
161 const std::array<double, 3> ant2_uvw{
162 uvw[0] + ant1_uvw[0], uvw[1] + ant1_uvw[1], uvw[2] + ant1_uvw[2]};
163 StoreOrCheck(antenna2, ant2_uvw);
164 } else if (IsSet(antenna2)) {
165 // baseline = a2 - a1. Given a2:
166 // a1 = a2 - baseline
167 const std::array<double, 3> ant2_uvw = block_uvws_[antenna2];
168 const std::array<double, 3> ant1_uvw{
169 ant2_uvw[0] - uvw[0], ant2_uvw[1] - uvw[1], ant2_uvw[2] - uvw[2]};
170 StoreOrCheck(antenna1, ant1_uvw);
171 } else {
172 throw std::runtime_error(
173 "Baselines are written in a non-ordered way: they need to be "
174 "ordered either by antenna 1 or by antenna 2");
175 }
176 }
177 n_rows_ = std::max(n_rows_, row + 1);
178 }
179
185 void ReadUvw(uint64_t row, size_t antenna1, size_t antenna2, double* uvw) {
186 assert(file_.IsOpen());
187 if (row >= n_rows_ || antenna1 >= n_antennas_ || antenna2 >= n_antennas_) {
188 throw std::runtime_error(
189 "Invalid read for Uvw data: row " + std::to_string(row) +
190 ", baseline (" + std::to_string(antenna1) + ", " +
191 std::to_string(antenna2) + ") was requested. File has only " +
192 std::to_string(n_rows_) + " rows.");
193 }
194 if (rows_per_block_ != 0) {
195 const uint64_t block = row / rows_per_block_;
196 ActivateBlock(block);
197 }
198 uvw[0] = block_uvws_[antenna2][0] - block_uvws_[antenna1][0];
199 uvw[1] = block_uvws_[antenna2][1] - block_uvws_[antenna1][1];
200 uvw[2] = block_uvws_[antenna2][2] - block_uvws_[antenna1][2];
201 }
202
203 void Close() {
204 if (file_.IsOpen()) {
205 if (rows_per_block_ == 0) {
207 n_antennas_ = block_uvws_.size();
208 WriteHeader();
209 }
210 if (block_is_changed_) {
212 }
213 file_.Close();
214 }
215 }
216
217 uint64_t NRows() const { return n_rows_; }
218 std::string Filename() const { return file_.Filename(); }
219
220 private:
224 UvwFile(const std::string& filename)
226 sizeof(double) * 3)) {}
227
232 UvwFile(const std::string& filename, bool /*open existing*/)
234 ReadHeader();
235 active_block_ = std::numeric_limits<uint64_t>::max();
236 if (n_antennas_ > 1) {
237 if (file_.NRows() % (n_antennas_ - 1) != 0) {
238 throw std::runtime_error(
239 "Uvw file has an incorrect number of rows (" +
240 std::to_string(file_.NRows()) + ", expecting multiple of " +
241 std::to_string(n_antennas_ - 1) + "): file corrupted?");
242 }
243 const uint64_t n_blocks = file_.NRows() / (n_antennas_ - 1);
244 n_rows_ = n_blocks * rows_per_block_;
245 }
247 throw std::runtime_error(
248 "Invalid combination of values for n_antenna and reference antenna "
249 "in file: file damaged?");
250 // Setting the size of block_uvws_ here, saves an extra size check in
251 // ActivateBlock().
253 }
254
262 void StoreOrCheck(size_t antenna, const std::array<double, 3>& antenna_uvw) {
263 if (IsSet(antenna)) {
264 if (!AreNear(block_uvws_[antenna], antenna_uvw)) {
265 std::ostringstream msg;
266 msg << "Inconsistent UVW value written for antenna " << antenna
267 << ": old value is " << UvwAsString(block_uvws_[antenna])
268 << ", new value is " << UvwAsString(antenna_uvw) << ".";
269 throw std::runtime_error(msg.str());
270 }
271 } else {
272 if (block_uvws_.size() <= antenna)
273 block_uvws_.resize(antenna + 1, kUnsetPosition);
274 block_uvws_[antenna] = antenna_uvw;
275 block_is_changed_ = true;
276 }
277 }
278
279 void ActivateBlock(size_t block) {
280 if (block != active_block_) {
281 if (block_is_changed_) {
283 }
284
285 active_block_ = block;
287 }
288 }
289
291 const uint64_t block_start_row = (n_antennas_ - 1) * active_block_;
292 if (block_start_row < file_.NRows()) {
293 block_uvws_.clear();
294 for (size_t antenna = 0; antenna != n_antennas_; ++antenna) {
295 if (antenna != reference_antenna_) {
296 const uint64_t row = antenna < reference_antenna_
297 ? block_start_row + antenna
298 : block_start_row + antenna - 1;
299 std::array<double, 3>& uvw = block_uvws_.emplace_back();
300 file_.Read(row, 0, uvw.data(), 3);
301 } else {
302 block_uvws_.emplace_back(std::array<double, 3>{0.0, 0.0, 0.0});
303 }
304 }
305 } else {
306 std::fill(block_uvws_.begin(), block_uvws_.end(), kUnsetPosition);
307 block_uvws_[reference_antenna_] = {0.0, 0.0, 0.0};
308 }
309 }
310
312 if (block_uvws_.size() != n_antennas_)
313 throw std::runtime_error("Trying to write an incomplete UVW block");
314 const uint64_t block_start_row = (n_antennas_ - 1) * active_block_;
315 for (size_t antenna = 0; antenna != n_antennas_; ++antenna) {
316 if (antenna != reference_antenna_) {
317 const uint64_t row = antenna < reference_antenna_
318 ? block_start_row + antenna
319 : block_start_row + antenna - 1;
320 file_.Write(row, 0, block_uvws_[antenna].data(), 3);
321 }
322 }
323 block_is_changed_ = false;
324 }
325
326 void ReadHeader() {
327 unsigned char data[kHeaderSize];
328 file_.ReadHeader(data);
329 if (!std::equal(data, data + 8, kMagicHeaderTag)) {
330 throw std::runtime_error(
331 "The UVW columnar file header not have the expected tag for UVW "
332 "columns: the measurement set may be damaged");
333 }
334 rows_per_block_ = reinterpret_cast<uint64_t&>(data[8]);
335 reference_antenna_ = reinterpret_cast<uint64_t&>(data[16]);
336 n_antennas_ = reinterpret_cast<uint64_t&>(data[24]);
337 }
338
339 void WriteHeader() {
340 unsigned char data[kHeaderSize];
341 std::copy_n(kMagicHeaderTag, 8, data);
342 reinterpret_cast<uint64_t&>(data[8]) = rows_per_block_;
343 reinterpret_cast<uint64_t&>(data[16]) = reference_antenna_;
344 reinterpret_cast<uint64_t&>(data[24]) = n_antennas_;
345 file_.WriteHeader(data);
346 }
347
348 bool IsSet(size_t antenna) const {
349 return block_uvws_.size() > antenna &&
350 block_uvws_[antenna] != kUnsetPosition;
351 }
352 static bool AreNear(std::array<double, 3> a, std::array<double, 3> b) {
353 return AreNear(a[0], b[0]) && AreNear(a[1], b[1]) && AreNear(a[2], b[2]);
354 }
355 static bool AreNear(double a, double b) {
356 const double magnitude = std::max({1e-5, std::fabs(a), std::fabs(b)});
357 return (std::fabs(a - b) / magnitude) < 1e-5;
358 }
359 static std::string UvwAsString(const std::array<double, 3>& uvw) {
360 std::ostringstream str;
361 str << "[" << uvw[0] << ", " << uvw[1] << ", " << uvw[2] << "]";
362 return str.str();
363 }
364
372 constexpr static size_t kHeaderSize = 32;
373 constexpr static const char kMagicHeaderTag[8] = "Uvw-col";
374 constexpr static std::array<double, 3> kUnsetPosition = {
375 std::numeric_limits<double>::max(), std::numeric_limits<double>::max(),
376 std::numeric_limits<double>::max()};
385 uint64_t n_rows_ = 0;
396 uint64_t rows_per_block_ = 0;
397 uint64_t active_block_ = 0;
399 // This value is used to determine the first baseline in the data, which is
400 // the baseline (reference_antenna_, start_antenna_2_).
402 size_t n_antennas_ = 0;
403 // UVW for each antenna in the block
404 std::vector<std::array<double, 3>> block_uvws_;
405 bool block_is_changed_ = false;
406};
407
408} // namespace casacore
409
410#endif
Stores values of a UVW column in a compressed way.
Definition UvwFile.h:49
std::string Filename() const
Definition UvwFile.h:218
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:372
uint64_t active_block_
Definition UvwFile.h:397
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:373
size_t n_antennas_
Definition UvwFile.h:402
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:396
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:405
BufferedColumnarFile file_
Definition UvwFile.h:377
uint64_t n_rows_
Number of rows in the Uvw column.
Definition UvwFile.h:385
static bool AreNear(std::array< double, 3 > a, std::array< double, 3 > b)
Definition UvwFile.h:352
std::vector< std::array< double, 3 > > block_uvws_
UVW for each antenna in the block.
Definition UvwFile.h:404
uint64_t NRows() const
Definition UvwFile.h:217
static bool AreNear(double a, double b)
Definition UvwFile.h:355
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:262
bool IsSet(size_t antenna) const
Definition UvwFile.h:348
void ReadHeader()
Definition UvwFile.h:326
UvwFile(const std::string &filename)
Create a new file on disk.
Definition UvwFile.h:224
static constexpr std::array< double, 3 > kUnsetPosition
Definition UvwFile.h:374
UvwFile & operator=(UvwFile &&rhs)
Definition UvwFile.h:75
size_t reference_antenna_
Definition UvwFile.h:398
static std::string UvwAsString(const std::array< double, 3 > &uvw)
Definition UvwFile.h:359
void ReadActiveBlock()
Definition UvwFile.h:290
UvwFile(const std::string &filename, bool)
Open an existing file from disk.
Definition UvwFile.h:232
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:401
void ReadUvw(uint64_t row, size_t antenna1, size_t antenna2, double *uvw)
Read a single row.
Definition UvwFile.h:185
void WriteActiveBlock()
Definition UvwFile.h:311
~UvwFile() noexcept
Definition UvwFile.h:73
void WriteHeader()
Definition UvwFile.h:339
void ActivateBlock(size_t block)
Definition UvwFile.h:279
void ReadHeader(unsigned char *data)
Read an optional extra header to the file.
const std::string & Filename() const
void WriteHeader(const unsigned char *data)
Write an optional extra header to the file.
uint64_t NRows() const
Total number of rows stored in this file.
void Read(uint64_t row, uint64_t column_offset, float *data, uint64_t n)
Read one cell containing an array of floats.
void Write(uint64_t row, uint64_t column_offset, const float *data, uint64_t n)
Write one cell containing an array of floats.
this file contains all the compiler specific defines
Definition mainpage.dox:28
Define real & complex conjugation for non-complex types and put comparisons into std namespace.
Definition Complex.h:350