LCOV - code coverage report
Current view: top level - dataset - util.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 106 108 98.1 %
Date: 2024-11-24 01:48:31 Functions: 19 20 95.0 %

          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 Matthew Andrew
       5             : 
       6             : #include "scipp/dataset/util.h"
       7             : #include "scipp/common/overloaded.h"
       8             : #include "scipp/core/element/arg_list.h"
       9             : #include "scipp/dataset/sized_dict_forward.h"
      10             : #include "scipp/variable/accumulate.h"
      11             : #include "scipp/variable/reduction.h"
      12             : #include "scipp/variable/structure_array_model.h"
      13             : #include "scipp/variable/util.h"
      14             : #include "scipp/variable/variable.h"
      15             : #include "scipp/variable/variable_concept.h"
      16             : 
      17             : #include "dataset_operations_common.h"
      18             : 
      19             : using namespace scipp::variable;
      20             : namespace scipp {
      21             : 
      22             : namespace {
      23             : scipp::index
      24             : size_of_elements(const Variable &view, SizeofTag tag,
      25             :                  const std::optional<std::pair<Dim, double>> &scale_in_dim);
      26             : 
      27             : scipp::index
      28        1429 : size_of_impl(const Variable &var, const SizeofTag tag,
      29             :              const std::optional<std::pair<Dim, double>> &scale_in_dim) {
      30             :   const auto object_size =
      31        1429 :       static_cast<scipp::index>(sizeof(Variable)) + var.data().object_size();
      32        1429 :   return size_of_elements(var, tag, scale_in_dim) + object_size;
      33             : }
      34             : 
      35             : /// Return the size in memory of a DataArray object. The aligned coord is
      36             : /// optional because for a DataArray owned by a dataset aligned coords are
      37             : /// assumed to be owned by the dataset as they can apply to multiple arrays.
      38             : scipp::index
      39         306 : size_of_impl(const DataArray &da, const SizeofTag tag,
      40             :              const std::optional<std::pair<Dim, double>> &scale_in_dim,
      41             :              bool include_aligned_coords = true) {
      42             :   auto size = static_cast<scipp::index>(
      43             :       sizeof(DataArray) + sizeof(dataset::Coords) + sizeof(dataset::Attrs) +
      44         306 :       sizeof(dataset::Masks) + da.coords().capacity() + da.attrs().capacity() +
      45         306 :       da.masks().capacity());
      46         306 :   size += size_of_impl(da.data(), tag, scale_in_dim);
      47         318 :   for (const auto &coord : da.attrs()) {
      48          12 :     size += size_of_impl(coord.second, tag, scale_in_dim);
      49             :   }
      50         490 :   for (const auto &mask : da.masks()) {
      51         184 :     size += size_of_impl(mask.second, tag, scale_in_dim);
      52             :   }
      53         306 :   if (include_aligned_coords) {
      54         588 :     for (const auto &coord : da.coords()) {
      55         370 :       size += size_of_impl(coord.second, tag, scale_in_dim);
      56             :     }
      57             :   }
      58         306 :   return size;
      59             : }
      60             : 
      61             : scipp::index
      62          48 : size_of_impl(const Dataset &ds, const SizeofTag tag,
      63             :              const std::optional<std::pair<Dim, double>> &scale_in_dim) {
      64          48 :   auto size = static_cast<scipp::index>(sizeof(Dataset) + ds.capacity());
      65         136 :   for (const auto &data : ds) {
      66          88 :     size += size_of_impl(data, tag, scale_in_dim, false);
      67          88 :   }
      68          56 :   for (const auto &coord : ds.coords()) {
      69           8 :     size += size_of_impl(coord.second, tag, scale_in_dim);
      70             :   }
      71          48 :   return size;
      72             : }
      73             : 
      74             : struct SizeOfKernel {
      75             :   using types = std::tuple<std::tuple<scipp::index, std::string>,
      76             :                            std::tuple<scipp::index, scipp::index>>;
      77             : 
      78     1000076 :   void operator()(scipp::index &out, const std::string &str) {
      79     1000076 :     if (const auto str_address =
      80     1000076 :             reinterpret_cast<const char *>(std::addressof(str));
      81     1000143 :         str.data() > str_address &&
      82          67 :         str.data() + str.size() < str_address + sizeof(std::string)) {
      83             :       // Small string optimization: The characters are located
      84             :       // in the string's internal buffer.
      85          67 :       out += sizeof(std::string);
      86             :     } else {
      87             :       // A long string: The characters are in a separate
      88             :       // array on the heap.
      89     1000009 :       out += sizeof(std::string) + str.size();
      90             :     }
      91     1000076 :   }
      92          25 :   void operator()(scipp::index &out, const scipp::index &s) { out += s; }
      93             : };
      94             : 
      95             : struct SizeOfContainerKernel {
      96             :   using types = std::tuple<std::tuple<scipp::index, Variable>,
      97             :                            std::tuple<scipp::index, DataArray>,
      98             :                            std::tuple<scipp::index, Dataset>>;
      99             : 
     100             :   SizeofTag tag;
     101             : 
     102          15 :   template <class T> void operator()(scipp::index &out, const T &x) const {
     103          15 :     out += size_of(x, tag);
     104          15 :   }
     105             : };
     106             : 
     107             : template <class T>
     108          98 : scipp::index size_of_bins(const Variable &view, const SizeofTag tag) {
     109          98 :   const auto &[indices, dim, buffer] = view.constituents<T>();
     110          98 :   std::pair<Dim, double> scale_in_dim{Dim::Invalid, 1.0};
     111          98 :   if (tag == SizeofTag::ViewOnly) {
     112          49 :     const auto &[begin, end] = unzip(indices);
     113          49 :     const auto sizes = sum(end - begin).template value<scipp::index>();
     114             :     // avoid division by zero
     115          49 :     scale_in_dim.second =
     116          49 :         sizes == 0 ? 0.0 : sizes / static_cast<double>(buffer.dims()[dim]);
     117          49 :     scale_in_dim.first = dim;
     118          49 :   }
     119          98 :   const auto indices_volume = tag == SizeofTag::Underlying
     120          98 :                                   ? indices.data().size()
     121          49 :                                   : indices.dims().volume();
     122          98 :   return indices_volume * sizeof(scipp::index_pair) +
     123             :          sizeof(
     124          98 :              variable::StructureArrayModel<scipp::index_pair, scipp::index>) +
     125         196 :          size_of_impl(buffer, tag, scale_in_dim);
     126          98 : }
     127             : 
     128             : template <class Op>
     129          27 : auto accumulate_size_of(const Variable &view, const SizeofTag tag,
     130             :                         const Op &op) {
     131          27 :   auto size = makeVariable<scipp::index>(Shape{}, Values{0});
     132          27 :   if (tag == SizeofTag::Underlying) {
     133          28 :     const Variable full(core::Dimensions{Dim::X, view.data().size()},
     134          14 :                         view.data_handle());
     135          14 :     accumulate_in_place(size, full, op, "size_of");
     136          14 :   } else {
     137          13 :     accumulate_in_place(size, view, op, "size_of");
     138             :   }
     139          54 :   return size.value<scipp::index>();
     140          27 : }
     141             : 
     142             : scipp::index
     143        1429 : size_of_elements(const Variable &view, const SizeofTag tag,
     144             :                  const std::optional<std::pair<Dim, double>> &scale_in_dim) {
     145        1429 :   if (view.dtype() == dtype<bucket<Variable>>) {
     146          26 :     return size_of_bins<Variable>(view, tag);
     147             :   }
     148        1403 :   if (view.dtype() == dtype<bucket<DataArray>>) {
     149          68 :     return size_of_bins<DataArray>(view, tag);
     150             :   }
     151        1335 :   if (view.dtype() == dtype<bucket<Dataset>>) {
     152           4 :     return size_of_bins<Dataset>(view, tag);
     153             :   }
     154        1331 :   if (view.dtype() == dtype<std::string>) {
     155          16 :     return accumulate_size_of(view, tag, SizeOfKernel{});
     156             :   }
     157        2619 :   if (view.dtype() == dtype<Variable> || view.dtype() == dtype<DataArray> ||
     158        2619 :       view.dtype() == dtype<Dataset>) {
     159          11 :     return accumulate_size_of(view, tag, SizeOfContainerKernel{tag});
     160             :   }
     161             : 
     162        1304 :   const auto value_size = view.data().dtype_size();
     163        1304 :   const auto variance_scale = view.has_variances() ? 2 : 1;
     164             :   const auto data_size =
     165        1304 :       tag == SizeofTag::Underlying ? view.data().size() : view.dims().volume();
     166             :   const auto extra_scale =
     167        1758 :       scale_in_dim.has_value() && view.dims().contains(scale_in_dim->first)
     168        1758 :           ? scale_in_dim->second
     169        1304 :           : 1.0;
     170             :   return static_cast<scipp::index>(
     171        1304 :       static_cast<double>(data_size * value_size * variance_scale) *
     172        1304 :       extra_scale);
     173             : }
     174             : } // namespace
     175             : 
     176         523 : scipp::index size_of(const Variable &var, const SizeofTag tag) {
     177         523 :   return size_of_impl(var, tag, std::nullopt);
     178             : }
     179         150 : scipp::index size_of(const DataArray &da, const SizeofTag tag,
     180             :                      const bool include_aligned_coords) {
     181         150 :   return size_of_impl(da, tag, std::nullopt, include_aligned_coords);
     182             : }
     183          44 : scipp::index size_of(const Dataset &ds, const SizeofTag tag) {
     184          44 :   return size_of_impl(ds, tag, std::nullopt);
     185             : }
     186             : } // namespace scipp
     187             : 
     188             : namespace scipp::dataset {
     189         163 : DataArray strip_edges_along(const DataArray &da, const Dim dim) {
     190         163 :   auto out = da;
     191         396 :   for (const auto &[name, var] : da.coords())
     192         233 :     if (core::is_edges(da.dims(), var.dims(), dim))
     193           3 :       out.coords().erase(name);
     194         243 :   for (const auto &[name, var] : da.masks())
     195          80 :     if (core::is_edges(da.dims(), var.dims(), dim))
     196           2 :       out.masks().erase(name);
     197         165 :   for (const auto &[name, var] : da.attrs())
     198           2 :     if (core::is_edges(da.dims(), var.dims(), dim))
     199           2 :       out.attrs().erase(name);
     200         163 :   return out;
     201           0 : }
     202             : 
     203          28 : Dataset strip_edges_along(const Dataset &ds, const Dim dim) {
     204             :   auto out = apply_to_items(
     205          64 :       ds, [](auto &&...args) { return strip_edges_along(args...); }, dim);
     206          84 :   for (const auto &[name, var] : ds.coords())
     207          56 :     if (!core::is_edges(ds.sizes(), var.dims(), dim))
     208          55 :       out.setCoord(name, var);
     209          28 :   return out;
     210           0 : }
     211             : 
     212             : } // namespace scipp::dataset

Generated by: LCOV version 1.14