Skip to content
Snippets Groups Projects
Select Git revision
  • 61a057e9158f73c792ff8b22d460b4b6ecdbbbbe
  • main default protected
  • gpu_predict
  • compute-smearterms-gpu
  • enable-radec2lmn-avx2
  • new-implementation
  • remove-duo-matrix
  • temp_initial_split
8 results

Directions.h

  • mancini's avatar
    Mattia Mancini authored
    61a057e9
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    Directions.h 7.23 KiB
    // Directions.h: A collection of directions
    //
    // Copyright (C) 2020 ASTRON (Netherlands Institute for Radio Astronomy)
    // SPDX-License-Identifier: Apache2.0
    
    /// \file
    /// \brief A collection of directions
    
    #ifndef PREDICT_DIRECTIONS_H_
    #define PREDICT_DIRECTIONS_H_
    
    #include <Direction.h>
    #include <ObjectCollection.h>
    #include <common/SmartVector.h>
    
    #include <vector>
    #include <xsimd/xsimd.hpp>
    #include <xtensor/xmath.hpp>
    #include <xtensor/xtensor.hpp>
    #include <xtensor/xview.hpp>
    
    using Direction = dp3::base::Direction;
    
    enum computation_strategy { SINGLE, MULTI, MULTI_SIMD };
    
    class Directions : ObjectCollection<Direction> {
    public:
      enum computation_strategy { SINGLE, MULTI, MULTI_SIMD };
      Directions() : ra(), dec() {}
      void Add(const Direction &direction) {
        ra.push_back(direction.ra);
        dec.push_back(direction.dec);
      }
    
      void Add(const std::span<Direction> &directions) {
        ra.reserve(Size() + directions.size());
        dec.reserve(Size() + directions.size());
        for (size_t i = 0; i < directions.size(); ++i) {
          ra.push_back(directions[i].ra);
          dec.push_back(directions[i].dec);
        }
      }
    
      void Reserve(size_t new_size) {
        ra.reserve(new_size);
        dec.reserve(new_size);
      }
    
      void Clear() {
        ra.clear();
        dec.clear();
      }
    
      Direction operator[](size_t i) const { return Direction(ra[i], dec[i]); }
    
      size_t Size() const { return ra.size(); }
    
      SmartVector<double> ra;
      SmartVector<double> dec;
    
      /**
       * Compute LMN coordinates of \p direction relative to \p reference.
       * \param[in]   reference
       * Reference direction on the celestial sphere.
       * \param[in]   direction
       * Direction of interest on the celestial sphere.
       * \param[out]   lmn
       * Pointer to a buffer of (at least) length three into which the computed LMN
       * coordinates will be written.
       */
      template <computation_strategy T = computation_strategy::MULTI_SIMD>
      inline void RaDec2Lmn(const Direction &reference,
                            xt::xtensor<double, 2> &lmn) const;
    };
    
    template <>
    inline void Directions::RaDec2Lmn<Directions::computation_strategy::MULTI>(
        const Direction &reference, xt::xtensor<double, 2> &lmn) const {
      /**
       * \f{eqnarray*}{
       *   \ell &= \cos(\delta) \sin(\alpha - \alpha_0) \\
       *      m &= \sin(\delta) \cos(\delta_0) - \cos(\delta) \sin(\delta_0)
       *                                         \cos(\alpha - \alpha_0)
       * \f}
       */
    
      const auto ra_view = ra.view();
      const auto dec_view = dec.view();
    
      const xt::xtensor<double, 1> delta_ra = ra_view - reference.ra;
      const xt::xtensor<double, 1> sin_delta_ra = xt::sin(delta_ra);
      const xt::xtensor<double, 1> cos_delta_ra = xt::cos(delta_ra);
      const xt::xtensor<double, 1> sin_dec = xt::sin(dec_view);
      const xt::xtensor<double, 1> cos_dec = xt::cos(dec_view);
      const double sin_dec0 = std::sin(reference.dec);
      const double cos_dec0 = std::cos(reference.dec);
    
      xt::view(lmn, xt::all(), 0) = cos_dec * sin_delta_ra;
      xt::view(lmn, xt::all(), 1) =
          sin_dec * cos_dec0 - cos_dec * sin_dec0 * cos_delta_ra;
      // Normally, n is calculated using n = std::sqrt(1.0 - l * l - m * m).
      // However the sign of n is lost that way, so a calculation is used that
      // avoids losing the sign. This formula can be found in Perley (1989).
      // Be aware that we asserted that the sign is wrong in Perley (1989),
      // so this is corrected.
      xt::view(lmn, xt::all(), 2) =
          sin_dec * sin_dec0 + cos_dec * cos_dec0 * cos_delta_ra;
    }
    
    template <>
    inline void Directions::RaDec2Lmn<Directions::computation_strategy::SINGLE>(
        const Direction &reference, xt::xtensor<double, 2> &lmn) const {
      /**
       * \f{eqnarray*}{
       *   \ell &= \cos(\delta) \sin(\alpha - \alpha_0) \\
       *      m &= \sin(\delta) \cos(\delta_0) - \cos(\delta) \sin(\delta_0)
       *                                         \cos(\alpha - \alpha_0)
       * \f}
       */
      for (size_t i = 0; i < ra.size(); i++) {
        const double delta_ra = ra[i] - reference.ra;
        const double sin_delta_ra = std::sin(delta_ra);
        const double cos_delta_ra = std::cos(delta_ra);
        const double sin_dec = std::sin(dec[i]);
        const double cos_dec = std::cos(dec[i]);
        const double sin_dec0 = std::sin(reference.dec);
        const double cos_dec0 = std::cos(reference.dec);
    
        lmn(i, 0) = cos_dec * sin_delta_ra;
        lmn(i, 1) = sin_dec * cos_dec0 - cos_dec * sin_dec0 * cos_delta_ra;
        // Normally, n is calculated using n = std::sqrt(1.0 - l * l - m * m).
        // However the sign of n is lost that way, so a calculation is used that
        // avoids losing the sign. This formula can be found in Perley (1989).
        // Be aware that we asserted that the sign is wrong in Perley (1989),
        // so this is corrected.
        lmn(i, 2) = sin_dec * sin_dec0 + cos_dec * cos_dec0 * cos_delta_ra;
      }
    }
    
    namespace xsimd {
    
    struct radec2lmn {
      template <class C, class Tag, class Arch>
      void operator()(Arch, const Direction &reference, const C &ra, const C &dec,
                      xt::xtensor<double, 2> &lmn, Tag);
    };
    
    template <class C, class Tag, class Arch>
    void radec2lmn::operator()(Arch, const Direction &reference, const C &ra,
                               const C &dec, xt::xtensor<double, 2> &lmn, Tag) {
      using b_type = xsimd::batch<double, Arch>;
      std::size_t inc = b_type::size;
      std::size_t size = ra.size();
      double sin_dec0 = std::sin(reference.dec);
      double cos_dec0 = std::cos(reference.dec);
      // size for which the vectorization is possible
      std::size_t vec_size = size - size % inc;
    
      for (std::size_t i = 0; i < vec_size; i += inc) {
        const b_type ra_vec = b_type::load(&ra[i], Tag());
        const b_type dec_vec = b_type::load(&dec[i], Tag());
    
        const b_type delta_ra = ra_vec - reference.ra;
    
        const std::pair<b_type, b_type> sin_cos_delta_ra = xsimd::sincos(delta_ra);
        const std::pair<b_type, b_type> sin_cos_dec = xsimd::sincos(dec_vec);
    
        const b_type &cos_dec = sin_cos_dec.second;
        const b_type &sin_dec = sin_cos_dec.first;
        const b_type &sin_delta_ra = sin_cos_delta_ra.first;
        const b_type &cos_delta_ra = sin_cos_delta_ra.second;
    
        const b_type result_vec_l = cos_dec * sin_delta_ra;
        const b_type result_vec_m =
            sin_dec * cos_dec0 - cos_dec * sin_dec0 * cos_delta_ra;
        const b_type result_vec_n =
            sin_dec * sin_dec0 + cos_dec * cos_dec0 * cos_delta_ra;
    
        xsimd::store(&lmn(0, i), result_vec_l, Tag());
        xsimd::store(&lmn(1, i), result_vec_m, Tag());
        xsimd::store(&lmn(2, i), result_vec_n, Tag());
      }
      // Remaining part that cannot be vectorize
      for (std::size_t i = vec_size; i < size; ++i) {
        double delta_ra = ra[i] - reference.ra;
        double sin_delta_ra = std::sin(delta_ra);
        double cos_delta_ra = std::cos(delta_ra);
        double sin_dec = std::sin(dec[i]);
        double cos_dec = std::cos(dec[i]);
    
        lmn(0, i) = cos_dec * sin_delta_ra;
        lmn(1, i) = sin_dec * cos_dec0 - cos_dec * sin_dec0 * cos_delta_ra;
        lmn(2, i) = sin_dec * sin_dec0 + cos_dec * cos_dec0 * cos_delta_ra;
      }
    }
    
    } // namespace xsimd
    
    template <>
    inline void Directions::RaDec2Lmn<Directions::computation_strategy::MULTI_SIMD>(
        const Direction &reference, xt::xtensor<double, 2> &lmn) const {
      xt::xtensor<double, 2> lmn_tmp;
      lmn_tmp.resize({3, ra.size()});
      xsimd::dispatch(xsimd::radec2lmn{})(reference, ra, dec, lmn_tmp,
                                          xsimd::unaligned_mode());
      lmn = xt::transpose(lmn_tmp);
    }
    #endif