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/dataset/data_array.h"
6 : #include "scipp/dataset/dataset_util.h"
7 : #include "scipp/variable/misc_operations.h"
8 :
9 : #include "dataset_operations_common.h"
10 :
11 : namespace scipp::dataset {
12 :
13 : namespace {
14 229 : template <class T> void expect_writable(const T &dict) {
15 229 : if (dict.is_readonly())
16 4 : throw except::DataArrayError("Read-only flag is set, cannot set new data.");
17 225 : }
18 :
19 1007192 : template <class T> auto copy_shared(const std::shared_ptr<T> &obj) {
20 1007192 : return obj ? std::make_shared<T>(*obj) : obj;
21 : }
22 : } // namespace
23 :
24 251798 : DataArray::DataArray(const DataArray &other, const AttrPolicy attrPolicy)
25 251798 : : m_name(other.m_name), m_data(copy_shared(other.m_data)),
26 251798 : m_coords(copy_shared(other.m_coords)),
27 251798 : m_masks(copy_shared(other.m_masks)),
28 251798 : m_attrs(attrPolicy == AttrPolicy::Keep ? copy_shared(other.m_attrs)
29 : : std::make_shared<Attrs>()),
30 251798 : m_readonly(false) {}
31 :
32 251798 : DataArray::DataArray(const DataArray &other)
33 251798 : : DataArray(other, AttrPolicy::Keep) {}
34 :
35 19291 : DataArray::DataArray(Variable data, Coords coords, Masks masks, Attrs attrs,
36 19291 : const std::string_view name)
37 19291 : : m_name(name), m_data(std::make_shared<Variable>(std::move(data))),
38 19291 : m_coords(std::make_shared<Coords>(std::move(coords))),
39 19291 : m_masks(std::make_shared<Masks>(std::move(masks))),
40 19291 : m_attrs(std::make_shared<Attrs>(std::move(attrs))) {
41 19291 : const Sizes sizes(dims());
42 19291 : m_coords->setSizes(sizes);
43 19291 : m_masks->setSizes(sizes);
44 19291 : m_attrs->setSizes(sizes);
45 19291 : }
46 :
47 139944 : DataArray::DataArray(Variable data, typename Coords::holder_type coords,
48 : typename Masks::holder_type masks,
49 : typename Attrs::holder_type attrs,
50 139944 : const std::string_view name)
51 139944 : : m_name(name), m_data(std::make_shared<Variable>(std::move(data))),
52 139944 : m_coords(std::make_shared<Coords>(dims(), std::move(coords))),
53 139941 : m_masks(std::make_shared<Masks>(dims(), std::move(masks))),
54 139949 : m_attrs(std::make_shared<Attrs>(dims(), std::move(attrs))) {}
55 :
56 67 : DataArray &DataArray::operator=(const DataArray &other) {
57 67 : if (this == &other) {
58 8 : return *this;
59 : }
60 59 : check_nested_in_assign(*this, other);
61 55 : return *this = DataArray(other);
62 : }
63 :
64 48350 : DataArray &DataArray::operator=(DataArray &&other) {
65 48350 : if (this == &other) {
66 0 : return *this;
67 : }
68 48350 : check_nested_in_assign(*this, other);
69 48350 : m_name = std::move(other.m_name);
70 48350 : m_data = std::move(other.m_data);
71 48350 : m_coords = std::move(other.m_coords);
72 48350 : m_masks = std::move(other.m_masks);
73 48350 : m_attrs = std::move(other.m_attrs);
74 48350 : m_readonly = other.m_readonly;
75 48350 : return *this;
76 : }
77 :
78 484 : void DataArray::setData(const Variable &data) {
79 : // Return early on self assign to avoid exceptions from Python inplace ops
80 484 : if (m_data->is_same(data))
81 255 : return;
82 229 : expect_writable(*this);
83 677 : core::expect::equals(static_cast<Sizes>(dims()),
84 451 : static_cast<Sizes>(data.dims()));
85 224 : *m_data = data;
86 : }
87 :
88 : /// Return true if the dataset proxies have identical content.
89 5930 : bool operator==(const DataArray &a, const DataArray &b) {
90 5930 : if (a.has_variances() != b.has_variances())
91 20 : return false;
92 5910 : if (a.coords() != b.coords())
93 102 : return false;
94 5808 : if (a.masks() != b.masks())
95 44 : return false;
96 5764 : if (a.attrs() != b.attrs())
97 54 : return false;
98 5710 : return a.data() == b.data();
99 : }
100 :
101 1059 : bool operator!=(const DataArray &a, const DataArray &b) {
102 1059 : return !operator==(a, b);
103 : }
104 :
105 325 : bool equals_nan(const DataArray &a, const DataArray &b) {
106 325 : if (!equals_nan(a.coords(), b.coords()))
107 34 : return false;
108 291 : if (!equals_nan(a.masks(), b.masks()))
109 14 : return false;
110 277 : if (!equals_nan(a.attrs(), b.attrs()))
111 16 : return false;
112 261 : return equals_nan(a.data(), b.data());
113 : }
114 :
115 : /// Return the name of the data array.
116 : ///
117 : /// If part of a dataset, the name of the array is equal to the key of this item
118 : /// in the dataset. Note that comparison operations ignore the name.
119 75781 : const std::string &DataArray::name() const { return m_name; }
120 :
121 21 : void DataArray::setName(const std::string_view name) { m_name = name; }
122 :
123 48482 : Coords DataArray::meta() const {
124 48482 : auto out = attrs().merge_from(coords());
125 48481 : out.set_readonly();
126 48481 : return out;
127 : }
128 :
129 9196 : DataArray DataArray::slice(const Slice &s) const {
130 18291 : auto out = DataArray{m_data->slice(s), m_coords->slice_coords(s),
131 18190 : m_masks->slice(s), m_attrs->slice(s), m_name};
132 9095 : out.m_readonly = true;
133 9095 : return out;
134 : }
135 :
136 18 : void DataArray::validateSlice(const Slice &s, const DataArray &array) const {
137 18 : expect::coords_are_superset(slice(s), array, "");
138 18 : data().validateSlice(s, array.data());
139 18 : masks().validateSlice(s, array.masks());
140 15 : }
141 :
142 45 : DataArray &DataArray::setSlice(const Slice &s, const DataArray &array) {
143 : // validateSlice, but not masks as otherwise repeated
144 47 : expect::coords_are_superset(slice(s), array, "");
145 43 : data().validateSlice(s, array.data());
146 : // Apply changes
147 40 : masks().setSlice(s, array.masks());
148 36 : return setSlice(s, array.data());
149 : }
150 :
151 44 : DataArray &DataArray::setSlice(const Slice &s, const Variable &var) {
152 44 : data().setSlice(s, var);
153 43 : return *this;
154 : }
155 :
156 1 : DataArray DataArray::view() const {
157 1 : DataArray out;
158 1 : out.m_data = m_data; // share data
159 1 : out.m_coords = m_coords; // share coords
160 1 : out.m_masks = m_masks; // share masks
161 1 : out.m_attrs = m_attrs; // share attrs
162 1 : out.m_name = m_name;
163 1 : return out;
164 0 : }
165 :
166 7519 : DataArray DataArray::view_with_coords(const Coords &coords,
167 : const std::string &name,
168 : const bool readonly) const {
169 7519 : DataArray out;
170 7519 : out.m_data = m_data; // share data
171 7519 : const Sizes sizes(dims());
172 7519 : typename Coords::holder_type selected;
173 28414 : for (const auto &[dim, coord] : coords)
174 20895 : if (coords.item_applies_to(dim, dims()))
175 20779 : selected.insert_or_assign(dim, coord.as_const());
176 7519 : const bool readonly_coords = true;
177 : out.m_coords =
178 7519 : std::make_shared<Coords>(sizes, std::move(selected), readonly_coords);
179 7519 : out.m_masks = m_masks; // share masks
180 7519 : out.m_attrs = m_attrs; // share attrs
181 7519 : out.m_name = name;
182 7519 : out.m_readonly = readonly;
183 15038 : return out;
184 7519 : }
185 :
186 : DataArray
187 252 : DataArray::drop_coords(const scipp::span<const Dim> coord_names) const {
188 252 : DataArray result = *this;
189 529 : for (const auto &name : coord_names)
190 277 : result.coords().erase(name);
191 252 : return result;
192 0 : }
193 :
194 : DataArray
195 9 : DataArray::drop_masks(const scipp::span<const std::string> mask_names) const {
196 9 : DataArray result = *this;
197 22 : for (const auto &name : mask_names)
198 13 : result.masks().erase(name);
199 9 : return result;
200 0 : }
201 :
202 8 : DataArray DataArray::drop_attrs(const scipp::span<const Dim> attr_names) const {
203 8 : DataArray result = *this;
204 20 : for (const auto &name : attr_names)
205 12 : result.attrs().erase(name);
206 8 : return result;
207 0 : }
208 :
209 286 : DataArray DataArray::rename_dims(const std::vector<std::pair<Dim, Dim>> &names,
210 : const bool fail_on_unknown) const {
211 563 : return DataArray(m_data->rename_dims(names, fail_on_unknown),
212 567 : m_coords->rename_dims(names, false),
213 571 : m_masks->rename_dims(names, false),
214 854 : m_attrs->rename_dims(names, false));
215 : }
216 :
217 2 : DataArray DataArray::as_const() const {
218 4 : auto out = DataArray(data().as_const(), coords().as_const(),
219 6 : masks().as_const(), attrs().as_const(), name());
220 2 : out.m_readonly = true;
221 2 : return out;
222 : }
223 :
224 230 : bool DataArray::is_readonly() const noexcept { return m_readonly; }
225 :
226 : } // namespace scipp::dataset
|