diff --git a/.gitlab-ci.common.yml b/.gitlab-ci.common.yml index a0e352c91283142f4f988fa23eccae42fd163bac..976639dbebfec2e5644a962177442091afe73f77 100644 --- a/.gitlab-ci.common.yml +++ b/.gitlab-ci.common.yml @@ -114,16 +114,20 @@ format-2204: - git submodule update --init external/aocommon - ./scripts/run-format.sh +.download-wsrt-measures: + before_script: + - wget -q ftp://ftp.astron.nl/outgoing/Measures/WSRT_Measures.ztar + - tar -xf WSRT_Measures.ztar -C /var/lib/casacore/data/ + - rm -f WSRT_Measures.ztar + # Build a debug version of EveryBeam from the base image test-and-coverage-2204: - extends: .needs-base-2204 + extends: [ .needs-base-2204, .download-wsrt-measures ] stage: build variables: GIT_SUBMODULE_STRATEGY: normal script: - WORKDIR=$PWD - # Download casacore wsrt measures - - wget -q ftp://ftp.astron.nl/outgoing/Measures/WSRT_Measures.ztar && tar -xf WSRT_Measures.ztar -C /var/lib/casacore/data/ && rm -f WSRT_Measures.ztar # Build in Debug mode - mkdir -p build/coeffs/lobes && cd build - mv /coeffs/lobes/* ./coeffs/lobes/ @@ -161,14 +165,12 @@ test-and-coverage-2204: # Python tests do not work with the sanitizer, since the main executable # (python) was not built with the sanitizer. sanitize-2204: - extends: [ ".needs-base-2204", ".dind-requester" ] + extends: [ .needs-base-2204, .dind-requester, .download-wsrt-measures ] stage: build image: $BASE_IMAGE_2204 variables: GIT_SUBMODULE_STRATEGY: normal script: - # Download casacore wsrt measures - - wget -q ftp://ftp.astron.nl/outgoing/Measures/WSRT_Measures.ztar && tar -xf WSRT_Measures.ztar -C /var/lib/casacore/data/ && rm -f WSRT_Measures.ztar # Build and run unit tests. - mkdir -p build/coeffs/lobes && cd build - mv /coeffs/lobes/* ./coeffs/lobes/ @@ -183,20 +185,21 @@ sanitize-2204: script: - mkdir -p build/coeffs/lobes && cd build - mv /coeffs/lobes/* ./coeffs/lobes/ - - echo Configuring with CXX flags \"$CXX_FLAGS\" - cmake -DBUILD_TESTING=ON -DBUILD_WITH_PYTHON=ON -DCMAKE_CXX_FLAGS="$CXX_FLAGS" .. - - make -j`nproc` + - make -j`nproc` install + - if [ -n "$RUN_TESTS" ]; then ctest -j`nproc` --output-on-failure; fi -build-everybeam-2004: - extends: [.needs-base-2004,.build-everybeam] +build-test-2004: + extends: [ .needs-base-2004, .build-everybeam, .download-wsrt-measures ] variables: CXX_FLAGS: -mavx2 -mfma + RUN_TESTS: yes please run all tests with AVX support build-everybeam-2204: - extends: [.needs-base-2204,.build-everybeam] + extends: [ .needs-base-2204, .build-everybeam ] build-everybeam-2204-gcc12: - extends: [.needs-base-2204-gcc12,.build-everybeam] + extends: [ .needs-base-2204-gcc12, .build-everybeam ] build-doc-2204: extends: .needs-base-2204 @@ -212,7 +215,7 @@ build-doc-2204: - build/doc/html build-package-2204: - extends: [.needs-base-2204] + extends: .needs-base-2204 stage: package variables: GIT_SUBMODULE_STRATEGY: normal @@ -236,7 +239,7 @@ build-package-2204: build-compare-oskar-2204: stage: oskar-comparison - extends: [.needs-base-2204] + extends: .needs-base-2204 image: $BASE_IMAGE_2204 variables: GIT_SUBMODULE_STRATEGY: normal @@ -302,7 +305,7 @@ deploy-image-2204: - dist/everybeam*.whl cibuild-python-wheels: - extends: [ ".needs-base-2204", ".cibuildwheels-custom" ] + extends: [ .needs-base-2204, .cibuildwheels-custom ] stage: deploy image: python:3.8 variables: diff --git a/cpp/beamformer.cc b/cpp/beamformer.cc index 030238d42fbf5f61e92686a963b843a14c0b24b7..b3521ab5167adf8067e19f5a1598419be0a91195 100644 --- a/cpp/beamformer.cc +++ b/cpp/beamformer.cc @@ -84,7 +84,7 @@ std::vector<aocommon::MC2x2Diag> BeamFormer::ComputeWeightedResponses( ComputeGeometricResponse(delta_phase_reference_positions_, pointing); // Initialize and fill result - double weight_sum[2] = {0.0, 0.0}; + std::array<double, 2> weight_sum = {0.0, 0.0}; std::vector<aocommon::MC2x2Diag> result(antennas_.size()); for (size_t idx = 0; idx < antennas_.size(); ++idx) { // Get geometric response at index @@ -98,8 +98,7 @@ std::vector<aocommon::MC2x2Diag> BeamFormer::ComputeWeightedResponses( // Normalize the weight by the number of antennas for (auto& entry : result) { - entry[0] /= weight_sum[0]; - entry[1] /= weight_sum[1]; + entry = {entry[0] / weight_sum[0], entry[1] / weight_sum[1]}; } return result; } diff --git a/cpp/beamformerlofar.cc b/cpp/beamformerlofar.cc index ef7d92cc220c1d940ea1e048208655f811f2f0be..d5dd6fd3dae6080d5f6f6d7e2a3f5ae8fe524046 100644 --- a/cpp/beamformerlofar.cc +++ b/cpp/beamformerlofar.cc @@ -27,21 +27,21 @@ aocommon::MC2x2Diag BeamFormerLofar::FieldArrayFactor( aocommon::UVector<std::complex<double>> geometric_response = BeamFormer::ComputeGeometricResponse(antenna_positions, delta_direction); - double weight_sum[2] = {0.0, 0.0}; - aocommon::MC2x2Diag result(0., 0.); + std::array<std::complex<double>, 2> response_sum = {0.0, 0.0}; + std::array<double, 2> weight_sum = {0.0, 0.0}; for (size_t idx = 0; idx < antenna_positions.size(); ++idx) { - result[0] += geometric_response[idx] * (1.0 * antenna_enabled[idx][0]); - result[1] += geometric_response[idx] * (1.0 * antenna_enabled[idx][1]); + response_sum[0] += + geometric_response[idx] * (1.0 * antenna_enabled[idx][0]); + response_sum[1] += + geometric_response[idx] * (1.0 * antenna_enabled[idx][1]); weight_sum[0] += (1.0 * antenna_enabled[idx][0]); weight_sum[1] += (1.0 * antenna_enabled[idx][1]); } // Normalize the weight by the number of enabled tiles - result[0] /= weight_sum[0]; - result[1] /= weight_sum[1]; - - return result; + return aocommon::MC2x2Diag(response_sum[0] / weight_sum[0], + response_sum[1] / weight_sum[1]); } aocommon::MC2x2 BeamFormerLofar::LocalResponse( diff --git a/cpp/hamaker/hamakerelementresponse.cc b/cpp/hamaker/hamakerelementresponse.cc index c332e4ac41075526df05b29087486b71a47a56be..63d58c27c73bb3aa35c0bac0da332347d99175db 100644 --- a/cpp/hamaker/hamakerelementresponse.cc +++ b/cpp/hamaker/hamakerelementresponse.cc @@ -99,10 +99,8 @@ aocommon::MC2x2 HamakerElementResponse::Response(double freq, double theta, const double caz = std::cos(angle); const double saz = std::sin(angle); - response[0] += caz * P.first; - response[1] += -saz * P.second; - response[2] += saz * P.first; - response[3] += caz * P.second; + response += aocommon::MC2x2(caz * P.first, -saz * P.second, saz * P.first, + caz * P.second); // Update sign and kappa. sign = -sign; diff --git a/cpp/pointresponse/dishpoint.cc b/cpp/pointresponse/dishpoint.cc index 98c8a9baa4bba18b7184be8aac499d2c209891bc..890439480bf3a81834276e43760a15fb85aa3353 100644 --- a/cpp/pointresponse/dishpoint.cc +++ b/cpp/pointresponse/dishpoint.cc @@ -86,15 +86,7 @@ aocommon::MC2x2 DishPoint::Response(BeamMode beam_mode, size_t station_idx, vp.Render(buffer, pointing_direction_angle, 0.0, 0.0, 0.0, freq); - // Because of the conversion from std::complex<float> to std::complex<double> - // It is not possible to directly return the buffer by a - // return aocommon::MC2x2(buffer); - // Instead, cast the buffer element by element before returning - aocommon::MC2x2 result; - for (int i = 0; i < 4; i++) { - result[i] = buffer[i]; - } - return result; + return aocommon::MC2x2(aocommon::MC2x2F(buffer)); } void DishPoint::ResponseAllStations(BeamMode beam_mode, diff --git a/cpp/sphericalharmonicsresponse.cc b/cpp/sphericalharmonicsresponse.cc index 5dc7995703dbe45f38312550e9ff18c2fd66b219..9fdd871fef6edaa94f43292760de8f02257b0982 100644 --- a/cpp/sphericalharmonicsresponse.cc +++ b/cpp/sphericalharmonicsresponse.cc @@ -220,10 +220,10 @@ aocommon::MC2x2 SphericalHarmonicsResponse::ComputeResponse( std::complex<double> q3; std::tie(q2, q3) = common::F4far_new(nms_(i, 2), nms_(i, 1), nms_(i, 0), theta, phi); - response[0] += q2 * c0; // xx - response[1] += q3 * c0; // xy - response[2] += q2 * c1; // yx - response[3] += q3 * c1; // yy + + // xx, xy, yx, yy + response += ElementProduct(aocommon::MC2x2(q2, q3, q2, q3), + aocommon::MC2x2(c0, c0, c1, c1)); } return response; diff --git a/cpp/sphericalharmonicsresponsefixeddirection.cc b/cpp/sphericalharmonicsresponsefixeddirection.cc index f809c1a262c0f59e95d34f71c42dc970b9687e18..b8303ad7ff16773901be3b3157f0487a5bd7c119 100644 --- a/cpp/sphericalharmonicsresponsefixeddirection.cc +++ b/cpp/sphericalharmonicsresponsefixeddirection.cc @@ -66,10 +66,10 @@ aocommon::MC2x2 SphericalHarmonicsResponseFixedDirection::ComputeResponse( coefficients(1, frequency_index, element_index, i); const std::complex<double> q2 = base_functions_(i, 0); const std::complex<double> q3 = base_functions_(i, 1); - response[0] += q2 * c0; // xx - response[1] += q3 * c0; // xy - response[2] += q2 * c1; // yx - response[3] += q3 * c1; // yy + + // xx, xy, yx, yy + response += ElementProduct(aocommon::MC2x2(q2, q3, q2, q3), + aocommon::MC2x2(c0, c0, c1, c1)); } return response; diff --git a/cpp/test/tatermconfig.cc b/cpp/test/tatermconfig.cc index d2475c1ab3d0025103d1aa58342d6d4dc2ffd499..7999303f55408342f50487cd106326d0490c8fec 100644 --- a/cpp/test/tatermconfig.cc +++ b/cpp/test/tatermconfig.cc @@ -228,17 +228,14 @@ BOOST_AUTO_TEST_CASE(combine_aterms) { n_channels, n_times, coord_system); // Combine the aterms generated in the beam-only and diagonal-only modes - std::vector<std::complex<float>> aterms_product(aterm_buffer_size); for (size_t j = 0; j != aterm_buffer_size; j += kAtermMatrixSize) { - aocommon::MC2x2F scratch = + const aocommon::MC2x2F product = aocommon::MC2x2F(aterm_buffer_diagonal.data() + j) * aocommon::MC2x2F(aterm_buffer_beam.data() + j); - scratch.AssignTo(aterms_product.data() + j); + for (size_t i = 0; i < 4; ++i) { + BOOST_CHECK_CLOSE(product[i], aterm_buffer_combined[j + i], 1.0e-4); + } } - - BOOST_CHECK_EQUAL_COLLECTIONS(aterms_product.begin(), aterms_product.end(), - aterm_buffer_combined.begin(), - aterm_buffer_combined.end()); } BOOST_AUTO_TEST_CASE(fourierfit) { diff --git a/cpp/test/tdish.cc b/cpp/test/tdish.cc index c4738af64b221baed6a7f3a07355983b496bc7ec..3b35d853adf17e8dff7a28508231ac6b29274dbd 100644 --- a/cpp/test/tdish.cc +++ b/cpp/test/tdish.cc @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(load_dish) { dynamic_cast<everybeam::pointresponse::DishPoint*>(point_response.get()); BOOST_REQUIRE(dish_point_response); - std::vector<std::vector<std::complex<float>>> reference_response = { + const std::vector<std::vector<std::complex<float>>> kReferenceResponse = { {{1.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {1.0, 0.0}}, {{0.382599, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {0.382599, 0.0}}}; @@ -64,9 +64,8 @@ BOOST_AUTO_TEST_CASE(load_dish) { kFrequency, station_id, field_id); for (std::size_t i = 0; i < 4; ++i) { - std::cout << point_response_buffer[i] << std::endl; - BOOST_CHECK( - std::abs(point_response_buffer[i] - reference_response[j][i]) < 1e-6); + BOOST_CHECK_CLOSE(point_response_buffer[i], kReferenceResponse[j][i], + 2.0e-4); } casacore::MDirection pointing(casacore::Quantity(ra, "rad"), @@ -76,13 +75,12 @@ BOOST_AUTO_TEST_CASE(load_dish) { const coords::ItrfConverter itrf_converter(kTime); vector3r_t direction = itrf_converter.ToItrf(pointing); - aocommon::MC2x2 response = dish_point_response->Response( + const aocommon::MC2x2 response = dish_point_response->Response( everybeam::BeamMode::kFull, station_id, kFrequency, direction); for (std::size_t i = 0; i < 4; ++i) { - std::cout << response[i] << " " << reference_response[j][i] << std::endl; - BOOST_CHECK(std::abs(response[i] - std::complex<double>( - reference_response[j][i])) < 1e-6); + BOOST_CHECK_CLOSE(response[i], + std::complex<double>(kReferenceResponse[j][i]), 2.0e-4); } } } diff --git a/cpp/test/tlofar_lba.cc b/cpp/test/tlofar_lba.cc index fc2b906ea666bacb9f2f6bfb56aa87c5f5572ef8..8c765926b028ba402738a448e1947aad2d070d71 100644 --- a/cpp/test/tlofar_lba.cc +++ b/cpp/test/tlofar_lba.cc @@ -30,19 +30,26 @@ using everybeam::griddedresponse::PhasedArrayGrid; using everybeam::telescope::LOFAR; using everybeam::telescope::Telescope; -BOOST_AUTO_TEST_SUITE(tlofar_lba) +BOOST_AUTO_TEST_SUITE(lofar_lba) +namespace { // Properties extracted from MS -double time = 4.92183348e+09; -double frequency = 57812500.; -double ra(-1.44194878), dec(0.85078091); +const double kTime = 4.92183348e+09; +const double kFrequency = 57812500.0; +const double kRa = -1.44194878; +const double kDec = 0.85078091; // Properties of grid -std::size_t width(4), height(4); -double dl(0.5 * M_PI / 180.), dm(0.5 * M_PI / 180.), shift_l(0.), shift_m(0.); +const std::size_t kWidth = 4; +const std::size_t kHeight = 4; +const double kDl = 0.5 * M_PI / 180.0; +const double kDm = 0.5 * M_PI / 180.0; +const double kShiftL = 0.0; +const double kShiftM = 0.0; -CoordinateSystem coord_system = {width, height, ra, dec, - dl, dm, shift_l, shift_m}; +const CoordinateSystem kCoordinateSystem = {kWidth, kHeight, kRa, kDec, + kDl, kDm, kShiftL, kShiftM}; +} // namespace BOOST_AUTO_TEST_CASE(test_hamaker) { Options options; @@ -71,7 +78,7 @@ BOOST_AUTO_TEST_CASE(test_hamaker) { const Station& station = lofartelescope.GetStation(19); aocommon::MC2x2 element_response = - station.ComputeElementResponse(time, frequency, direction, false, true); + station.ComputeElementResponse(kTime, kFrequency, direction, false, true); for (size_t i = 0; i != 4; ++i) { BOOST_CHECK(std::abs(element_response[i] - target_element_response[i]) < @@ -86,7 +93,7 @@ BOOST_AUTO_TEST_CASE(test_hamaker) { vector3r_t direction_s31 = {0.667806, -0.0770635, 0.740335}; vector3r_t station0_dir = {0.655743, -0.0670973, 0.751996}; aocommon::MC2x2 station31_response = station31.Response( - time, freq4, direction_s31, freq4, station0_dir, station0_dir); + kTime, freq4, direction_s31, freq4, station0_dir, station0_dir); aocommon::MC2x2 target_station_response( {-0.71383788, 0.00612506}, {-0.4903527, 0.00171652}, @@ -99,7 +106,7 @@ BOOST_AUTO_TEST_CASE(test_hamaker) { // Gridded response std::unique_ptr<GriddedResponse> grid_response = - telescope->GetGriddedResponse(coord_system); + telescope->GetGriddedResponse(kCoordinateSystem); BOOST_CHECK(nullptr != dynamic_cast<PhasedArrayGrid*>(grid_response.get())); // Define buffer and get gridded responses @@ -107,7 +114,8 @@ BOOST_AUTO_TEST_CASE(test_hamaker) { grid_response->GetStationBufferSize(1)); grid_response->Response(everybeam::BeamMode::kFull, - antenna_buffer_single.data(), time, frequency, 31, 0); + antenna_buffer_single.data(), kTime, kFrequency, 31, + 0); // Compare with everybeam at pixel (1, 3), reference solution obtained with // everybeam at commit sha 70a286e7dace4616417b0e973a624477f15c9ce3 @@ -117,10 +125,10 @@ BOOST_AUTO_TEST_CASE(test_hamaker) { {-0.541472, 0.0053149}, {0.775696, -0.00369905}}; - std::size_t offset_13 = (3 + 1 * width) * 4; + std::size_t offset_13 = (3 + 1 * kWidth) * 4; for (std::size_t i = 0; i < 4; ++i) { BOOST_CHECK(std::abs(antenna_buffer_single[offset_13 + i] - - everybeam_ref_p13[i]) < 1e-6); + everybeam_ref_p13[i]) < 1.0e-6); } } @@ -142,7 +150,7 @@ BOOST_AUTO_TEST_CASE(test_lobes) { // Gridded response std::unique_ptr<GriddedResponse> grid_response = - telescope->GetGriddedResponse(coord_system); + telescope->GetGriddedResponse(kCoordinateSystem); // Define buffer and get gridded responses std::vector<std::complex<float>> antenna_buffer_single( @@ -150,7 +158,8 @@ BOOST_AUTO_TEST_CASE(test_lobes) { // Get the gridded response for station 20 (of course!) grid_response->Response(everybeam::BeamMode::kFull, - antenna_buffer_single.data(), time, frequency, 20, 0); + antenna_buffer_single.data(), kTime, kFrequency, 20, + 0); // Compare with everybeam at pixel (1, 3). This solution only is a "reference" // certainly not a "ground-truth" @@ -160,11 +169,11 @@ BOOST_AUTO_TEST_CASE(test_lobes) { {0.0086051673, 0.034685627}, {1.5801408, 2.0045171}}; - std::size_t offset_13 = (3 + 1 * width) * 4; + std::size_t offset_13 = (3 + 1 * kWidth) * 4; for (std::size_t i = 0; i < 4; ++i) { - // relative tolerance is 2e-1%, so 2e-3 + // relative tolerance is 5.0e-1%, so 5.0e-3 BOOST_CHECK_CLOSE(antenna_buffer_single[offset_13 + i], - everybeam_ref_p13[i], 2e-1); + everybeam_ref_p13[i], 5.0e-1); } } diff --git a/docker/ubuntu_20_04_base b/docker/ubuntu_20_04_base index 3ecbd4f2915d9fb1d93f8f6a4b881deca2e11141..241f1f139e1f8d2272e3f1a4f6975adb3fac82fb 100644 --- a/docker/ubuntu_20_04_base +++ b/docker/ubuntu_20_04_base @@ -30,6 +30,8 @@ RUN export DEBIAN_FRONTEND="noninteractive" && \ wget \ && \ rm -rf /var/lib/apt/lists/* +# pytest-lazy-fixture does not work with pytest-8.x -> Use pytest-7.x for now. +# TODO(AST-1501): Investigate removing pytest-lazy-fixture. RUN pip3 install \ aptly-api-client \ astropy \ @@ -42,6 +44,8 @@ RUN pip3 install \ myst-parser \ numpy==1.19.0 \ pandas \ + pytest~=7.0 \ + pytest-lazy-fixture \ scipy \ sphinx \ sphinx_rtd_theme \