ATLAS Offline Software
Loading...
Searching...
No Matches
SoACopy.icc
Go to the documentation of this file.
1// Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2#ifndef ATHDEVICEUTILS_SOACOPY_ICC
3#define ATHDEVICEUTILS_SOACOPY_ICC
4
5// Local include(s).
6#include "AthDeviceUtils/details/AccessorTuple.h"
7#include "AthDeviceUtils/details/getData.h"
8
9namespace AthDevice {
10namespace Details {
11
12template <std::size_t INDEX, Concepts::SoAColumn... COLUMNS,
13 typename... VARTYPES, typename ACCESSOR_TUPLE>
14vecmem::copy::event_type copyColumn(
15 const SG::AuxVectorBase& input,
16 vecmem::edm::view<vecmem::edm::schema<VARTYPES...>>& output,
17 const vecmem::copy& copy, const ACCESSOR_TUPLE& accessors) {
18
19 static_assert(INDEX < sizeof...(COLUMNS),
20 "Index out of bounds in copyColumn.");
21 static_assert(
22 ((vecmem::edm::type::details::is_jagged_vector_v<
23 std::tuple_element_t<INDEX, std::tuple<VARTYPES...>>> == false) &&
24 (vecmem::edm::type::details::is_scalar_v<
25 std::tuple_element_t<INDEX, std::tuple<VARTYPES...>>> == false)),
26 "Only 1D vectors are currently supported");
27
28 const auto& acc = std::get<INDEX>(accessors);
29 constexpr std::size_t index =
30 std::tuple_element_t<INDEX, std::tuple<COLUMNS...>>::index;
31 if constexpr (INDEX + 1 < sizeof...(COLUMNS)) {
32 copy(getData(acc.getDataSpan(input)), output.template get<index>())
33 ->ignore();
34 return copyColumn<INDEX + 1, COLUMNS...>(input, output, copy, accessors);
35 } else {
36 return copy(getData(acc.getDataSpan(input)), output.template get<index>());
37 }
38}
39
40template <std::size_t INDEX, Concepts::SoAColumn... COLUMNS,
41 typename... VARTYPES, typename ACCESSOR_TUPLE>
42vecmem::copy::event_type copyColumn(
43 const vecmem::edm::view<vecmem::edm::schema<VARTYPES...>>& input,
44 SG::AuxVectorBase& output, const vecmem::copy& copy,
45 const ACCESSOR_TUPLE& accessors) {
46
47 static_assert(INDEX < sizeof...(COLUMNS),
48 "Index out of bounds in copyColumn.");
49 static_assert(
50 ((vecmem::edm::type::details::is_jagged_vector_v<
51 std::tuple_element_t<INDEX, std::tuple<VARTYPES...>>> == false) &&
52 (vecmem::edm::type::details::is_scalar_v<
53 std::tuple_element_t<INDEX, std::tuple<VARTYPES...>>> == false)),
54 "Only 1D vectors are currently supported");
55
56 const auto& acc = std::get<INDEX>(accessors);
57 constexpr std::size_t index =
58 std::tuple_element_t<INDEX, std::tuple<COLUMNS...>>::index;
59 if constexpr (INDEX + 1 < sizeof...(COLUMNS)) {
60 copy(input.template get<index>(), getData(acc.getDataSpan(output)))
61 ->ignore();
62 return copyColumn<INDEX + 1, COLUMNS...>(input, output, copy, accessors);
63 } else {
64 return copy(input.template get<index>(), getData(acc.getDataSpan(output)));
65 }
66}
67
68} // namespace Details
69
70template <Concepts::SoAColumn... COLUMNS>
71SoACopy<COLUMNS...>::SoACopy(COLUMNS... columns)
72 : SoACopy(std::make_tuple(columns...)) {}
73
74template <Concepts::SoAColumn... COLUMNS>
75SoACopy<COLUMNS...>::SoACopy(const std::tuple<COLUMNS...>& columns)
76 : m_columns(columns) {}
77
78template <Concepts::SoAColumn... COLUMNS>
79template <typename SCHEMA>
80void SoACopy<COLUMNS...>::operator()(const SG::AuxVectorBase& input,
81 vecmem::edm::view<SCHEMA>& output,
82 const EventContext& ctx,
83 const IMemoryResourcesTool& mrs,
84 const ICopiesTool& copies) const {
85
86 static const auto accessors =
87 Details::AccessorTuple<SCHEMA>::get_const(m_columns);
88 static_assert(
89 std::tuple_size_v<decltype(accessors)> == sizeof...(COLUMNS),
90 "Number of accessors does not match number of column definitions.");
91
92 // If we have a separate "main" and "host" memory resource, then we first
93 // create a host-resident VecMem buffer with the appropriate data. Then we
94 // copy the host-resident buffer to the container passed to this function.
95 // (Which should be a device-resident buffer.)
96 if (mrs.hostMR() != nullptr) {
97 vecmem::edm::buffer<SCHEMA> hostBuffer(input.size_v(), *(mrs.hostMR()));
98 Details::copyColumn<0, COLUMNS...>(input, hostBuffer,
99 *(copies.hostCopy(ctx)), accessors)
100 ->wait();
101 (*(copies.deviceCopy(ctx)))(hostBuffer, output)->wait();
102 }
103 // If we only have a "main" memory resource, then we just directly copy
104 // into the vecmem container. Using the host copy object. Since the "one"
105 // memory resource should be host-accessible in this case.
106 else {
107 Details::copyColumn<0, COLUMNS...>(input, output, *(copies.hostCopy(ctx)),
108 accessors)
109 ->wait();
110 }
111}
112
113template <Concepts::SoAColumn... COLUMNS>
114template <typename SCHEMA, typename INTERFACE, typename BASE>
115void SoACopy<COLUMNS...>::operator()(const vecmem::edm::view<SCHEMA>& input,
116 DataVector<INTERFACE, BASE>& output,
117 const EventContext& ctx,
118 const IMemoryResourcesTool& mrs,
119 const ICopiesTool& copies) const {
120
121 static const auto accessors =
122 Details::AccessorTuple<SCHEMA>::get_nc(m_columns);
123 static_assert(
124 std::tuple_size_v<decltype(accessors)> == sizeof...(COLUMNS),
125 "Number of accessors does not match number of column definitions.");
126
127 // Resize the output xAOD container to match the input VecMem container.
128 typename vecmem::edm::view<SCHEMA>::size_type size = 0u;
129 if (mrs.hostMR() != nullptr) {
130 auto async_size = copies.deviceCopy(ctx)->get_size(input, *(mrs.hostMR()));
131 // Wait for the asynchronous size retrieval to complete.
132 size = async_size.get();
133 } else {
134 size = copies.hostCopy(ctx)->get_size(input);
135 }
136 if (output.size() != size) {
137 if (output.size() > 0u) {
138 output.clear();
139 }
140 output.push_new(size, []() { return new INTERFACE{}; });
141 }
142
143 // If we have a separate "main" and "host" memory resource, then we first
144 // copy into a host-resident VecMem buffer. Then we copy the columns one by
145 // one from this host-resident buffer into the output xAOD container.
146 if (mrs.hostMR() != nullptr) {
147 auto hostBuffer = copies.deviceCopy(ctx)->to(
148 input, *(mrs.hostMR()), nullptr, vecmem::copy::type::device_to_host);
149 Details::copyColumn<0, COLUMNS...>(hostBuffer, output,
150 *(copies.hostCopy(ctx)), accessors)
151 ->wait();
152 }
153 // If we only have a "main" memory resource, then we just directly copy
154 // from the vecmem container. Using the host copy object. Since the "one"
155 // memory resource should be host-accessible in this case.
156 else {
157 Details::copyColumn<0, COLUMNS...>(input, output, *(copies.hostCopy(ctx)),
158 accessors)
159 ->wait();
160 }
161}
162
163} // namespace AthDevice
164
165#endif // ATHDEVICEUTILS_SOACOPY_ICC