1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
|
#include "visibilitymodifier.h"
#include "../msproviders/synchronizedms.h"
#include "../structures/observationinfo.h"
#ifdef HAVE_EVERYBEAM
#include <EveryBeam/load.h>
#include <EveryBeam/aterms/atermconfig.h>
#include <EveryBeam/pointresponse/phasedarraypoint.h>
#endif
// Only needed for EB/H5Parm related options
#include "../io/findmwacoefffile.h"
#include "solutionchannelinterpolation.h"
using aocommon::MC2x2F;
namespace wsclean {
namespace {
void setNonFiniteToZero(std::vector<std::complex<float>>& values) {
for (std::complex<float>& v : values) {
if (!std::isfinite(v.real()) || !std::isfinite(v.imag())) {
v = 0.0;
}
}
}
} // namespace
void VisibilityModifier::InitializeTimeFrequencySmearing(
const ObservationInfo& observation_info, double interval) {
/**
* Length of a sidereal day in seconds.
*/
constexpr double kSiderealDay = 86164.0905;
const double angular_speed = 2 * M_PI * interval / kSiderealDay;
// scaled_ncp_uvw_ is initialized with the NCP for epoch J2000.
// The expression is simpler than for the the current epoch (of the
// observation). The first element is zero and that is currently assumed where
// scaled_ncp_uvw_ is used. If the initialization here is modified to the more
// accurate current epoch with a non-zero first element, please update the
// usage as well
scaled_ncp_uvw_[0] = 0.0;
scaled_ncp_uvw_[1] =
angular_speed * std::cos(observation_info.phaseCentreDec);
scaled_ncp_uvw_[2] =
angular_speed * std::sin(observation_info.phaseCentreDec);
}
void VisibilityModifier::InitializePointResponse(
SynchronizedMS&& ms, double facet_beam_update_time,
const std::string& element_response, const aocommon::MultiBandData& bands,
const std::string& data_column, const std::string& mwa_path) {
#ifdef HAVE_EVERYBEAM
// Hard-coded for now
const bool frequency_interpolation = true;
const bool use_channel_frequency = true;
// Get path to coefficient file for MWA telescope
everybeam::TelescopeType telescope_type = everybeam::GetTelescopeType(*ms);
const std::string coeff_path =
(telescope_type == everybeam::TelescopeType::kMWATelescope)
? wsclean::mwa::FindCoeffFile(mwa_path)
: "";
everybeam::ATermSettings aterm_settings;
aterm_settings.coeff_path = coeff_path;
aterm_settings.data_column_name = data_column;
everybeam::Options options =
everybeam::aterms::ATermConfig::ConvertToEBOptions(
*ms, aterm_settings, frequency_interpolation, _beamNormalisationMode,
use_channel_frequency, element_response, _beamModeString);
_beamMode = options.beam_mode;
_telescope = everybeam::Load(*ms, options);
// Initialize with 0.0 time to make sure first call to UpdateTime()
// will fill the beam response cache.
_pointResponse = _telescope->GetPointResponse(0.0);
_pointResponse->SetUpdateInterval(facet_beam_update_time);
n_stations_ = _telescope->GetNrStations();
for (size_t data_desc_id : bands.DataDescIds()) {
std::vector<aocommon::MC2x2F>& band_response =
_cachedBeamResponse.AlwaysEmplace(data_desc_id);
band_response.resize(bands[data_desc_id].ChannelCount() * n_stations_);
}
#endif
}
void VisibilityModifier::InitializeMockResponse(
size_t n_channels, size_t n_stations, size_t data_desc_id,
const std::vector<aocommon::MC2x2F>& beam_response,
const std::vector<std::complex<float>>& parm_response) {
n_stations_ = n_stations;
assert(beam_response.size() == n_channels * n_stations);
assert(parm_response.size() == n_channels * n_stations * 2 ||
parm_response.size() == n_channels * n_stations * 4);
#ifdef HAVE_EVERYBEAM
std::vector<aocommon::MC2x2F>& band_beam_response =
_cachedBeamResponse.AlwaysEmplace(data_desc_id);
band_beam_response.assign(beam_response.begin(), beam_response.end());
#endif
SolutionsResponseMap& band_parm_response =
_cachedParmResponse.emplace(0, SolutionsResponseMap()).first->second;
band_parm_response.AlwaysEmplace(data_desc_id) = parm_response;
time_offsets_ = {std::pair(0, 0)};
}
void VisibilityModifier::InitializeCacheParmResponse(
const std::vector<std::string>& antennaNames,
const aocommon::MultiBandData& selected_bands, size_t ms_index) {
using schaapcommon::h5parm::JonesParameters;
const size_t solution_index = (*_h5parms).size() == 1 ? 0 : ms_index;
// Only extract DD solutions if the corresponding cache entry is empty.
SolutionsResponseMap& parm_response = _cachedParmResponse[ms_index];
if (parm_response.Empty()) {
const size_t nparms = NValuesPerSolution(ms_index);
const size_t n_times = _cachedMSTimes[ms_index]->size();
const std::string dir_name = (*_h5parms)[solution_index].GetNearestSource(
_facetDirectionRA, _facetDirectionDec);
schaapcommon::h5parm::SolTab* const first_solution =
(*_firstSolutions)[solution_index];
schaapcommon::h5parm::SolTab* const second_solution =
_secondSolutions->empty() ? nullptr
: (*_secondSolutions)[solution_index];
const size_t dir_index = first_solution->GetDirIndex(dir_name);
if (uses_bda_) {
// In BDA mode, the channels are interpolated from the data_desc_id with
// the most channels, to avoid rereading the file many times.
const size_t max_channel_id = selected_bands.DataDescIdWithMaxChannels();
const aocommon::BandData& band = selected_bands[max_channel_id];
const std::vector<double> freqs(band.begin(), band.end());
const size_t response_size =
n_times * freqs.size() * antennaNames.size() * nparms;
JonesParameters jones_parameters(
freqs, *_cachedMSTimes[ms_index], antennaNames,
(*_gainTypes)[solution_index],
JonesParameters::InterpolationType::NEAREST, dir_index,
first_solution, second_solution, false, 0u,
JonesParameters::MissingAntennaBehavior::kUnit);
// parms (Casacore::Cube) is column major
const casacore::Cube<std::complex<float>>& parms =
jones_parameters.GetParms();
std::vector<std::complex<float>> full_channel_response(
&parms(0, 0, 0), &parms(0, 0, 0) + response_size);
for (size_t data_desc_id : selected_bands.DataDescIds()) {
std::vector<std::complex<float>>& band_response =
parm_response.AlwaysEmplace(data_desc_id);
InterpolateChannels(full_channel_response, band, band_response,
selected_bands[data_desc_id], n_times,
antennaNames.size() * nparms);
setNonFiniteToZero(band_response);
}
} else {
for (size_t data_desc_id : selected_bands.DataDescIds()) {
const aocommon::BandData& band = selected_bands[data_desc_id];
const std::vector<double> freqs(band.begin(), band.end());
const size_t response_size =
n_times * freqs.size() * antennaNames.size() * nparms;
JonesParameters jones_parameters(
freqs, *_cachedMSTimes[ms_index], antennaNames,
(*_gainTypes)[solution_index],
JonesParameters::InterpolationType::NEAREST, dir_index,
first_solution, second_solution, false, 0u,
JonesParameters::MissingAntennaBehavior::kUnit);
const casacore::Cube<std::complex<float>>& parms =
jones_parameters.GetParms();
std::vector<std::complex<float>>& band_response =
parm_response.AlwaysEmplace(data_desc_id);
band_response.assign(&parms(0, 0, 0), &parms(0, 0, 0) + response_size);
setNonFiniteToZero(band_response);
}
}
}
}
size_t VisibilityModifier::GetCacheParmResponseSize() const {
size_t size = 0;
for (const auto& ms_info : _cachedParmResponse) {
for (const std::vector<std::complex<float>>& band_solutions :
ms_info.second) {
size += band_solutions.capacity();
}
}
return size * sizeof(std::complex<float>);
}
void VisibilityModifier::CacheParmResponse(double time,
const aocommon::MultiBandData& bands,
size_t ms_index,
size_t& time_offset) {
const auto it = std::find(_cachedMSTimes[ms_index]->begin() + time_offset,
_cachedMSTimes[ms_index]->end(), time);
if (it != _cachedMSTimes[ms_index]->end()) {
// Update time_offsets_ value with index
time_offset = std::distance(_cachedMSTimes[ms_index]->begin(), it);
} else {
throw std::runtime_error(
"Time not found in cached times. A potential reason could be that the "
"time values in the provided MS are not in ascending order. "
"Error occurred with ms index = " +
std::to_string(ms_index) +
", cache "
"contained " +
std::to_string(_cachedMSTimes[ms_index]->size()) + " elements.\n");
}
}
#ifdef HAVE_EVERYBEAM
void VisibilityModifier::GetBeamResponse(
const aocommon::BandData& band, size_t field_id,
std::vector<aocommon::MC2x2F>& result) const {
std::vector<double> frequencies(band.ChannelCount());
std::vector<aocommon::MC2x2F> response(n_stations_ * band.ChannelCount());
for (size_t ch = 0; ch < band.ChannelCount(); ++ch) {
frequencies[ch] = band.ChannelFrequency(ch);
}
_pointResponse->ResponseAllStations(_beamMode, response.data(),
_facetDirectionRA, _facetDirectionDec,
frequencies, field_id);
// Transpose the structure
for (size_t station = 0; station != n_stations_; ++station) {
for (size_t ch = 0; ch < band.ChannelCount(); ++ch) {
result[ch * n_stations_ + station] =
response[station * band.ChannelCount() + ch];
}
}
}
bool VisibilityModifier::UpdateCachedBeamResponseForRow(
double time, size_t field_id, const aocommon::MultiBandData& bands,
BeamResponseMap& cached_beam_response) {
_pointResponse->UpdateTime(time);
if (_pointResponse->HasTimeUpdate()) {
if (uses_bda_) {
// In BDA mode, interpolate the channels from the data_desc_id with the
// highest nr of channels.
const size_t max_channels_id = bands.DataDescIdWithMaxChannels();
const aocommon::BandData& band = bands[max_channels_id];
std::vector<aocommon::MC2x2F>& full_cached_response =
cached_beam_response[max_channels_id];
GetBeamResponse(band, field_id, full_cached_response);
for (size_t data_desc_id : bands.DataDescIds()) {
std::vector<aocommon::MC2x2F>& destination =
cached_beam_response[data_desc_id];
const aocommon::BandData& destination_band = bands[data_desc_id];
InterpolateChannels(full_cached_response, band, destination,
destination_band, 1, n_stations_);
}
} else {
for (size_t data_desc_id : bands.DataDescIds()) {
const aocommon::BandData& band = bands[data_desc_id];
std::vector<aocommon::MC2x2F>& response =
cached_beam_response[data_desc_id];
GetBeamResponse(band, field_id, response);
}
}
return true;
}
return false;
}
template <GainMode Mode>
void VisibilityModifier::ApplyBeamResponse(std::complex<float>* data,
size_t n_channels,
size_t data_desc_id, size_t antenna1,
size_t antenna2) {
for (size_t ch = 0; ch < n_channels; ++ch) {
const size_t offset = ch * n_stations_;
const size_t offset1 = offset + antenna1;
const size_t offset2 = offset + antenna2;
const MC2x2F& gain1(_cachedBeamResponse[data_desc_id][offset1]);
const MC2x2F& gain2(_cachedBeamResponse[data_desc_id][offset2]);
internal::ApplyGain<Mode>(data, gain1, gain2);
data += GetNVisibilities(Mode);
}
}
template void VisibilityModifier::ApplyBeamResponse<GainMode::kXX>(
std::complex<float>* data, size_t n_channels, size_t data_desc_id,
size_t antenna1, size_t antenna2);
template void VisibilityModifier::ApplyBeamResponse<GainMode::kYY>(
std::complex<float>* data, size_t n_channels, size_t data_desc_id,
size_t antenna1, size_t antenna2);
template void VisibilityModifier::ApplyBeamResponse<GainMode::kTrace>(
std::complex<float>* data, size_t n_channels, size_t data_desc_id,
size_t antenna1, size_t antenna2);
template void VisibilityModifier::ApplyBeamResponse<GainMode::k2VisDiagonal>(
std::complex<float>* data, size_t n_channels, size_t data_desc_id,
size_t antenna1, size_t antenna2);
template void VisibilityModifier::ApplyBeamResponse<GainMode::kFull>(
std::complex<float>* data, size_t n_channels, size_t data_desc_id,
size_t antenna1, size_t antenna2);
#endif
template <GainMode Mode>
void VisibilityModifier::ApplyParmResponseWithTime(
std::complex<float>* data, size_t ms_index, size_t n_channels,
size_t data_desc_id, size_t n_antennas, size_t antenna1, size_t antenna2,
size_t time_offset) {
const size_t nparms = NValuesPerSolution(ms_index);
const std::vector<std::complex<float>>& parm_response =
_cachedParmResponse[ms_index][data_desc_id];
if (nparms == 2) {
for (size_t ch = 0; ch < n_channels; ++ch) {
// Column major indexing
const size_t offset =
(time_offset * n_channels + ch) * n_antennas * nparms;
const size_t offset1 = offset + antenna1 * nparms;
const size_t offset2 = offset + antenna2 * nparms;
const MC2x2F gain1(parm_response[offset1], 0, 0,
parm_response[offset1 + 1]);
const MC2x2F gain2(parm_response[offset2], 0, 0,
parm_response[offset2 + 1]);
internal::ApplyGain<Mode>(data, gain1, gain2);
data += GetNVisibilities(Mode);
}
} else {
for (size_t ch = 0; ch < n_channels; ++ch) {
// Column major indexing
const size_t offset =
(time_offset * n_channels + ch) * n_antennas * nparms;
const size_t offset1 = offset + antenna1 * nparms;
const size_t offset2 = offset + antenna2 * nparms;
const MC2x2F gain1(&parm_response[offset1]);
const MC2x2F gain2(&parm_response[offset2]);
internal::ApplyGain<Mode>(data, gain1, gain2);
data += GetNVisibilities(Mode);
}
}
}
template void VisibilityModifier::ApplyParmResponseWithTime<GainMode::kXX>(
std::complex<float>* data, size_t ms_index, size_t n_channels,
size_t data_desc_id, size_t n_antennas, size_t antenna1, size_t antenna2,
size_t time_offset);
template void VisibilityModifier::ApplyParmResponseWithTime<GainMode::kYY>(
std::complex<float>* data, size_t ms_index, size_t n_channels,
size_t data_desc_id, size_t n_antennas, size_t antenna1, size_t antenna2,
size_t time_offset);
template void VisibilityModifier::ApplyParmResponseWithTime<GainMode::kTrace>(
std::complex<float>* data, size_t ms_index, size_t n_channels,
size_t data_desc_id, size_t n_antennas, size_t antenna1, size_t antenna2,
size_t time_offset);
template void
VisibilityModifier::ApplyParmResponseWithTime<GainMode::k2VisDiagonal>(
std::complex<float>* data, size_t ms_index, size_t n_channels,
size_t data_desc_id, size_t n_antennas, size_t antenna1, size_t antenna2,
size_t time_offset);
template void VisibilityModifier::ApplyParmResponseWithTime<GainMode::kFull>(
std::complex<float>* data, size_t ms_index, size_t n_channels,
size_t data_desc_id, size_t n_antennas, size_t antenna1, size_t antenna2,
size_t time_offset);
} // namespace wsclean
|