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 :
7 : #include "scipp/common/numeric.h"
8 : #include "scipp/common/overloaded.h"
9 :
10 : #include "scipp/units/unit.h"
11 :
12 : #include "scipp/core/element/arg_list.h"
13 : #include "scipp/core/histogram.h"
14 : #include "scipp/core/time_point.h"
15 : #include "scipp/core/transform_common.h"
16 : #include "scipp/core/value_and_variance.h"
17 :
18 : namespace scipp::core::element::event {
19 :
20 829 : constexpr auto get = [](const auto &x, const scipp::index i) {
21 : if constexpr (is_ValueAndVariance_v<std::decay_t<decltype(x)>>)
22 0 : return ValueAndVariance{x.value[i], x.variance[i]};
23 : else
24 829 : return x[i];
25 : };
26 :
27 : namespace map_detail {
28 : template <class Coord, class Edge, class Weight>
29 : using args = std::tuple<Coord, scipp::span<const Edge>,
30 : scipp::span<const Weight>, Weight>;
31 : } // namespace map_detail
32 :
33 : constexpr auto map = overloaded{
34 : element::arg_list<map_detail::args<int64_t, int64_t, double>,
35 : map_detail::args<int64_t, int64_t, float>,
36 : map_detail::args<int64_t, int64_t, int64_t>,
37 : map_detail::args<int64_t, int64_t, int32_t>,
38 : map_detail::args<int64_t, int64_t, bool>,
39 : map_detail::args<int32_t, int32_t, double>,
40 : map_detail::args<int32_t, int32_t, float>,
41 : map_detail::args<int32_t, int32_t, int64_t>,
42 : map_detail::args<int32_t, int32_t, int32_t>,
43 : map_detail::args<int32_t, int32_t, bool>,
44 : map_detail::args<int64_t, double, double>,
45 : map_detail::args<int64_t, double, float>,
46 : map_detail::args<int64_t, double, int64_t>,
47 : map_detail::args<int64_t, double, int32_t>,
48 : map_detail::args<int64_t, double, bool>,
49 : map_detail::args<int32_t, double, double>,
50 : map_detail::args<int32_t, double, float>,
51 : map_detail::args<int32_t, double, int64_t>,
52 : map_detail::args<int32_t, double, int32_t>,
53 : map_detail::args<int32_t, double, bool>,
54 : map_detail::args<time_point, time_point, double>,
55 : map_detail::args<time_point, time_point, float>,
56 : map_detail::args<time_point, time_point, int64_t>,
57 : map_detail::args<time_point, time_point, int32_t>,
58 : map_detail::args<time_point, time_point, bool>,
59 : map_detail::args<double, double, double>,
60 : map_detail::args<double, double, float>,
61 : map_detail::args<double, double, int64_t>,
62 : map_detail::args<double, double, int32_t>,
63 : map_detail::args<double, double, bool>,
64 : map_detail::args<float, double, double>,
65 : map_detail::args<float, double, float>,
66 : map_detail::args<float, double, int64_t>,
67 : map_detail::args<float, double, int32_t>,
68 : map_detail::args<float, double, bool>,
69 : map_detail::args<float, float, float>,
70 : map_detail::args<float, float, int64_t>,
71 : map_detail::args<float, float, int32_t>,
72 : map_detail::args<float, float, bool>,
73 : map_detail::args<double, float, double>,
74 : map_detail::args<double, float, float>,
75 : map_detail::args<double, float, int64_t>,
76 : map_detail::args<double, float, int32_t>,
77 : map_detail::args<double, float, bool>>,
78 : transform_flags::expect_no_variance_arg<0>,
79 : transform_flags::expect_no_variance_arg<1>,
80 164 : [](const units::Unit &x, const units::Unit &edges,
81 : const units::Unit &weights, const units::Unit &fill) {
82 164 : expect::equals(x, edges);
83 164 : expect::equals(weights, fill);
84 164 : return weights;
85 : }};
86 :
87 : constexpr auto map_linspace =
88 244 : overloaded{map, [](const auto &coord, const auto &edges,
89 : const auto &weights, const auto &fill) {
90 244 : const auto params = linear_edge_params(edges);
91 244 : const auto bin = get_bin<scipp::index>(coord, edges, params);
92 244 : return bin < 0 ? fill : get(weights, bin);
93 : }};
94 :
95 : constexpr auto map_sorted_edges =
96 88 : overloaded{map, [](const auto &coord, const auto &edges,
97 : const auto &weights, const auto &fill) {
98 88 : auto it = std::upper_bound(edges.begin(), edges.end(), coord);
99 173 : return (it == edges.end() || it == edges.begin())
100 88 : ? fill
101 88 : : get(weights, --it - edges.begin());
102 : }};
103 :
104 : constexpr auto lookup_previous =
105 210 : overloaded{map, [](const auto &point, const auto &x, const auto &weights,
106 : const auto &fill) {
107 210 : auto it = std::upper_bound(x.begin(), x.end(), point);
108 210 : return it == x.begin() ? fill : get(weights, --it - x.begin());
109 : }};
110 :
111 : namespace map_and_mul_detail {
112 : template <class Data, class Coord, class Edge, class Weight>
113 : using args =
114 : std::tuple<Data, Coord, scipp::span<const Edge>, scipp::span<const Weight>>;
115 : } // namespace map_and_mul_detail
116 :
117 : constexpr auto map_and_mul = overloaded{
118 : element::arg_list<
119 : map_and_mul_detail::args<double, double, double, double>,
120 : map_and_mul_detail::args<double, double, double, float>,
121 : map_and_mul_detail::args<float, double, double, double>,
122 : map_and_mul_detail::args<float, double, double, float>,
123 : map_and_mul_detail::args<double, float, float, double>,
124 : map_and_mul_detail::args<double, time_point, time_point, double>,
125 : map_and_mul_detail::args<double, time_point, time_point, float>,
126 : map_and_mul_detail::args<float, time_point, time_point, double>,
127 : map_and_mul_detail::args<float, time_point, time_point, float>>,
128 : transform_flags::expect_no_variance_arg<1>,
129 : transform_flags::expect_no_variance_arg<2>,
130 : transform_flags::expect_no_variance_arg<3>, // caught in transform anyway,
131 : // but adding this should save
132 : // binary size and compile time
133 117 : [](units::Unit &data, const units::Unit &x, const units::Unit &edges,
134 : const units::Unit &weights) {
135 117 : expect::equals(x, edges);
136 117 : data *= weights;
137 117 : }};
138 :
139 : constexpr auto map_and_mul_linspace = overloaded{
140 : map_and_mul,
141 325 : [](auto &data, const auto x, const auto &edges, const auto &weights) {
142 325 : const auto params = linear_edge_params(edges);
143 325 : if (const auto bin = get_bin<scipp::index>(x, edges, params); bin < 0)
144 7 : data *= 0.0;
145 : else
146 318 : data *= get(weights, bin);
147 325 : }};
148 :
149 : constexpr auto map_and_mul_sorted_edges =
150 12 : overloaded{map_and_mul, [](auto &data, const auto x, const auto &edges,
151 : const auto &weights) {
152 12 : auto it = std::upper_bound(edges.begin(), edges.end(), x);
153 12 : if (it == edges.end() || it == edges.begin())
154 0 : data *= 0.0;
155 : else
156 12 : data *= get(weights, --it - edges.begin());
157 12 : }};
158 :
159 : } // namespace scipp::core::element::event
|