LCOV - code coverage report
Current view: top level - variable/include/scipp/variable - variable.tcc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 41 44 93.2 %
Date: 2024-04-28 01:25:40 Functions: 276 557 49.6 %

          Line data    Source code
       1             : // SPDX-License-Identifier: BSD-3-Clause
       2             : // Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
       3             : /// @file
       4             : /// @author Simon Heybrock
       5             : #include "scipp/core/array_to_string.h"
       6             : #include "scipp/core/dimensions.h"
       7             : #include "scipp/core/eigen.h"
       8             : #include "scipp/core/element_array_view.h"
       9             : #include "scipp/core/except.h"
      10             : #include "scipp/core/has_eval.h"
      11             : #include "scipp/units/unit.h"
      12             : #include "scipp/variable/element_array_model.h"
      13             : #include "scipp/variable/except.h"
      14             : #include "scipp/variable/variable.h"
      15             : #include "scipp/variable/variable_factory.h"
      16             : 
      17             : namespace scipp::variable {
      18             : 
      19             : template <class T> struct model {
      20             :   using type = ElementArrayModel<T>;
      21             : };
      22             : template <class T> using model_t = typename model<T>::type;
      23             : 
      24             : namespace {
      25             : 
      26    10271325 : template <class T, class C> auto &requireT(C &varconcept) {
      27    10271325 :   if (varconcept.dtype() != dtype<typename T::value_type>)
      28          32 :     throw except::TypeError("Expected item dtype " +
      29             :                             to_string(T::static_dtype()) + ", got " +
      30          16 :                             to_string(varconcept.dtype()) + '.');
      31    10271309 :   return static_cast<T &>(varconcept);
      32             : }
      33             : 
      34     4785264 : template <class T> const auto &cast(const Variable &var) {
      35     4785264 :   return requireT<const model_t<T>>(var.data());
      36             : }
      37             : 
      38     3094242 : template <class T> auto &cast(Variable &var) {
      39     3094242 :   return requireT<model_t<T>>(var.data());
      40             : }
      41             : 
      42          70 : template <int I, class T> decltype(auto) get(T &&t) {
      43             :   if constexpr (std::is_same_v<std::decay_t<T>, Eigen::Affine3d>) {
      44           9 :     return t.matrix().operator()(I);
      45             :   } else if constexpr (core::has_eval_v<std::decay_t<T>> ||
      46             :                        std::is_same_v<std::decay_t<T>,
      47             :                                       scipp::core::Quaternion> ||
      48             :                        std::is_same_v<std::decay_t<T>,
      49             :                                       scipp::core::Translation>) {
      50          61 :     return t.operator()(I);
      51             :   } else {
      52             :     return std::get<I>(t);
      53             :   }
      54             : }
      55             : 
      56             : template <class T>
      57      803697 : auto make_model(const units::Unit unit, const Dimensions &dimensions,
      58             :                 element_array<T> values,
      59             :                 std::optional<element_array<T>> variances) {
      60             :   if constexpr (std::is_same_v<model_t<T>, ElementArrayModel<T>>) {
      61             :     return std::make_unique<model_t<T>>(
      62     1565145 :         dimensions.volume(), unit, std::move(values), std::move(variances));
      63             :   } else {
      64             :     // There is an extra copy caused here, but in practice this constructor
      65             :     // should not be used much outside unit tests.
      66             :     using Elem = typename model_t<T>::element_type;
      67       21120 :     element_array<Elem> elems;
      68       21120 :     if (values) {
      69       21084 :       auto begin = static_cast<Elem *>(&get<0>(*values.begin()));
      70       21084 :       auto end = begin + model_t<T>::element_count * values.size();
      71       21084 :       elems = element_array<Elem>{begin, end};
      72             :     }
      73       21120 :     return std::make_unique<model_t<T>>(dimensions.volume(), unit,
      74       63360 :                                         std::move(elems));
      75       21120 :   }
      76             : }
      77             : 
      78             : /// See also default_unit_for, for similar runtime functionality.
      79             : template <class T>
      80      803697 : units::Unit unit_for_dtype(const std::optional<units::Unit> &unit) {
      81      803697 :   if (unit.has_value())
      82      644691 :     return *unit;
      83      159006 :   return default_unit_for(dtype<T>);
      84             : }
      85             : 
      86             : } // namespace
      87             : 
      88             : template <class T>
      89      803697 : Variable::Variable(const std::optional<units::Unit> &unit,
      90             :                    const Dimensions &dimensions, T values_,
      91             :                    std::optional<T> variances_)
      92      803697 :     : m_dims(dimensions), m_strides(dimensions),
      93     1607412 :       m_object(
      94             :           make_model(unit_for_dtype<typename std::decay_t<T>::value_type>(unit),
      95     2411100 :                      dimensions, std::move(values_), std::move(variances_))) {}
      96             : 
      97     4417514 : template <class T> ElementArrayView<const T> Variable::values() const {
      98     4417514 :   return cast<T>(*this).values(array_params());
      99             : }
     100     3039019 : template <class T> ElementArrayView<T> Variable::values() {
     101     3039019 :   return cast<T>(*this).values(array_params());
     102             : }
     103      318569 : template <class T> ElementArrayView<const T> Variable::variances() const {
     104             :   if constexpr (!core::canHaveVariances<T>())
     105           0 :     except::throw_cannot_have_variances(core::dtype<T>);
     106             :   else
     107      318569 :     return cast<T>(*this).variances(array_params());
     108             : }
     109       55223 : template <class T> ElementArrayView<T> Variable::variances() {
     110             :   if constexpr (!core::canHaveVariances<T>())
     111           0 :     except::throw_cannot_have_variances(core::dtype<T>);
     112             :   else
     113       55223 :     return cast<T>(*this).variances(array_params());
     114             : }
     115             : 
     116             : #define INSTANTIATE_VARIABLE_BASE(name, ...)                                   \
     117             :   namespace {                                                                  \
     118             :   auto register_dtype_name_##name(                                             \
     119             :       (core::dtypeNameRegistry().emplace(dtype<__VA_ARGS__>, #name), 0));      \
     120             :   }                                                                            \
     121             :   template SCIPP_EXPORT ElementArrayView<const __VA_ARGS__> Variable::values() \
     122             :       const;                                                                   \
     123             :   template SCIPP_EXPORT ElementArrayView<__VA_ARGS__> Variable::values();
     124             : 
     125           1 : template <class T> std::string Formatter<T>::format(const Variable &var) const {
     126           1 :   if (var.ndim() == 0)
     127           1 :     return core::scalar_array_to_string(var.template values<T>(), var.unit());
     128           0 :   return array_to_string(var.template values<T>());
     129             : }
     130             : 
     131             : /// Insert classes into formatting registry. The objects themselves do nothing,
     132             : /// but the constructor call with comma operator does the insertion. Calling
     133             : /// this is required for formatting all but basic builtin types.
     134             : #define REGISTER_FORMATTER(name, ...)                                          \
     135             :   namespace {                                                                  \
     136             :   auto register_##name(                                                        \
     137             :       (variable::formatterRegistry().emplace(                                  \
     138             :            dtype<__VA_ARGS__>,                                                 \
     139             :            std::make_unique<variable::Formatter<__VA_ARGS__>>()),              \
     140             :        0));                                                                    \
     141             :   }
     142             : 
     143             : } // namespace scipp::variable

Generated by: LCOV version 1.14