diff --git a/CMakeLists.txt b/CMakeLists.txt index aefd9597eff049bef8f6e3793edbef91c2302403..adf9cbce91caa7c2dab9f8428338d4e9dfe0e682 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.7) #------------------------------------------------------------------------------ # Set version name and project number -set(EVERYBEAM_VERSION 0.2.3) +set(EVERYBEAM_VERSION 0.3.0) if(EVERYBEAM_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)") set(EVERYBEAM_VERSION_MAJOR "${CMAKE_MATCH_1}") set(EVERYBEAM_VERSION_MINOR "${CMAKE_MATCH_2}") diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index ae1bfe3f41f527c147aeeb5157ba0942d7612030..52b87e80e138f87aca7df9afdb3d724360825a77 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -46,6 +46,7 @@ add_library( coords/itrfdirection.cc msreadutils.cc station.cc + phasedarrayresponse.cc telescope/lofar.cc telescope/dish.cc telescope/mwa.cc @@ -102,6 +103,7 @@ install( station.h load.h options.h + phasedarrayresponse.h DESTINATION "include/${CMAKE_PROJECT_NAME}") # TODO: not sure whether this is needed at all diff --git a/cpp/aterms/atermconfig.cc b/cpp/aterms/atermconfig.cc index 0021456d1aa011d334293f20d0950d625cd2c86d..c2bd0642c5cfebb43b04911c6bf08841958256bd 100644 --- a/cpp/aterms/atermconfig.cc +++ b/cpp/aterms/atermconfig.cc @@ -289,19 +289,6 @@ std::unique_ptr<ATermBeam> ATermConfig::GetATermBeam( new EveryBeamATerm(ms, coordinate_system, options)); } -std::unique_ptr<ATermBeam> ATermConfig::GetATermBeam( - const casacore::MeasurementSet& ms, - const CoordinateSystem& coordinate_system, const ATermSettings& settings, - bool frequency_interpolation, bool use_differential_beam, - bool use_channel_frequency, const std::string& element_response_model, - const std::string& beam_mode) { - everybeam::Options options = ConvertToEBOptions( - ms, settings, frequency_interpolation, use_differential_beam, - use_channel_frequency, element_response_model, beam_mode); - return std::unique_ptr<ATermBeam>( - new EveryBeamATerm(ms, coordinate_system, options)); -} - everybeam::Options ATermConfig::ConvertToEBOptions( const casacore::MeasurementSet& ms, const ATermSettings& settings, bool frequency_interpolation, const std::string& beam_normalisation_mode, @@ -330,21 +317,5 @@ everybeam::Options ATermConfig::ConvertToEBOptions( options.beam_normalisation_mode = beam_normalisation_mode_enum; return options; } - -everybeam::Options ATermConfig::ConvertToEBOptions( - const casacore::MeasurementSet& ms, const ATermSettings& settings, - bool frequency_interpolation, bool use_differential_beam, - bool use_channel_frequency, const std::string& element_response_model, - const std::string& beam_mode) { - const std::string beam_normalisation_mode_none_str = "none"; - everybeam::Options options = ConvertToEBOptions( - ms, settings, frequency_interpolation, beam_normalisation_mode_none_str, - use_channel_frequency, element_response_model, beam_mode); - options.beam_normalisation_mode = use_differential_beam - ? BeamNormalisationMode::kFull - : BeamNormalisationMode::kPreApplied; - return options; -} - } // namespace aterms } // namespace everybeam diff --git a/cpp/aterms/atermconfig.h b/cpp/aterms/atermconfig.h index 21391e483bff29ffff61738bd87bfcad162d0764..7bd62737524383d41075eb87fcf42077b1515e2f 100644 --- a/cpp/aterms/atermconfig.h +++ b/cpp/aterms/atermconfig.h @@ -55,30 +55,6 @@ class ATermConfig final : public ATermBase { return avgTime; } - /** - * @brief Static method for constructing an (EveryBeam)ATerm - * - * @param ms Measurement set - * @param coordinate_system struct with image settings - * @param settings aterm specific settings - * @param frequency_interpolation Interpolate between frequencies? Relevant - * for MWA only. - * @param use_differential_beam Apply differential beam - * @param use_channel_frequency Use channel frequency - * @param element_response_model Element response model - * @return std::unique_ptr<ATermBeam> - */ - [[deprecated( - "Use other overload of GetATermBeam() instead. Function will be removed " - "in version " - "0.3.0.")]] static std::unique_ptr<ATermBeam> - GetATermBeam(const casacore::MeasurementSet& ms, - const coords::CoordinateSystem& coordinate_system, - const ATermSettings& settings, bool frequency_interpolation, - bool use_differential_beam, bool use_channel_frequency, - const std::string& element_response_model, - const std::string& beam_mode = "full"); - /** * @brief Static method for constructing an (EveryBeam)ATerm * @@ -119,17 +95,6 @@ class ATermConfig final : public ATermBase { bool use_channel_frequency, const std::string& element_response_model, const std::string& beam_mode = "full"); - [[deprecated( - "Use other overload of GetATermBeam() instead. Function will be removed " - "in version " - "0.3.0.")]] static everybeam::Options - ConvertToEBOptions(const casacore::MeasurementSet& ms, - const ATermSettings& settings, - bool frequency_interpolation, bool use_differential_beam, - bool use_channel_frequency, - const std::string& element_response_model, - const std::string& beam_mode = "full"); - private: const size_t n_antennas_; const coords::CoordinateSystem coordinate_system_; diff --git a/cpp/griddedresponse/aartfaacgrid.cc b/cpp/griddedresponse/aartfaacgrid.cc index b16989582a4a9a18c5709ec1943fa27e54b7e18a..82f2985a367ef49b2cd3cddc513363320a9aa05b 100644 --- a/cpp/griddedresponse/aartfaacgrid.cc +++ b/cpp/griddedresponse/aartfaacgrid.cc @@ -3,6 +3,8 @@ #include "aartfaacgrid.h" +#include <aocommon/uvector.h> + namespace everybeam { namespace griddedresponse { @@ -27,7 +29,7 @@ void AartfaacGrid::MakeIntegratedSnapshot( ResponseAllStations(beam_mode, buffer_undersampled.data(), time, frequency, field_id); - // For Aartfaac, we can simply weight a (time) snapshot with the accumulated + // For Aartfaac, simply weight a (time) snapshot with the accumulated // baseline weights const size_t n_baselines = n_stations * (n_stations + 1) / 2; double snapshot_weight = 0.; diff --git a/cpp/griddedresponse/dishgrid.cc b/cpp/griddedresponse/dishgrid.cc index af502e513780ac863450874897e74929a19db244..c78e5dbcae8295b67a3632ac9da2104febf379c9 100644 --- a/cpp/griddedresponse/dishgrid.cc +++ b/cpp/griddedresponse/dishgrid.cc @@ -24,19 +24,18 @@ void DishGrid::Response(BeamMode /* beam_mode */, std::complex<float>* buffer, const telescope::Dish& dish_telescope = static_cast<const telescope::Dish&>(*telescope_); - const double pdir_ra = - dish_telescope.ms_properties_.field_pointing[field_id].first; - const double pdir_dec = - dish_telescope.ms_properties_.field_pointing[field_id].second; + double pdir_ra; + double pdir_dec; + std::tie(pdir_ra, pdir_dec) = dish_telescope.GetFieldPointing()[field_id]; const double max_radius_arc_min = - dish_telescope.coefficients_->MaxRadiusInArcMin(); + dish_telescope.GetDishCoefficients()->MaxRadiusInArcMin(); const double reference_frequency = - dish_telescope.coefficients_->ReferenceFrequency(); + dish_telescope.GetDishCoefficients()->ReferenceFrequency(); circularsymmetric::VoltagePattern vp( - dish_telescope.coefficients_->GetFrequencies(frequency), + dish_telescope.GetDishCoefficients()->GetFrequencies(frequency), max_radius_arc_min, reference_frequency); const aocommon::UVector<double> coefs_vec = - dish_telescope.coefficients_->GetCoefficients(frequency); + dish_telescope.GetDishCoefficients()->GetCoefficients(frequency); vp.EvaluatePolynomial(coefs_vec, false); vp.Render(buffer, width_, height_, dl_, dm_, ra_, dec_, pdir_ra, pdir_dec, phase_centre_dl_, phase_centre_dm_, frequency); diff --git a/cpp/griddedresponse/griddedresponse.cc b/cpp/griddedresponse/griddedresponse.cc index e564a12e45ab236002cc6e33d3046e012a606c47..1b0d3b81b9f5135dc00660573e1daa228867b10f 100644 --- a/cpp/griddedresponse/griddedresponse.cc +++ b/cpp/griddedresponse/griddedresponse.cc @@ -6,8 +6,10 @@ #include "../telescope/telescope.h" +#include <aocommon/uvector.h> #include <aocommon/matrix2x2.h> #include <aocommon/matrix4x4.h> +#include <aocommon/hmatrix4x4.h> #include <vector> #include <complex> #include <stdexcept> @@ -16,9 +18,9 @@ using aocommon::HMC4x4; using aocommon::MC2x2; using aocommon::MC4x4; using aocommon::UVector; -using everybeam::common::FFTResampler; -using everybeam::griddedresponse::GriddedResponse; +namespace everybeam { +namespace griddedresponse { void GriddedResponse::IntegratedResponse( BeamMode beam_mode, float* buffer, double time, double frequency, size_t field_id, size_t undersampling_factor, @@ -163,7 +165,7 @@ void GriddedResponse::DoFFTResampling( float* buffer, int width_in, int height_in, int width_out, int height_out, const std::vector<aocommon::HMC4x4>& matrices) { // (FFT) resampling, run multi-threaded? - FFTResampler resampler(width_in, height_in, width_out, height_out); + common::FFTResampler resampler(width_in, height_in, width_out, height_out); resampler.SetWindowFunction(aocommon::WindowFunction::RaisedHann, true); UVector<float> lowres_input(width_in * height_in); // Loop over the "double" representation of the HMC4x4 Hermitian matrix @@ -176,3 +178,5 @@ void GriddedResponse::DoFFTResampling( buffer + p * width_out * height_out); } } +} // namespace griddedresponse +} // namespace everybeam \ No newline at end of file diff --git a/cpp/griddedresponse/griddedresponse.h b/cpp/griddedresponse/griddedresponse.h index 7f99c1cc6cc584433d6af1720c8f98b07951c737..9a422a28ac17e4413777c85987ffc036c70b5876 100644 --- a/cpp/griddedresponse/griddedresponse.h +++ b/cpp/griddedresponse/griddedresponse.h @@ -11,14 +11,12 @@ #include "./../coords/itrfconverter.h" #include "../beammode.h" +#include <aocommon/hmatrix4x4.h> + #include <memory> #include <vector> #include <thread> -#include <aocommon/lane.h> -#include <aocommon/uvector.h> -#include <aocommon/hmatrix4x4.h> - #include <casacore/measures/Measures/MDirection.h> namespace everybeam { @@ -37,37 +35,6 @@ class GriddedResponse { public: virtual ~GriddedResponse() {} - /** - * @brief See Response() - */ - [[deprecated( - "Use Response() instead. Function will be removed in version " - "0.3.0.")]] void - CalculateStation(std::complex<float>* buffer, double time, double freq, - size_t station_idx, size_t field_id) { - Response(BeamMode::kFull, buffer, time, freq, station_idx, field_id); - }; - - /** - * @brief Compute the full beam response for a single station. Result is - * stored in the output buffer, which should accommodate a Jones matrix (4 - * complex valued floats) per pixel. - * - * @param buffer Output buffer, compute and set size with - * GriddedResponse::GetStationBufferSize(1) - * @param station_idx Station index, must be smaller than number of stations - * in the Telescope - * @param time Time, modified Julian date, UTC, in seconds (MJD(UTC), s). - * @param frequency Frequency (Hz) - */ - [[deprecated( - "Use Response() instead. Function will be removed in version " - "0.3.0.")]] void - FullResponse(std::complex<float>* buffer, double time, double freq, - size_t station_idx, size_t field_id) { - Response(BeamMode::kFull, buffer, time, freq, station_idx, field_id); - } - /** * @brief Compute the beam for a single station, given a prescribed beam mode. * Result is stored in the output buffer, which should accommodate a Jones @@ -86,37 +53,6 @@ class GriddedResponse { double time, double freq, size_t station_idx, size_t field_id) = 0; - /** - * @brief See ResponseAllStations() - */ - [[deprecated( - "Use ResponseAllStations() instead. Function will be removed in " - "version " - "0.3.0.")]] void - CalculateAllStations(std::complex<float>* buffer, double time, - double frequency, size_t field_id) { - ResponseAllStations(BeamMode::kFull, buffer, time, frequency, field_id); - }; - - /** - * @brief Compute the full beam response for all stations in a Telescope. - * Result is stored in the output buffer, which should accommodate a Jones - * matrix (4 complex valued floats) per pixel for each station. - * - * @param buffer Output buffer, compute and set size with - * GriddedResponse::GetStationBufferSize() - * @param time Time, modified Julian date, UTC, in seconds (MJD(UTC), s). - * @param frequency Frequency (Hz) - */ - [[deprecated( - "Use ResponseAllStations() instead. Function will be removed in " - "version " - "0.3.0.")]] void - FullResponseAllStations(std::complex<float>* buffer, double time, - double frequency, size_t field_id) { - ResponseAllStations(BeamMode::kFull, buffer, time, frequency, field_id); - } - /** * @brief Compute the array factor for all stations in a Telescope. * Result is stored in the output buffer, which should accommodate a Jones @@ -169,19 +105,6 @@ class GriddedResponse { size_t field_id, size_t undersampling_factor, const std::vector<double>& baseline_weights); - [[deprecated( - "Overload will be kept alive to allow WSClean migrating to float " - "implementation")]] void - IntegratedResponse(BeamMode beam_mode, double* buffer, double time, - double frequency, size_t field_id, - size_t undersampling_factor, - const std::vector<double>& baseline_weights) { - std::vector<float> buffer_float(GetIntegratedBufferSize()); - IntegratedResponse(beam_mode, buffer_float.data(), time, frequency, - field_id, undersampling_factor, baseline_weights); - std::copy_n(buffer_float.begin(), GetIntegratedBufferSize(), buffer); - } - /** * @brief Calculate integrated beam over multiple time steps. * This function makes use of @ref MakeIntegratedSnapshot(). Subclasses @@ -206,19 +129,6 @@ class GriddedResponse { size_t undersampling_factor, const std::vector<double>& baseline_weights); - [[deprecated( - "Overload will be kept alive to allow WSClean migrating to float " - "implementation")]] void - IntegratedResponse(BeamMode beam_mode, double* buffer, - const std::vector<double>& time_array, double frequency, - size_t field_id, size_t undersampling_factor, - const std::vector<double>& baseline_weights) { - std::vector<float> buffer_float(GetIntegratedBufferSize()); - IntegratedResponse(beam_mode, buffer_float.data(), time_array, frequency, - field_id, undersampling_factor, baseline_weights); - std::copy_n(buffer_float.begin(), GetIntegratedBufferSize(), buffer); - } - std::size_t GetStationBufferSize(std::size_t nstations) const { return nstations * width_ * height_ * 4u; } diff --git a/cpp/griddedresponse/mwagrid.cc b/cpp/griddedresponse/mwagrid.cc index 08ef6852d3a591b5fd2e439b4ca187a9c460893c..a9c3bc6e7d446c8f642af70bbb978532fa352a5b 100644 --- a/cpp/griddedresponse/mwagrid.cc +++ b/cpp/griddedresponse/mwagrid.cc @@ -23,8 +23,7 @@ void MWAGrid::Response(BeamMode /* beam_mode */, std::complex<float>* buffer, static_cast<const telescope::MWA&>(*telescope_); casacore::MEpoch time_epoch(casacore::Quantity(time, "s")); - casacore::MeasFrame frame(mwatelescope.ms_properties_.array_position, - time_epoch); + casacore::MeasFrame frame(mwatelescope.GetArrayPosition(), time_epoch); const casacore::MDirection::Ref hadec_ref(casacore::MDirection::HADEC, frame); const casacore::MDirection::Ref azelgeo_ref(casacore::MDirection::AZELGEO, @@ -33,12 +32,12 @@ void MWAGrid::Response(BeamMode /* beam_mode */, std::complex<float>* buffer, casacore::MDirection::Convert j2000_to_hadecref(j2000_ref, hadec_ref), j2000_to_azelgeoref(j2000_ref, azelgeo_ref); casacore::MPosition wgs = casacore::MPosition::Convert( - mwatelescope.ms_properties_.array_position, casacore::MPosition::WGS84)(); - double arr_latitude = wgs.getValue().getLat(); + mwatelescope.GetArrayPosition(), casacore::MPosition::WGS84)(); + const double arr_latitude = wgs.getValue().getLat(); if (!tile_beam_) { tile_beam_.reset( - new TileBeam2016(mwatelescope.ms_properties_.delays, + new TileBeam2016(mwatelescope.GetDelays().data(), mwatelescope.GetOptions().frequency_interpolation, mwatelescope.GetOptions().coeff_path)); } diff --git a/cpp/griddedresponse/phasedarraygrid.cc b/cpp/griddedresponse/phasedarraygrid.cc index 9044b732e48b5862fbbdac4ea071053c60c915dc..8fd0a1505fc89a6c0a24ccba6ed1f6416e110fa2 100644 --- a/cpp/griddedresponse/phasedarraygrid.cc +++ b/cpp/griddedresponse/phasedarraygrid.cc @@ -4,31 +4,22 @@ #include "phasedarraygrid.h" #include "../telescope/phasedarray.h" +#include <aocommon/lane.h> #include <aocommon/imagecoordinates.h> #include <aocommon/threadpool.h> #include <cmath> #include <iostream> +namespace everybeam { -using everybeam::griddedresponse::PhasedArrayGrid; +using telescope::PhasedArray; + +namespace griddedresponse { PhasedArrayGrid::PhasedArrayGrid( const telescope::Telescope* telescope_ptr, const coords::CoordinateSystem& coordinate_system) : GriddedResponse(telescope_ptr, coordinate_system), - beam_normalisation_mode_( - telescope_->GetOptions().beam_normalisation_mode) { - // Extract PhasedArrayPoint specific options from ms_properties_ and - // telescope::Options - const telescope::PhasedArray& phasedarray = - dynamic_cast<const telescope::PhasedArray&>(*telescope_ptr); - delay_dir_ = phasedarray.GetMSProperties().delay_dir; - tile_beam_dir_ = phasedarray.GetMSProperties().tile_beam_dir; - preapplied_beam_dir_ = phasedarray.GetMSProperties().preapplied_beam_dir; - preapplied_correction_mode_ = - phasedarray.GetMSProperties().preapplied_correction_mode; - subband_frequency_ = phasedarray.GetMSProperties().subband_freq; - use_channel_frequency_ = phasedarray.GetOptions().use_channel_frequency; - + PhasedArrayResponse(static_cast<const PhasedArray*>(telescope_ptr)) { // Compute and set number of threads const size_t ncpus = aocommon::ThreadPool::NCPUs(); const size_t nthreads = std::min(ncpus, telescope_->GetNrStations()); @@ -66,7 +57,7 @@ void PhasedArrayGrid::ResponseAllStations(BeamMode beam_mode, std::complex<float>* buffer, double time, double frequency, size_t) { - const telescope::PhasedArray& phasedarraytelescope = + const telescope::PhasedArray& phased_array = static_cast<const telescope::PhasedArray&>(*telescope_); aocommon::Lane<Job> lane(threads_.size()); lane_ = &lane; @@ -74,8 +65,8 @@ void PhasedArrayGrid::ResponseAllStations(BeamMode beam_mode, SetITRFVectors(time); bool apply_normalisation; - inverse_central_gain_.resize(phasedarraytelescope.GetNrStations()); - for (size_t i = 0; i != phasedarraytelescope.GetNrStations(); ++i) { + inverse_central_gain_.resize(phased_array.GetNrStations()); + for (size_t i = 0; i != phased_array.GetNrStations(); ++i) { apply_normalisation = CalculateBeamNormalisation( beam_mode, time, frequency, i, inverse_central_gain_[i]); } @@ -87,8 +78,8 @@ void PhasedArrayGrid::ResponseAllStations(BeamMode beam_mode, } for (size_t y = 0; y != height_; ++y) { - for (size_t antenna_idx = 0; - antenna_idx != phasedarraytelescope.GetNrStations(); ++antenna_idx) { + for (size_t antenna_idx = 0; antenna_idx != phased_array.GetNrStations(); + ++antenna_idx) { lane.write(Job(y, antenna_idx, antenna_idx)); } } @@ -126,72 +117,10 @@ void PhasedArrayGrid::SetITRFVectors(double time) { diff_beam_centre_); } -bool PhasedArrayGrid::CalculateBeamNormalisation( - BeamMode beam_mode, double time, double frequency, size_t station_idx, - aocommon::MC2x2F& inverse_gain) const { - const telescope::PhasedArray& phasedarraytelescope = - static_cast<const telescope::PhasedArray&>(*telescope_); - if (beam_normalisation_mode_ == BeamNormalisationMode::kNone) { - return false; - } - - const double sb_freq = - use_channel_frequency_ ? frequency : subband_frequency_; - - // if the normalisation mode is kPreApplied, but no beam correction was pre - // applied then there is nothing to do - if (beam_normalisation_mode_ == BeamNormalisationMode::kPreApplied && - preapplied_correction_mode_ == BeamMode::kNone) { - return false; - } - - // If the normalisation mode is kPreApplied, or kPreAppliedOrFull and the - // fallback to Full is not needed then the response for the diff_beam_centre_ - // with preapplied_correction_mode_ needs to be computed - if (beam_normalisation_mode_ == BeamNormalisationMode::kPreApplied || - (beam_normalisation_mode_ == BeamNormalisationMode::kPreAppliedOrFull && - preapplied_correction_mode_ != BeamMode::kNone)) { - inverse_gain = aocommon::MC2x2F( - phasedarraytelescope.GetStation(station_idx) - ->Response(preapplied_correction_mode_, time, frequency, - diff_beam_centre_, sb_freq, station0_, tile0_) - .Data()); - } else { - // in all other cases the response for the reference direction with - // beam_mode is needed - inverse_gain = aocommon::MC2x2F( - phasedarraytelescope.GetStation(station_idx) - ->Response(beam_mode, time, frequency, diff_beam_centre_, sb_freq, - station0_, tile0_) - .Data()); - } - - switch (beam_normalisation_mode_) { - case BeamNormalisationMode::kFull: - case BeamNormalisationMode::kPreApplied: - case BeamNormalisationMode::kPreAppliedOrFull: - if (!inverse_gain.Invert()) { - inverse_gain = aocommon::MC2x2F::Zero(); - } - break; - case BeamNormalisationMode::kAmplitude: { - const float amplitude_inv = 1.0 / std::sqrt(0.5 * Norm(inverse_gain)); - inverse_gain[0] = std::isfinite(amplitude_inv) ? amplitude_inv : 0.0; - inverse_gain[1] = 0.0; - inverse_gain[2] = 0.0; - inverse_gain[3] = std::isfinite(amplitude_inv) ? amplitude_inv : 0.0; - break; - } - default: - throw std::runtime_error("Invalid beam normalisation mode here"); - } - return true; -} - void PhasedArrayGrid::CalcThread(BeamMode beam_mode, bool apply_normalisation, std::complex<float>* buffer, double time, double frequency) { - const telescope::PhasedArray& phasedarraytelescope = + const telescope::PhasedArray& phased_array = static_cast<const telescope::PhasedArray&>(*telescope_); const size_t values_per_ant = width_ * height_ * 4; const double sb_freq = @@ -216,7 +145,7 @@ void PhasedArrayGrid::CalcThread(BeamMode beam_mode, bool apply_normalisation, base_buffer + job.buffer_offset * values_per_ant; const aocommon::MC2x2F gain_matrix = aocommon::MC2x2F( - phasedarraytelescope.GetStation(job.antenna_idx) + phased_array.GetStation(job.antenna_idx) ->Response(beam_mode, time, frequency, itrf_direction, sb_freq, station0_, tile0_) .Data()); @@ -231,3 +160,5 @@ void PhasedArrayGrid::CalcThread(BeamMode beam_mode, bool apply_normalisation, } } } +} // namespace griddedresponse +} // namespace everybeam \ No newline at end of file diff --git a/cpp/griddedresponse/phasedarraygrid.h b/cpp/griddedresponse/phasedarraygrid.h index 5ceea6fb1e1f77b355661f662191a06e9debe319..bff2507fed07406645d89be04b4a2806b9e034df 100644 --- a/cpp/griddedresponse/phasedarraygrid.h +++ b/cpp/griddedresponse/phasedarraygrid.h @@ -9,10 +9,16 @@ #include "griddedresponse.h" #include "../beamnormalisationmode.h" +#include "../phasedarrayresponse.h" + +namespace aocommon { +template <typename Tp> +class Lane; +} namespace everybeam { namespace griddedresponse { -class PhasedArrayGrid : public GriddedResponse { +class PhasedArrayGrid : public GriddedResponse, protected PhasedArrayResponse { public: PhasedArrayGrid(const telescope::Telescope* telescope_ptr, const coords::CoordinateSystem& coordinate_system); @@ -25,17 +31,10 @@ class PhasedArrayGrid : public GriddedResponse { double time, double frequency, size_t field_id) override; - protected: - casacore::MDirection delay_dir_, tile_beam_dir_, preapplied_beam_dir_; - vector3r_t station0_, tile0_, l_vector_itrf_, m_vector_itrf_, n_vector_itrf_, - diff_beam_centre_; - - CorrectionMode preapplied_correction_mode_; - BeamNormalisationMode beam_normalisation_mode_; - bool use_channel_frequency_; - double subband_frequency_; - private: + vector3r_t l_vector_itrf_; + vector3r_t m_vector_itrf_; + vector3r_t n_vector_itrf_; std::vector<aocommon::MC2x2F> inverse_central_gain_; std::vector<std::thread> threads_; @@ -48,10 +47,6 @@ class PhasedArrayGrid : public GriddedResponse { }; aocommon::Lane<Job>* lane_; - bool CalculateBeamNormalisation(BeamMode beam_mode, double time, - double frequency, size_t station_idx, - aocommon::MC2x2F& inverse_gain) const; - /** * @brief Method for computing the ITRF-vectors. * NOTE: method not thread-safe due to casacore dependencies. diff --git a/cpp/phasedarrayresponse.cc b/cpp/phasedarrayresponse.cc new file mode 100644 index 0000000000000000000000000000000000000000..dc67cad88ce7fe65c38bcb523ed4cd3fae171aec --- /dev/null +++ b/cpp/phasedarrayresponse.cc @@ -0,0 +1,91 @@ +// Copyright (C) 2020 ASTRON (Netherlands Institute for Radio Astronomy) +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "telescope/phasedarray.h" +#include "phasedarrayresponse.h" + +#include <cassert> + +namespace everybeam { + +PhasedArrayResponse::PhasedArrayResponse( + const telescope::PhasedArray* phased_array) + : delay_dir_(phased_array->GetMSProperties().delay_dir), + tile_beam_dir_(phased_array->GetMSProperties().tile_beam_dir), + preapplied_beam_dir_(phased_array->GetMSProperties().preapplied_beam_dir), + preapplied_correction_mode_( + phased_array->GetMSProperties().preapplied_correction_mode), + beam_normalisation_mode_( + phased_array->GetOptions().beam_normalisation_mode), + use_channel_frequency_(phased_array->GetOptions().use_channel_frequency), + subband_frequency_(phased_array->GetMSProperties().subband_freq), + phased_array_(phased_array) { + assert(phased_array_); +} + +bool PhasedArrayResponse::CalculateBeamNormalisation( + BeamMode beam_mode, double time, double frequency, size_t station_index, + aocommon::MC2x2F& inverse_gain) const { + const telescope::PhasedArray& phased_array = + static_cast<const telescope::PhasedArray&>(*phased_array_); + if (beam_normalisation_mode_ == BeamNormalisationMode::kNone) { + return false; + } + + const double subband_frequency = + use_channel_frequency_ ? frequency : subband_frequency_; + + // if the normalisation mode is kPreApplied, but no beam correction was pre + // applied then there is nothing to do + if (beam_normalisation_mode_ == BeamNormalisationMode::kPreApplied && + preapplied_correction_mode_ == BeamMode::kNone) { + return false; + } + + // If the normalisation mode is kPreApplied, or kPreAppliedOrFull and the + // fallback to Full is not needed then the response for the diff_beam_centre_ + // with preapplied_correction_mode_ needs to be computed + if (beam_normalisation_mode_ == BeamNormalisationMode::kPreApplied || + (beam_normalisation_mode_ == BeamNormalisationMode::kPreAppliedOrFull && + preapplied_correction_mode_ != BeamMode::kNone)) { + inverse_gain = aocommon::MC2x2F( + phased_array.GetStation(station_index) + ->Response(preapplied_correction_mode_, time, frequency, + diff_beam_centre_, subband_frequency, station0_, tile0_) + .Data()); + } else { + // in all other cases the response for the reference direction with + // beam_mode is needed + inverse_gain = aocommon::MC2x2F( + phased_array.GetStation(station_index) + ->Response(beam_mode, time, frequency, diff_beam_centre_, + subband_frequency, station0_, tile0_) + .Data()); + } + + switch (beam_normalisation_mode_) { + case BeamNormalisationMode::kFull: + case BeamNormalisationMode::kPreApplied: + case BeamNormalisationMode::kPreAppliedOrFull: + if (!inverse_gain.Invert()) { + inverse_gain = aocommon::MC2x2F::Zero(); + } + break; + case BeamNormalisationMode::kAmplitude: { + const float norm_inverse_gain = Norm(inverse_gain); + const float amplitude_inv = + (norm_inverse_gain == 0.0) ? 0.0 + : 1.0 / std::sqrt(0.5 * norm_inverse_gain); + inverse_gain[0] = amplitude_inv; + inverse_gain[1] = 0.0; + inverse_gain[2] = 0.0; + inverse_gain[3] = amplitude_inv; + break; + } + case BeamNormalisationMode::kNone: + throw std::runtime_error("Invalid beam normalisation mode here"); + } + return true; +} + +} // namespace everybeam \ No newline at end of file diff --git a/cpp/phasedarrayresponse.h b/cpp/phasedarrayresponse.h new file mode 100644 index 0000000000000000000000000000000000000000..34899c73b08c6038d7fd3c3808cfc6f1a0cfa11f --- /dev/null +++ b/cpp/phasedarrayresponse.h @@ -0,0 +1,72 @@ +// phasedarrayresponse.h: Common functionality for PhasedArrayPoint and +// PhasedArrayGrid. +// +// Copyright (C) 2021 ASTRON (Netherlands Institute for Radio Astronomy) +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef EVERYBEAM_PHASEDARRAYRESPONSE_PHASEDARRAYRESPONSE_H_ +#define EVERYBEAM_PHASEDARRAYRESPONSE_PHASEDARRAYRESPONSE_H_ + +#include "common/types.h" +#include "correctionmode.h" +#include "beammode.h" +#include "beamnormalisationmode.h" + +#include <aocommon/matrix2x2.h> +#include <casacore/measures/Measures/MDirection.h> + +namespace everybeam { +namespace telescope { + +/** + * @brief Class containing shared functionality and member variables + * for phased array beamformer responses. + * + * TODO: this class might migrate to a better suited namespace in the future. + */ +class PhasedArray; +} // namespace telescope + +class PhasedArrayResponse { + public: + ~PhasedArrayResponse() = default; + + /** + * @brief Determine whether beam normalisation should be applied, + * and calculate inverse central gain if + * + * @param beam_mode Requested beam mode (kNone, kFull, kArrayFactor, kElement) + * @param time Time (J2000,s) + * @param frequency Frequency (Hz) + * @param station_index Station index + * @param inverse_gain Inverse central gain with which to normalize beam. + * @return Is beam normalisation required? + */ + bool CalculateBeamNormalisation(BeamMode beam_mode, double time, + double frequency, size_t station_index, + aocommon::MC2x2F& inverse_gain) const; + + protected: + PhasedArrayResponse(const telescope::PhasedArray* phasedarray); + + vector3r_t station0_; + vector3r_t tile0_; + vector3r_t diff_beam_centre_; + + const casacore::MDirection delay_dir_; + const casacore::MDirection tile_beam_dir_; + const casacore::MDirection preapplied_beam_dir_; + const CorrectionMode preapplied_correction_mode_; + + const BeamNormalisationMode beam_normalisation_mode_; + // non-const, since OSKAR overwrites these member variables + // to correct default + bool use_channel_frequency_; + double subband_frequency_; + + private: + const telescope::PhasedArray* phased_array_; +}; +} // namespace everybeam + +#endif // EVERYBEAM_PHASEDARRAYRESPONSE_PHASEDARRAYRESPONSE_H_ \ No newline at end of file diff --git a/cpp/pointresponse/dishpoint.cc b/cpp/pointresponse/dishpoint.cc index 5b077806560f4e63d0967a6e2139e104bc4ca88b..29f7cad24849e06bbe9078d90f25b09245594890 100644 --- a/cpp/pointresponse/dishpoint.cc +++ b/cpp/pointresponse/dishpoint.cc @@ -16,20 +16,20 @@ void DishPoint::Response(BeamMode /* beam_mode */, std::complex<float>* buffer, const telescope::Dish& dish_telescope = static_cast<const telescope::Dish&>(*telescope_); - const double pdir_ra = - dish_telescope.ms_properties_.field_pointing[field_id].first; - const double pdir_dec = - dish_telescope.ms_properties_.field_pointing[field_id].second; + double pdir_ra; + double pdir_dec; + std::tie(pdir_ra, pdir_dec) = dish_telescope.GetFieldPointing()[field_id]; const double max_radius_arc_min = - dish_telescope.coefficients_->MaxRadiusInArcMin(); + dish_telescope.GetDishCoefficients()->MaxRadiusInArcMin(); const double reference_frequency = - dish_telescope.coefficients_->ReferenceFrequency(); + dish_telescope.GetDishCoefficients()->ReferenceFrequency(); circularsymmetric::VoltagePattern vp( - dish_telescope.coefficients_->GetFrequencies(freq), max_radius_arc_min, - reference_frequency); + dish_telescope.GetDishCoefficients()->GetFrequencies(freq), + max_radius_arc_min, reference_frequency); const aocommon::UVector<double> coefs_vec = - dish_telescope.coefficients_->GetCoefficients(freq); - vp.EvaluatePolynomial(coefs_vec, dish_telescope.coefficients_->AreInverted()); + dish_telescope.GetDishCoefficients()->GetCoefficients(freq); + vp.EvaluatePolynomial(coefs_vec, + dish_telescope.GetDishCoefficients()->AreInverted()); vp.Render(buffer, ra, dec, pdir_ra, pdir_dec, freq); } diff --git a/cpp/pointresponse/mwapoint.cc b/cpp/pointresponse/mwapoint.cc index 364751621c7dd9113314e0f9d88b996ac2b9f05a..e1d515099061b5fb8c7b7e03dca0f8f00fa559fa 100644 --- a/cpp/pointresponse/mwapoint.cc +++ b/cpp/pointresponse/mwapoint.cc @@ -23,17 +23,19 @@ void MWAPoint::Response(BeamMode /* beam_mode */, std::complex<float>* buffer, if (!tile_beam_) { tile_beam_.reset( - new TileBeam2016(mwatelescope.ms_properties_.delays, + new TileBeam2016(mwatelescope.GetDelays().data(), mwatelescope.GetOptions().frequency_interpolation, mwatelescope.GetOptions().coeff_path)); } - std::complex<double> gain[4]; + std::array<std::complex<double>, 4> gains; + tile_beam_->ArrayResponse(ra, dec, j2000_ref_, j2000_to_hadecref_, - j2000_to_azelgeoref_, arr_latitude_, freq, gain); + j2000_to_azelgeoref_, arr_latitude_, freq, + gains.data()); - for (size_t i = 0; i != 4; ++i) { - *buffer = gain[i]; + for (const auto& gain : gains) { + *buffer = gain; ++buffer; } } @@ -57,8 +59,7 @@ void MWAPoint::SetJ200Vectors() { std::unique_lock<std::mutex> lock(mutex_); casacore::MEpoch time_epoch( casacore::Quantity(time_ + 0.5 * update_interval_, "s")); - casacore::MeasFrame frame(mwatelescope.ms_properties_.array_position, - time_epoch); + casacore::MeasFrame frame(mwatelescope.GetArrayPosition(), time_epoch); const casacore::MDirection::Ref hadec_ref(casacore::MDirection::HADEC, frame); const casacore::MDirection::Ref azelgeo_ref(casacore::MDirection::AZELGEO, @@ -67,7 +68,7 @@ void MWAPoint::SetJ200Vectors() { j2000_to_hadecref_(j2000_ref_, hadec_ref); j2000_to_azelgeoref_(j2000_ref_, azelgeo_ref); casacore::MPosition wgs = casacore::MPosition::Convert( - mwatelescope.ms_properties_.array_position, casacore::MPosition::WGS84)(); + mwatelescope.GetArrayPosition(), casacore::MPosition::WGS84)(); arr_latitude_ = wgs.getValue().getLat(); } } // namespace pointresponse diff --git a/cpp/pointresponse/phasedarraypoint.cc b/cpp/pointresponse/phasedarraypoint.cc index 1501d0ee7d557d70ee23dadbe23445624b290536..2fabb6dae115df397ed71afe01c476cad868daf4 100644 --- a/cpp/pointresponse/phasedarraypoint.cc +++ b/cpp/pointresponse/phasedarraypoint.cc @@ -11,32 +11,20 @@ #include <limits> namespace everybeam { + +using telescope::PhasedArray; + namespace pointresponse { PhasedArrayPoint::PhasedArrayPoint(const telescope::Telescope *telescope_ptr, double time) : PointResponse(telescope_ptr, time), - beam_normalisation_mode_( - telescope_->GetOptions().beam_normalisation_mode), + PhasedArrayResponse(static_cast<const PhasedArray *>(telescope_ptr)), ra_(std::numeric_limits<double>::min()), dec_(std::numeric_limits<double>::min()), has_partial_itrf_update_(false), is_local_(false), - rotate_(true) { - // Extract phased array specific options from ms_properties_ and - // telescope::Options - // TODO: code is largely a duplicate of PhasedArrayGrid - // constructor - const telescope::PhasedArray &phasedarray = - dynamic_cast<const telescope::PhasedArray &>(*telescope_ptr); - delay_dir_ = phasedarray.GetMSProperties().delay_dir; - tile_beam_dir_ = phasedarray.GetMSProperties().tile_beam_dir; - preapplied_beam_dir_ = phasedarray.GetMSProperties().preapplied_beam_dir; - preapplied_correction_mode_ = - phasedarray.GetMSProperties().preapplied_correction_mode; - subband_frequency_ = phasedarray.GetMSProperties().subband_freq; - use_channel_frequency_ = phasedarray.GetOptions().use_channel_frequency; -} + rotate_(true) {} void PhasedArrayPoint::Response(BeamMode beam_mode, std::complex<float> *buffer, double ra, double dec, double freq, @@ -50,17 +38,17 @@ void PhasedArrayPoint::Response(BeamMode beam_mode, std::complex<float> *buffer, has_partial_itrf_update_ = false; } - const telescope::PhasedArray &phasedarraytelescope = - static_cast<const telescope::PhasedArray &>(*telescope_); + const PhasedArray &phased_array = + static_cast<const PhasedArray &>(*telescope_); aocommon::MC2x2F inverse_central_gain; - bool apply_normalisation = CalculateBeamNormalisation( + const bool apply_normalisation = CalculateBeamNormalisation( beam_mode, time_, freq, station_idx, inverse_central_gain); const double sb_freq = use_channel_frequency_ ? freq : subband_frequency_; const aocommon::MC2x2F gain_matrix = - aocommon::MC2x2F(phasedarraytelescope.GetStation(station_idx) - ->Response(beam_mode, time_, freq, dir_itrf_, + aocommon::MC2x2F(phased_array.GetStation(station_idx) + ->Response(beam_mode, time_, freq, itrf_direction_, sb_freq, station0_, tile0_) .Data()); @@ -71,9 +59,10 @@ void PhasedArrayPoint::Response(BeamMode beam_mode, std::complex<float> *buffer, } } -aocommon::MC2x2 PhasedArrayPoint::FullResponse(size_t station_idx, double freq, - const vector3r_t &direction, - std::mutex *mutex) { +aocommon::MC2x2 PhasedArrayPoint::Response(BeamMode beam_mode, + size_t station_idx, double freq, + const vector3r_t &direction, + std::mutex *mutex) { if (has_time_update_) { if (mutex != nullptr) { // Caller takes over responsibility to be thread-safe @@ -85,67 +74,40 @@ aocommon::MC2x2 PhasedArrayPoint::FullResponse(size_t station_idx, double freq, has_time_update_ = false; has_partial_itrf_update_ = true; } - return FullResponse(station_idx, freq, direction, station0_, tile0_); -} -aocommon::MC2x2 PhasedArrayPoint::FullResponse(size_t station_idx, double freq, - const vector3r_t &direction, - const vector3r_t &station0, - const vector3r_t &tile0) { - const telescope::PhasedArray &phasedarraytelescope = - static_cast<const telescope::PhasedArray &>(*telescope_); - const double sb_freq = use_channel_frequency_ ? freq : subband_frequency_; - return phasedarraytelescope.GetStation(station_idx) - ->Response(time_, freq, direction, sb_freq, station0, tile0, rotate_); -} + aocommon::MC2x2F inverse_central_gain; + const bool apply_normalisation = CalculateBeamNormalisation( + beam_mode, time_, freq, station_idx, inverse_central_gain); -aocommon::MC2x2Diag PhasedArrayPoint::ArrayFactor(size_t station_idx, - double freq, - const vector3r_t &direction, - std::mutex *mutex) { - if (has_time_update_) { - if (mutex != nullptr) { - // Caller takes over responsibility to be thread-safe - UpdateITRFVectors(*mutex); - } else { - // Calllee assumes that caller is thread-safe - UpdateITRFVectors(mutex_); - } - has_time_update_ = false; - has_partial_itrf_update_ = true; - } - return ArrayFactor(station_idx, freq, direction, station0_, tile0_); -} + aocommon::MC2x2 gain_matrix = UnnormalisedResponse( + beam_mode, station_idx, freq, direction, station0_, tile0_); -aocommon::MC2x2Diag PhasedArrayPoint::ArrayFactor(size_t station_idx, - double freq, - const vector3r_t &direction, - const vector3r_t &station0, - const vector3r_t &tile0) { - const telescope::PhasedArray &phasedarraytelescope = - static_cast<const telescope::PhasedArray &>(*telescope_); + // Conversion to MC2x2 (double) for inverse_central_gain needed + return apply_normalisation + ? aocommon::MC2x2(inverse_central_gain.Data()) * gain_matrix + : gain_matrix; +} +aocommon::MC2x2 PhasedArrayPoint::UnnormalisedResponse( + BeamMode beam_mode, size_t station_idx, double freq, + const vector3r_t &direction, const vector3r_t &station0, + const vector3r_t &tile0) const { + const PhasedArray &phased_array = + static_cast<const PhasedArray &>(*telescope_); const double sb_freq = use_channel_frequency_ ? freq : subband_frequency_; - return phasedarraytelescope.GetStation(station_idx) - ->ArrayFactor(time_, freq, direction, sb_freq, station0, tile0); -} - -aocommon::MC2x2 PhasedArrayPoint::ElementResponse( - size_t station_idx, double freq, const vector3r_t &direction) const { - const telescope::PhasedArray &phasedarraytelescope = - static_cast<const telescope::PhasedArray &>(*telescope_); - return phasedarraytelescope.GetStation(station_idx) - ->ComputeElementResponse(time_, freq, direction, is_local_, rotate_); + return phased_array.GetStation(station_idx) + ->Response(beam_mode, time_, freq, direction, sb_freq, station0, tile0, + rotate_); } aocommon::MC2x2 PhasedArrayPoint::ElementResponse(size_t station_idx, double freq, const vector3r_t &direction, size_t element_idx) const { - const telescope::PhasedArray &phasedarraytelescope = - static_cast<const telescope::PhasedArray &>(*telescope_); - return phasedarraytelescope.GetStation(station_idx) + const PhasedArray &phased_array = + static_cast<const PhasedArray &>(*telescope_); + return phased_array.GetStation(station_idx) ->ComputeElementResponse(time_, freq, direction, element_idx, is_local_, rotate_); } @@ -168,7 +130,7 @@ void PhasedArrayPoint::UpdateITRFVectors(double ra, double dec) { casacore::MVDirection(casacore::Quantity(ra, rad_unit), casacore::Quantity(dec, rad_unit)), casacore::MDirection::J2000); - coords::SetITRFVector(itrf_converter.ToDirection(n_dir), dir_itrf_); + coords::SetITRFVector(itrf_converter.ToDirection(n_dir), itrf_direction_); coords::SetITRFVector(itrf_converter.ToDirection(preapplied_beam_dir_), diff_beam_centre_); @@ -181,67 +143,5 @@ void PhasedArrayPoint::UpdateITRFVectors(std::mutex &mutex) { coords::SetITRFVector(itrf_converter.ToDirection(tile_beam_dir_), tile0_); } -bool PhasedArrayPoint::CalculateBeamNormalisation( - BeamMode beam_mode, double time, double frequency, size_t station_idx, - aocommon::MC2x2F &inverse_gain) const { - const telescope::PhasedArray &phasedarraytelescope = - static_cast<const telescope::PhasedArray &>(*telescope_); - if (beam_normalisation_mode_ == BeamNormalisationMode::kNone) { - return false; - } - - const double sb_freq = - use_channel_frequency_ ? frequency : subband_frequency_; - - // if the normalisation mode is kPreApplied, but no beam correction was pre - // applied then there is nothing to do - if (beam_normalisation_mode_ == BeamNormalisationMode::kPreApplied && - preapplied_correction_mode_ == BeamMode::kNone) { - return false; - } - // If the normalisation mode is kPreApplied, or kPreAppliedOrFull and the - // fallback to Full is not needed then the response for the diff_beam_centre_ - // with preapplied_correction_mode_ needs to be computed - if (beam_normalisation_mode_ == BeamNormalisationMode::kPreApplied || - (beam_normalisation_mode_ == BeamNormalisationMode::kPreAppliedOrFull && - preapplied_correction_mode_ != BeamMode::kNone)) { - inverse_gain = aocommon::MC2x2F( - phasedarraytelescope.GetStation(station_idx) - ->Response(preapplied_correction_mode_, time, frequency, - diff_beam_centre_, sb_freq, station0_, tile0_) - .Data()); - } else { - // in all other cases the response in for the reference direction with - // beam_mode is needed - inverse_gain = aocommon::MC2x2F( - phasedarraytelescope.GetStation(station_idx) - ->Response(beam_mode, time, frequency, diff_beam_centre_, sb_freq, - station0_, tile0_) - .Data()); - } - - switch (beam_normalisation_mode_) { - case BeamNormalisationMode::kFull: - case BeamNormalisationMode::kPreApplied: - case BeamNormalisationMode::kPreAppliedOrFull: - if (!inverse_gain.Invert()) { - inverse_gain = aocommon::MC2x2F::Zero(); - } - break; - case BeamNormalisationMode::kAmplitude: { - const float amplitude_inv = 1.0 / std::sqrt(0.5 * Norm(inverse_gain)); - inverse_gain[0] = std::isfinite(amplitude_inv) ? amplitude_inv : 0.0; - inverse_gain[1] = 0.0; - inverse_gain[2] = 0.0; - inverse_gain[3] = std::isfinite(amplitude_inv) ? amplitude_inv : 0.0; - break; - } - default: - throw std::runtime_error("Invalid beam normalisation mode here"); - } - - return true; -} - } // namespace pointresponse } // namespace everybeam diff --git a/cpp/pointresponse/phasedarraypoint.h b/cpp/pointresponse/phasedarraypoint.h index 93d118c0ed701dbdfda42972da42216c68ce3718..f9c972cd49980dc9e3dbd34e94c7a42466d7be4a 100644 --- a/cpp/pointresponse/phasedarraypoint.h +++ b/cpp/pointresponse/phasedarraypoint.h @@ -11,6 +11,7 @@ #include "../common/types.h" #include "../correctionmode.h" #include "../beamnormalisationmode.h" +#include "../phasedarrayresponse.h" #include <aocommon/matrix2x2.h> #include <casacore/measures/Measures/MDirection.h> @@ -18,7 +19,7 @@ namespace everybeam { namespace pointresponse { -class PhasedArrayPoint : public PointResponse { +class PhasedArrayPoint : public PointResponse, protected PhasedArrayResponse { public: PhasedArrayPoint(const telescope::Telescope *telescope_ptr, double time); @@ -44,30 +45,31 @@ class PhasedArrayPoint : public PointResponse { double ra, double dec, double freq, size_t station_idx, size_t field_id) final override; - aocommon::MC2x2 FullResponse(size_t station_idx, double freq, - const vector3r_t &direction, - std::mutex *mutex) final override; - /** - * @brief Convenience function for the python bindings + * @brief Compute beam response. Optional beam normalisation is + * done in this function + * + * @param beam_mode BeamMode, can be any of kNone, kFull, kArrayFactor or + * kElement + * @param station_idx Station index for which to compute the beam response. + * @param freq Freq [Hz] + * @param direction Direction in ITRF + * @param mutex mutex. When provided, the caller keeps control over + * thread-safety. If not provided, the internal mutex will be used and the + * caller is assumed to be thread-safe. + * @return aocommon::MC2x2 */ - aocommon::MC2x2 FullResponse(size_t station_idx, double freq, - const vector3r_t &direction, - const vector3r_t &station0, - const vector3r_t &tile0); - - aocommon::MC2x2Diag ArrayFactor(size_t station_idx, double freq, - const vector3r_t &direction, - std::mutex *mutex) final override; + aocommon::MC2x2 Response(BeamMode beam_mode, size_t station_idx, double freq, + const vector3r_t &direction, + std::mutex *mutex) final override; /** - * @brief Compute the array factor given a direction, station0 direction - * and tile0 direction. Method is used in the python bindings. + * @brief Compute the unnormalised response. */ - aocommon::MC2x2Diag ArrayFactor(size_t station_idx, double freq, - const vector3r_t &direction, - const vector3r_t &station0, - const vector3r_t &tile0); + aocommon::MC2x2 UnnormalisedResponse(BeamMode beam_mode, size_t station_idx, + double freq, const vector3r_t &direction, + const vector3r_t &station0, + const vector3r_t &tile0) const; /** * @brief Convenience method for computing the element response, for a @@ -86,10 +88,6 @@ class PhasedArrayPoint : public PointResponse { const vector3r_t &direction, size_t element_idx) const; - aocommon::MC2x2 ElementResponse( - size_t station_idx, double freq, - const vector3r_t &direction) const final override; - /** * @brief Method for computing the ITRF-vectors, given ra, dec position in * radians and using the cached \param time ((MJD(UTC), s)) @@ -110,16 +108,6 @@ class PhasedArrayPoint : public PointResponse { void SetParalacticRotation(bool rotate) { rotate_ = rotate; } bool GetParalacticRotation() const { return rotate_; }; - protected: - casacore::MDirection delay_dir_, tile_beam_dir_; - vector3r_t station0_, tile0_, dir_itrf_, diff_beam_centre_; - bool use_channel_frequency_; - bool use_differential_beam_; - casacore::MDirection preapplied_beam_dir_; - CorrectionMode preapplied_correction_mode_; - BeamNormalisationMode beam_normalisation_mode_; - double subband_frequency_; - private: /** * @brief Update ITRF coordinates for reference station and reference tile @@ -128,10 +116,7 @@ class PhasedArrayPoint : public PointResponse { */ void UpdateITRFVectors(std::mutex &mutex); - bool CalculateBeamNormalisation(BeamMode beam_mode, double time, - double frequency, size_t station_idx, - aocommon::MC2x2F &inverse_gain) const; - + vector3r_t itrf_direction_; double ra_, dec_; std::mutex mutex_; diff --git a/cpp/pointresponse/pointresponse.h b/cpp/pointresponse/pointresponse.h index d2e3a7045218b0302174cba128840360c1a7d558..8e302f723b282123fdb89c9a887fb8528c9318b1 100644 --- a/cpp/pointresponse/pointresponse.h +++ b/cpp/pointresponse/pointresponse.h @@ -20,12 +20,11 @@ namespace everybeam { namespace pointresponse { /** - * @brief Virtual base class to compute the point response - * + * @brief Virtual base class to compute the point response. */ class PointResponse { public: - virtual ~PointResponse() {} + virtual ~PointResponse() = default; /** * @brief Update the (cached) time @@ -58,44 +57,6 @@ class PointResponse { */ bool HasTimeUpdate() const { return has_time_update_; } - /** - * @brief See FullResponse. - */ - [[deprecated("Use FullResponse() instead.")]] void CalculateStation( - std::complex<float>* response_matrix, double ra, double dec, double freq, - size_t station_idx, size_t field_id) { - FullResponse(response_matrix, ra, dec, freq, station_idx, field_id); - }; - - /** - * @brief See FullResponseAllStations. - */ - [[deprecated("Use FullResponseAllStations() instead.")]] void - CalculateAllStations(std::complex<float>* response_matrices, double ra, - double dec, double freq, size_t field_id) { - FullResponseAllStations(response_matrices, ra, dec, freq, field_id); - }; - - /** - * @brief Get beam response for a given station at a prescribed ra, dec - * position. - * - * @param response_matrix Buffer with a size of 4 complex floats to receive - * the beam response - * @param ra Right ascension (rad) - * @param dec Declination (rad) - * @param freq Frequency (Hz) - * @param station_id Station index, corresponding to measurement set antenna - * index. - * @param field_id Field index as used in the measurement set - */ - virtual void FullResponse(std::complex<float>* response_matrix, double ra, - double dec, double freq, size_t station_id, - size_t field_id) { - Response(BeamMode::kFull, response_matrix, ra, dec, freq, station_id, - field_id); - } - /** * @brief Get beam response for a given station at a prescribed ra, dec * position. @@ -117,74 +78,8 @@ class PointResponse { size_t field_id) = 0; /** - * @brief Get the full beam response for a station, given a pointing direction - * in ITRF coordinates - * - * @param beam_mode Selects beam mode (element, array factor or full) - * @param station_idx Station index - * @param freq Frequency (Hz) - * @param direction Direction in ITRF - * @param mutex Optional mutex. When provided, the caller keeps control over - * thread-safety. If not provided, the internal mutex will be used and the - * caller is assumed to be thread-safe. - * @return aocommon::MC2x2 - */ - aocommon::MC2x2 Response(BeamMode beam_mode, size_t station_idx, double freq, - const vector3r_t& direction, - std::mutex* mutex = nullptr) { - switch (beam_mode) { - case BeamMode::kNone: - return aocommon::MC2x2::Unity(); - case BeamMode::kFull: - return FullResponse(station_idx, freq, direction, mutex); - case BeamMode::kElement: - return ElementResponse(station_idx, freq, direction); - case BeamMode::kArrayFactor: - return ArrayFactor(station_idx, freq, direction, mutex); - default: - throw std::runtime_error("Invalid beam mode."); - } - } - - /** - * @brief Get the full beam response for a station, given a pointing direction - * in ITRF coordinates - * - * @param station_idx Station index - * @param freq Frequency (Hz) - * @param direction Direction in ITRF - * @param mutex Optional mutex. When provided, the caller keeps control over - * thread-safety. If not provided, the internal mutex will be used and the - * caller is assumed to be thread-safe. - * @return aocommon::MC2x2 - */ - virtual aocommon::MC2x2 FullResponse(size_t station_idx, double freq, - const vector3r_t& direction, - std::mutex* mutex = nullptr) { - throw std::runtime_error("Not yet implemented"); - } - - /** - * @brief Same as FullResponse, but now iterate over all stations in - * MS. - * - * @param response_matrices Buffer with a size of 4 * nr_stations complex - * floats to receive the beam response - * @param ra Right ascension (rad) - * @param dec Declination (rad) - * @param freq Frequency (Hz) - * @param field_id Field index as used in the measurement set - */ - virtual void FullResponseAllStations(std::complex<float>* response_matrices, - double ra, double dec, double freq, - size_t field_id) { - ResponseAllStations(BeamMode::kFull, response_matrices, ra, dec, freq, - field_id); - } - - /** - * @brief Same as FullResponse, but now iterate over all stations in - * MS. + * @brief Same as Response, but now iterate over all stations in + * measurement set. * * @param beam_mode Selects beam mode (element, array factor or full) * @param response_matrices Buffer with a size of 4 * nr_stations complex @@ -205,7 +100,7 @@ class PointResponse { } /** - * @brief Get the array factor for a station, given a pointing direction + * @brief Get the beam response for a station, given a pointing direction * in ITRF coordinates * * @param station_idx Station index @@ -214,16 +109,11 @@ class PointResponse { * @param mutex Optional mutex. When provided, the caller keeps control over * thread-safety. If not provided, the internal mutex will be used and the * caller is assumed to be thread-safe. - * @return aocommon::MC2x2Diag + * @return aocommon::MC2x2 */ - virtual aocommon::MC2x2Diag ArrayFactor(size_t station_idx, double freq, - const vector3r_t& direction, - std::mutex* mutex = nullptr) { - throw std::runtime_error("Not yet implemented"); - }; - - virtual aocommon::MC2x2 ElementResponse(size_t station_idx, double freq, - const vector3r_t& direction) const { + virtual aocommon::MC2x2 Response(BeamMode beam_mode, size_t station_idx, + double freq, const vector3r_t& direction, + std::mutex* mutex = nullptr) { throw std::runtime_error("Not yet implemented"); } diff --git a/cpp/telescope/dish.cc b/cpp/telescope/dish.cc index 2efa0f76e02e371ca48606520dfe687dd97bbcc1..532bad464b3592367c5429376c524d01948e1f12 100644 --- a/cpp/telescope/dish.cc +++ b/cpp/telescope/dish.cc @@ -16,7 +16,7 @@ using everybeam::telescope::Dish; Dish::Dish(const casacore::MeasurementSet &ms, std::unique_ptr<circularsymmetric::Coefficients> coefficients, const Options &options) - : Telescope(ms, options), coefficients_(std::move(coefficients)) { + : Telescope(ms, options), dish_coefficients_(std::move(coefficients)) { casacore::MSField field_table = ms.field(); casacore::ArrayColumn<double> pointing_dir_col( field_table, casacore::MSField::columnName(casacore::MSField::DELAY_DIR)); @@ -25,7 +25,7 @@ Dish::Dish(const casacore::MeasurementSet &ms, casacore::Array<double> pdir = pointing_dir_col(field_id); double pdir_ra = *pdir.cbegin(); double pdir_dec = *(pdir.cbegin() + 1); - ms_properties_.field_pointing.emplace_back(pdir_ra, pdir_dec); + field_pointing_.emplace_back(pdir_ra, pdir_dec); } SetIsTimeRelevant(false); } diff --git a/cpp/telescope/dish.h b/cpp/telescope/dish.h index c91880dfc54a2f6570fa5c06162adc90c64aaadd..3e93bdc69e72f1f2a6bc76d62029185ee2b308f2 100644 --- a/cpp/telescope/dish.h +++ b/cpp/telescope/dish.h @@ -17,12 +17,10 @@ namespace everybeam { namespace griddedresponse { class DishGrid; -class GriddedResponse; } // namespace griddedresponse namespace pointresponse { class PointResponse; -class DishPoint; } // namespace pointresponse namespace telescope { @@ -32,9 +30,6 @@ namespace telescope { * response. */ class Dish final : public Telescope { - friend class griddedresponse::DishGrid; - friend class pointresponse::DishPoint; - public: Dish(const casacore::MeasurementSet &ms, std::unique_ptr<circularsymmetric::Coefficients> coefficients, @@ -46,12 +41,24 @@ class Dish final : public Telescope { std::unique_ptr<pointresponse::PointResponse> GetPointResponse( double time) const override; + /** + * @brief Get (ra, dec) pointings of fields. + * + * @return std::vector<std::pair<double, double>> Vector of size number of + * fields, and (ra, dec) pointings as entries. + */ + const std::vector<std::pair<double, double>> &GetFieldPointing() const { + return field_pointing_; + } + + const circularsymmetric::Coefficients *GetDishCoefficients() const { + return dish_coefficients_.get(); + } + private: - struct MSProperties { - std::vector<std::pair<double, double>> field_pointing; - }; - MSProperties ms_properties_; - std::unique_ptr<circularsymmetric::Coefficients> coefficients_; + std::unique_ptr<circularsymmetric::Coefficients> dish_coefficients_; + /// Store ra, dec pointing per field id from measurement set + std::vector<std::pair<double, double>> field_pointing_; }; } // namespace telescope } // namespace everybeam diff --git a/cpp/telescope/mwa.cc b/cpp/telescope/mwa.cc index e3f50d6a2727f6f409d44e05909e6b9614c935dd..b6f12e38d6c77eabd007d22a02622c59902f1aeb 100644 --- a/cpp/telescope/mwa.cc +++ b/cpp/telescope/mwa.cc @@ -16,19 +16,24 @@ using everybeam::telescope::MWA; MWA::MWA(const casacore::MeasurementSet &ms, const Options &options) : Telescope(ms, options) { - if (GetNrStations() == 0) throw std::runtime_error("No antennae in set"); + if (GetNrStations() == 0) { + throw std::runtime_error("No antennae in set"); + } casacore::MSAntenna antenna(ms.antenna()); casacore::MPosition::ScalarColumn antenna_pos_col( antenna, antenna.columnName(casacore::MSAntennaEnums::POSITION)); - ms_properties_.array_position = antenna_pos_col(0); + array_position_ = antenna_pos_col(0); casacore::Table mwa_tile_pointing = ms.keywordSet().asTable("MWA_TILE_POINTING"); casacore::ArrayColumn<int> delays_col(mwa_tile_pointing, "DELAYS"); casacore::Array<int> delays_arr = delays_col(0); casacore::Array<int>::contiter delays_arr_ptr = delays_arr.cbegin(); - for (int i = 0; i != 16; ++i) ms_properties_.delays[i] = delays_arr_ptr[i]; + for (auto &delay : delays_) { + delay = *delays_arr_ptr; + ++delays_arr_ptr; + } } std::unique_ptr<GriddedResponse> MWA::GetGriddedResponse( @@ -38,7 +43,6 @@ std::unique_ptr<GriddedResponse> MWA::GetGriddedResponse( } std::unique_ptr<PointResponse> MWA::GetPointResponse(double time) const { - // Get and return PointResponse ptr std::unique_ptr<PointResponse> point_response(new MWAPoint(this, time)); return point_response; } \ No newline at end of file diff --git a/cpp/telescope/mwa.h b/cpp/telescope/mwa.h index dadb50e2f902e800a0c57967368f25c7e355da52..9e9182d7dcc2b2c5f0f817c002ce52016f9c5ffd 100644 --- a/cpp/telescope/mwa.h +++ b/cpp/telescope/mwa.h @@ -14,21 +14,16 @@ namespace everybeam { namespace griddedresponse { -class MWAGrid; class GriddedResponse; } // namespace griddedresponse namespace pointresponse { -class MWAPoint; class PointResponse; } // namespace pointresponse namespace telescope { class MWA final : public Telescope { - friend class griddedresponse::MWAGrid; - friend class pointresponse::MWAPoint; - public: /** * @brief Construct a new MWA object @@ -45,12 +40,12 @@ class MWA final : public Telescope { std::unique_ptr<pointresponse::PointResponse> GetPointResponse( double time) const override; + casacore::MPosition GetArrayPosition() const { return array_position_; } + const std::array<double, 16> &GetDelays() const { return delays_; } + private: - struct MSProperties { - double delays[16]; - casacore::MPosition array_position; - }; - MSProperties ms_properties_; + casacore::MPosition array_position_; + std::array<double, 16> delays_; }; } // namespace telescope diff --git a/python/test/test_pybindings.py b/python/test/test_pybindings.py index aefd6cceed257d688a42bd4d1aec3db22ca7b17c..8b9665b379d268060f17a1052f588e6dfe33119b 100644 --- a/python/test/test_pybindings.py +++ b/python/test/test_pybindings.py @@ -170,13 +170,6 @@ def test_coordinate_system(): def test_lofar(ref, differential_beam): ms_path = os.path.join(DATADIR, ref["filename"]) telescope = load_telescope(ms_path, use_differential_beam=differential_beam) - a = telescope.gridded_response( - ref["coordinate_system"], - ref["time"], - ref["freq"], - ref["station_id"], - field_index=10, - ) assert isinstance(telescope, LOFAR) time = ref["time"] diff --git a/python/wrappers/pytelescope.cc b/python/wrappers/pytelescope.cc index e8d9cf750b4c65f21f9c24270552a21c5b0efb53..ad888be6bf4ea685a25cd78126896242075c0b2c 100644 --- a/python/wrappers/pytelescope.cc +++ b/python/wrappers/pytelescope.cc @@ -438,8 +438,8 @@ void init_telescope(py::module &m) { (self.GetOptions().beam_normalisation_mode == BeamNormalisationMode::kPreApplied) ? aocommon::MC2x2::Unity() - : phased_array_point.FullResponse(idx, freq, direction, - &mutex); + : phased_array_point.Response(BeamMode::kFull, idx, freq, + direction, &mutex); return cast_matrix(response); }, R"pbdoc( @@ -597,9 +597,12 @@ void init_telescope(py::module &m) { PhasedArrayPoint &phased_array_point = static_cast<PhasedArrayPoint &>(*point_response); phased_array_point.SetParalacticRotation(rotate); - const aocommon::MC2x2 response = phased_array_point.FullResponse( - idx, freq, direction, station0, tile0); + aocommon::MC2x2 response = phased_array_point.UnnormalisedResponse( + BeamMode::kFull, idx, freq, direction, station0, tile0); + // We can't delegate the normalisation to Response, in this case. + // Since the diff_beam_centre direction would not be computed + // correctly. if (self.GetOptions().beam_normalisation_mode == BeamNormalisationMode::kPreApplied) { vector3r_t diff_beam_centre; @@ -609,13 +612,15 @@ void init_telescope(py::module &m) { diff_beam_centre); aocommon::MC2x2 response_diff_beam = - phased_array_point.FullResponse(idx, freq, diff_beam_centre, - station0, tile0); + phased_array_point.UnnormalisedResponse( + BeamMode::kFull, idx, freq, diff_beam_centre, station0, + tile0); apply_differential_beam(response_diff_beam, response); return cast_matrix(response_diff_beam); } else { return cast_matrix(response); } + return cast_matrix(response); }, R"pbdoc( Get station response in user-specified direction @@ -809,20 +814,30 @@ void init_telescope(py::module &m) { phased_array_point.SetUseLocalCoordinateSystem(is_local); phased_array_point.SetParalacticRotation(rotate); + // Avoid any beam normalisations, so compute station0 and tile0 + // manually + ITRFConverter itrf_converter(time); + vector3r_t station0; + vector3r_t tile0; + SetITRFVector(itrf_converter.ToDirection(self.GetDelayDirection()), + station0); + SetITRFVector( + itrf_converter.ToDirection(self.GetTileBeamDirection()), tile0); const aocommon::MC2x2 response = - phased_array_point.ElementResponse(idx, freq, direction); + phased_array_point.UnnormalisedResponse( + BeamMode::kElement, idx, freq, direction, station0, tile0); if (self.GetOptions().beam_normalisation_mode == BeamNormalisationMode::kPreApplied) { vector3r_t diff_beam_centre; - ITRFConverter itrf_converter(time); SetITRFVector( itrf_converter.ToDirection(self.GetPreappliedBeamDirection()), diff_beam_centre); aocommon::MC2x2 response_diff_beam = - phased_array_point.ElementResponse(idx, freq, - diff_beam_centre); + phased_array_point.UnnormalisedResponse( + BeamMode::kElement, idx, freq, diff_beam_centre, station0, + tile0); apply_differential_beam(response_diff_beam, response); return cast_matrix(response_diff_beam); } else { @@ -875,8 +890,10 @@ void init_telescope(py::module &m) { static_cast<PhasedArrayPoint &>(*point_response); // Diagonal to 2x2 matrix - const aocommon::MC2x2 response(phased_array_point.ArrayFactor( - idx, freq, direction, station0, tile0)); + const aocommon::MC2x2 response( + phased_array_point.UnnormalisedResponse(BeamMode::kArrayFactor, + idx, freq, direction, + station0, tile0)); return cast_matrix(response); }, R"pbdoc(