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 : #pragma once 6 : #include <algorithm> 7 : 8 : #include "scipp/core/bucket_array_view.h" 9 : #include "scipp/core/dimensions.h" 10 : #include "scipp/core/eigen.h" 11 : #include "scipp/core/except.h" 12 : #include "scipp/variable/arithmetic.h" 13 : #include "scipp/variable/bins.h" 14 : #include "scipp/variable/cumulative.h" 15 : #include "scipp/variable/element_array_model.h" 16 : #include "scipp/variable/except.h" 17 : #include "scipp/variable/reduction.h" 18 : #include "scipp/variable/util.h" 19 : 20 : namespace scipp::variable { 21 : 22 : template <class Indices> class BinModelBase : public VariableConcept { 23 : public: 24 159193 : BinModelBase(const VariableConceptHandle &indices, const Dim dim) 25 159193 : : VariableConcept(units::none), m_indices(indices), m_dim(dim) {} 26 : 27 159190 : scipp::index size() const override { return indices()->size(); } 28 : 29 4 : void setUnit(const units::Unit &unit) override { 30 4 : if (unit != units::none) 31 4 : throw except::UnitError( 32 : "Bins cannot have a unit. Did you mean to set the unit of the bin " 33 : "elements? This can be set with `array.bins.unit = 'm'`."); 34 0 : } 35 : 36 100838 : bool has_variances() const noexcept override { return false; } 37 938260 : const Indices &bin_indices() const override { return indices(); } 38 : 39 1159422 : const auto &indices() const { return m_indices; } 40 : auto &indices() { return m_indices; } 41 977022 : Dim bin_dim() const noexcept { return m_dim; } 42 : 43 : private: 44 : Indices m_indices; 45 : Dim m_dim; 46 : }; 47 : 48 : /// Specialization of ElementArrayModel for "binned" data. T could be Variable, 49 : /// DataArray, or Dataset. 50 : /// 51 : /// A bin in this context is defined as an element of a variable mapping to a 52 : /// range of data, such as a slice of a DataArray. 53 : template <class T> 54 : class BinArrayModel : public BinModelBase<VariableConceptHandle> { 55 : using Indices = VariableConceptHandle; 56 : 57 : public: 58 : using value_type = bucket<T>; 59 : 60 : BinArrayModel(const VariableConceptHandle &indices, const Dim dim, T buffer); 61 : 62 : [[nodiscard]] VariableConceptHandle clone() const override; 63 : 64 : bool operator==(const BinArrayModel &other) const noexcept; 65 : 66 0 : bool operator!=(const BinArrayModel &other) const noexcept { 67 0 : return !(*this == other); 68 : } 69 : 70 : [[nodiscard]] VariableConceptHandle 71 : makeDefaultFromParent(const scipp::index size) const override; 72 : 73 : [[nodiscard]] VariableConceptHandle 74 : makeDefaultFromParent(const Variable &shape) const override; 75 : 76 1 : static DType static_dtype() noexcept { return scipp::dtype<bucket<T>>; } 77 2679379 : [[nodiscard]] DType dtype() const noexcept override { 78 2679379 : return scipp::dtype<bucket<T>>; 79 : } 80 : 81 : [[nodiscard]] bool equals(const Variable &a, 82 : const Variable &b) const override; 83 : [[nodiscard]] bool equals_nan(const Variable &a, 84 : const Variable &b) const override; 85 : void copy(const Variable &src, Variable &dest) const override; 86 : void copy(const Variable &src, Variable &&dest) const override; 87 : void assign(const VariableConcept &other) override; 88 : 89 : // TODO Should the mutable version return a view to prevent risk of clients 90 : // breaking invariants of variable? 91 1088170 : const T &buffer() const noexcept { return m_buffer; } 92 137055 : T &buffer() noexcept { return m_buffer; } 93 : 94 381 : ElementArrayView<bucket<T>> values(const core::ElementArrayViewParams &base) { 95 381 : return {index_values(base), this->bin_dim(), m_buffer}; 96 : } 97 : ElementArrayView<const bucket<T>> 98 61554 : values(const core::ElementArrayViewParams &base) const { 99 61554 : return {index_values(base), this->bin_dim(), m_buffer}; 100 : } 101 : 102 0 : [[nodiscard]] scipp::index dtype_size() const override { 103 0 : return sizeof(scipp::index_pair); 104 : } 105 98 : scipp::index object_size() const override { return sizeof(*this); } 106 : 107 0 : void setVariances(const Variable &) override { 108 0 : except::throw_cannot_have_variances(core::dtype<core::bin<T>>); 109 : } 110 : 111 : private: 112 : ElementArrayView<const scipp::index_pair> 113 : index_values(const core::ElementArrayViewParams &base) const; 114 : T m_buffer; 115 : }; 116 : 117 : template <class T> BinArrayModel<T> copy(const BinArrayModel<T> &model); 118 : 119 : template <class T> 120 25711 : bool BinArrayModel<T>::equals(const Variable &a, const Variable &b) const { 121 : // TODO This implementation is slow since it creates a view for every bucket. 122 51422 : return a.dtype() == dtype() && b.dtype() == dtype() && 123 51422 : equals_impl(a.values<bucket<T>>(), b.values<bucket<T>>()); 124 : } 125 : 126 : template <class T> 127 63 : bool BinArrayModel<T>::equals_nan(const Variable &a, const Variable &b) const { 128 : // TODO This implementation is slow since it creates a view for every bucket. 129 126 : return a.dtype() == dtype() && b.dtype() == dtype() && 130 126 : equals_nan_impl(a.values<bucket<T>>(), b.values<bucket<T>>()); 131 : } 132 : 133 : namespace { 134 : template <class T> 135 3361 : void copy_coord_alignment(const T &src_buffer, Variable &dest) { 136 3361 : auto &dest_buffer = dest.bin_buffer<T>(); 137 12318 : for (const auto &[key, var] : src_buffer.coords()) 138 8957 : dest_buffer.coords().set_aligned(key, var.is_aligned()); 139 3361 : } 140 : } // namespace 141 : 142 : template <class T> 143 17007 : void BinArrayModel<T>::copy(const Variable &src, Variable &dest) const { 144 : if constexpr (std::is_same_v<T, Variable>) { 145 13626 : copy_data(src, dest); 146 13621 : dest.set_aligned(src.is_aligned()); 147 : } else { 148 3381 : const auto &[indices0, dim0, buffer0] = src.constituents<T>(); 149 3381 : auto &&[indices1, dim1, buffer1] = dest.constituents<T>(); 150 : static_cast<void>(dim1); 151 3401 : copy_slices(buffer0, buffer1, dim0, indices0, indices1); 152 3361 : copy_coord_alignment(buffer0, dest); 153 3401 : } 154 16982 : } 155 : 156 : template <class T> 157 72 : void BinArrayModel<T>::copy(const Variable &src, Variable &&dest) const { 158 72 : copy(src, dest); 159 52 : } 160 : 161 : } // namespace scipp::variable