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/variable/element_array_model.h"
6 : #include "scipp/variable/variable.tcc"
7 :
8 : namespace scipp::variable {
9 :
10 : template <class T>
11 1642272 : Variable make_default_init(const Dimensions &dims, const units::Unit &unit,
12 : const bool variances) {
13 1642272 : if (variances && !core::canHaveVariances<T>())
14 0 : throw except::VariancesError("This data type cannot have variances.");
15 1642272 : const auto volume = dims.volume();
16 1642272 : VariableConceptHandle model;
17 : if constexpr (std::is_same_v<model_t<T>, ElementArrayModel<T>>) {
18 1351904 : if (variances)
19 27755 : model = std::make_shared<model_t<T>>(
20 55510 : volume, unit, element_array<T>(volume, core::init_for_overwrite),
21 55510 : element_array<T>(volume, core::init_for_overwrite));
22 : else
23 1324149 : model = std::make_shared<model_t<T>>(
24 2648298 : volume, unit, element_array<T>(volume, core::init_for_overwrite));
25 : } else {
26 : using Elem = typename model_t<T>::element_type;
27 290368 : model = std::make_shared<model_t<T>>(
28 : volume, unit,
29 580736 : element_array<Elem>(model_t<T>::element_count * volume,
30 : core::init_for_overwrite));
31 : }
32 3284544 : return Variable(dims, std::move(model));
33 1642272 : }
34 :
35 : template <class T> class VariableMaker : public AbstractVariableMaker {
36 : using AbstractVariableMaker::create;
37 13358274 : bool is_bins() const override { return false; }
38 1642272 : Variable create(const DType, const Dimensions &dims, const units::Unit &unit,
39 : const bool variances, const parent_list &) const override {
40 1642272 : return make_default_init<T>(dims, unit, variances);
41 : }
42 0 : Dim elem_dim(const Variable &) const override { return Dim::Invalid; }
43 11051677 : DType elem_dtype(const Variable &var) const override { return var.dtype(); }
44 3076630 : units::Unit elem_unit(const Variable &var) const override {
45 3076630 : return var.unit();
46 : }
47 463808 : void expect_can_set_elem_unit(const Variable &var,
48 : const units::Unit &u) const override {
49 463808 : var.expect_can_set_unit(u);
50 463801 : }
51 463854 : void set_elem_unit(Variable &var, const units::Unit &u) const override {
52 463854 : var.setUnit(u);
53 463854 : }
54 6582448 : bool has_variances(const Variable &var) const override {
55 6582448 : return var.has_variances();
56 : }
57 281498 : Variable empty_like(const Variable &prototype,
58 : const std::optional<Dimensions> &shape,
59 : const Variable &sizes) const override {
60 281498 : if (sizes.is_valid())
61 15 : throw except::TypeError(
62 : "Cannot specify sizes in `empty_like` for non-bin prototype.");
63 281483 : return create(prototype.dtype(), shape ? *shape : prototype.dims(),
64 562966 : prototype.unit(), prototype.has_variances(), {});
65 : }
66 : };
67 :
68 : template <class T>
69 2488111 : ElementArrayModel<T>::ElementArrayModel(
70 : const scipp::index size, const units::Unit &unit, element_array<T> model,
71 : std::optional<element_array<T>> variances)
72 : : VariableConcept(unit),
73 2488163 : m_values(model ? std::move(model)
74 29274 : : element_array<T>(size, default_init<T>::value())),
75 4976222 : m_variances(std::move(variances)) {
76 2488111 : if (m_variances)
77 37486 : core::expect::canHaveVariances<T>();
78 2488106 : if (size != scipp::size(m_values))
79 4 : throw except::DimensionError("Creating Variable: data size does not match "
80 : "volume given by dimension extents.");
81 2488102 : if (m_variances && !*m_variances)
82 8277 : *m_variances = element_array<T>(size, default_init<T>::value());
83 2488129 : }
84 :
85 1 : template <class T> VariableConceptHandle ElementArrayModel<T>::clone() const {
86 1 : return std::make_shared<ElementArrayModel<T>>(*this);
87 : }
88 :
89 : template <class T>
90 : VariableConceptHandle
91 26538 : ElementArrayModel<T>::makeDefaultFromParent(const scipp::index size) const {
92 26538 : if (has_variances())
93 : return std::make_shared<ElementArrayModel<T>>(
94 35 : size, unit(), element_array<T>(size), element_array<T>(size));
95 : else
96 26503 : return std::make_shared<ElementArrayModel<T>>(size, unit(),
97 26503 : element_array<T>(size));
98 : }
99 :
100 : /// Helper for implementing Variable::operator==.
101 : ///
102 : /// This method is using virtual dispatch as a trick to obtain T, such that
103 : /// values<T> and variances<T> can be compared.
104 : template <class T>
105 382208 : bool ElementArrayModel<T>::equals(const Variable &a, const Variable &b) const {
106 1146228 : return equals_impl(a.values<T>(), b.values<T>()) &&
107 381812 : (!a.has_variances() ||
108 906193 : equals_impl(a.variances<T>(), b.variances<T>()));
109 : }
110 :
111 : /// Helper for implementing Variable::operator==.
112 : ///
113 : /// This method is using virtual dispatch as a trick to obtain T, such that
114 : /// values<T> and variances<T> can be compared.
115 : template <class T>
116 2041 : bool ElementArrayModel<T>::equals_nan(const Variable &a,
117 : const Variable &b) const {
118 5990 : return equals_nan_impl(a.values<T>(), b.values<T>()) &&
119 1908 : (!a.has_variances() ||
120 4203 : equals_nan_impl(a.variances<T>(), b.variances<T>()));
121 : }
122 :
123 : template <class T>
124 0 : void ElementArrayModel<T>::assign(const VariableConcept &other) {
125 0 : *this = requireT<const ElementArrayModel<T>>(other);
126 0 : }
127 :
128 : template <class T>
129 3545 : void ElementArrayModel<T>::setVariances(const Variable &variances) {
130 3545 : if (!variances.is_valid())
131 29 : return m_variances.reset();
132 3516 : if (!core::canHaveVariances<T>())
133 1 : throw except::VariancesError("This data type cannot have variances.");
134 : // TODO Could move if refcount is 1?
135 3515 : if (variances.has_variances())
136 2 : throw except::VariancesError(
137 : "Cannot set variances from variable with variances.");
138 7024 : m_variances.emplace(
139 3513 : requireT<const ElementArrayModel>(variances.data()).m_values);
140 : }
141 :
142 : #define INSTANTIATE_ELEMENT_ARRAY_VARIABLE_BASE(name, ...) \
143 : template SCIPP_EXPORT Variable variable::make_default_init<__VA_ARGS__>( \
144 : const Dimensions &, const units::Unit &, const bool); \
145 : INSTANTIATE_VARIABLE_BASE(name, __VA_ARGS__) \
146 : namespace { \
147 : auto register_variable_maker_##name(( \
148 : variableFactory().emplace( \
149 : dtype<__VA_ARGS__>, std::make_unique<VariableMaker<__VA_ARGS__>>()), \
150 : 0)); \
151 : } \
152 : template SCIPP_EXPORT Variable::Variable( \
153 : const std::optional<units::Unit> &, const Dimensions &, \
154 : element_array<__VA_ARGS__>, std::optional<element_array<__VA_ARGS__>>); \
155 : template SCIPP_EXPORT ElementArrayView<const __VA_ARGS__> \
156 : Variable::variances() const; \
157 : template SCIPP_EXPORT ElementArrayView<__VA_ARGS__> Variable::variances();
158 :
159 : /// Macro for instantiating classes and functions required for support a new
160 : /// dtype in Variable.
161 : #define INSTANTIATE_ELEMENT_ARRAY_VARIABLE(name, ...) \
162 : template class SCIPP_EXPORT ElementArrayModel<__VA_ARGS__>; \
163 : INSTANTIATE_ELEMENT_ARRAY_VARIABLE_BASE(name, __VA_ARGS__)
164 :
165 : } // namespace scipp::variable
|