ATLAS Offline Software
Loading...
Searching...
No Matches
CaloGPUOutput.cxx
Go to the documentation of this file.
1//
2// Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3//
4// Dear emacs, this is -*- c++ -*-
5//
6
7#include "CaloGPUOutput.h"
8
10
11#include <unordered_map>
12
13using namespace CaloRecGPU;
14
15CaloGPUOutput::CaloGPUOutput(const std::string & type, const std::string & name, const IInterface * parent):
16 base_class(type, name, parent),
18{
19}
20
21StatusCode CaloGPUOutput::execute(const EventContext & ctx, const ConstantDataHolder & constant_data, EventDataHolder & event_data, void * /*temporary_buffer*/) const
22{
23 if (!m_constantDataSaved.load())
24 {
25 std::lock_guard<std::mutex> lock_guard(m_mutex);
26 if (!m_constantDataSaved.load())
27 {
28 const auto err1 = StandaloneDataIO::save_constants_to_folder(std::string(m_savePath), constant_data.m_geometry_dev,
31 {
32 return StatusCode::FAILURE;
33 }
34 m_constantDataSaved.store(true);
35 }
36 }
37
39
41 {
42 const auto err2 = StandaloneDataIO::save_cell_info_to_folder(ctx.evt(), std::string(m_savePath), cell_info, m_filePrefix, m_fileSuffix, m_numWidth);
43
45 {
46 return StatusCode::FAILURE;
47 }
48
49 return StatusCode::SUCCESS;
50 }
51
52
53 Helpers::CPU_object<ClusterInfoArr> clusters(event_data.m_clusters_dev), final_clusters(true);
54
55 //For every new index, the corresponding old index
56 std::vector<int> cluster_order(clusters->number);
57
58 //For every old index, the corresponding new index (if any)
59 std::vector<int> reverse_cluster_order(clusters->number, -1);
60
61 std::iota(cluster_order.begin(), cluster_order.end(), 0);
62
64 {
65 std::sort(cluster_order.begin(), cluster_order.end(), [&](const int a, const int b)
66 {
67 if (clusters->seedCellIndex[a] < 0)
68 {
69 return false;
70 //This means that clusters with no cells
71 //(marked as invalid) always compare lower,
72 //so they appear in the end.
73 }
74 else if (clusters->seedCellIndex[b] < 0)
75 {
76 return true;
77 }
78 return clusters->clusterEt[a] > clusters->clusterEt[b];
79 } );
80
81 unsigned int real_cluster_number = 0;
82
83 for (real_cluster_number = 0; real_cluster_number < cluster_order.size(); ++real_cluster_number)
84 {
85 if (clusters->seedCellIndex[real_cluster_number] < 0)
86 {
87 break;
88 }
89 else
90 {
91 reverse_cluster_order[cluster_order[real_cluster_number]] = real_cluster_number;
92 }
93 }
94
95 cluster_order.resize(real_cluster_number);
96
97 final_clusters->number = real_cluster_number;
98 final_clusters->has_deleted_clusters = false;
99 }
100
101 if (m_outputTags)
102 {
103 if (clusters->has_cells_per_cluster())
104 {
105 for (int i = 0; i < cell_info->number; ++i)
106 {
107 final_clusters->cells.tags[i] = 0;
108 }
109 for (int i = 0; i < clusters->number_cells; ++i)
110 {
111 const int real_cluster_index = reverse_cluster_order[clusters->clusterIndices[i]];
112
113 if (real_cluster_index < 0)
114 {
115 continue;
116 }
117
118 const int this_cell_index = clusters->cells.indices[i];
119
120 const float weight = clusters->cellWeights[i];
121
122 uint32_t weight_as_int = 0;
123 std::memcpy(&weight_as_int, &weight, sizeof(float));
124 //On the platforms we expect to be running this, it should be fine.
125 //Still UB.
126 //With C++20, we could do that bit-cast thing.
127
128 if (weight_as_int == 0)
129 {
130 weight_as_int = 1;
131 //Subnormal,
132 //but just to distinguish from
133 //a non-shared cluster.
134 }
135
136 const ClusterTag this_tag = final_clusters->cells.tags[this_cell_index];
137
138 const int other_index = this_tag.is_part_of_cluster() ? this_tag.cluster_index() : -1;
139
140 if (other_index < 0)
141 {
142 if (weight < 0.5f)
143 {
144 final_clusters->cells.tags[this_cell_index] = ClusterTag::make_tag(real_cluster_index, weight_as_int, 0);
145 }
146 else
147 {
148 final_clusters->cells.tags[this_cell_index] = ClusterTag::make_tag(real_cluster_index);
149 }
150 }
151 else if (weight > 0.5f)
152 {
153 final_clusters->cells.tags[this_cell_index] = ClusterTag::make_tag(real_cluster_index, this_tag.secondary_cluster_weight(), other_index);
154 }
155 else if (weight == 0.5f)
156 //Unlikely, but...
157 {
158 const int max_cluster = real_cluster_index > other_index ? real_cluster_index : other_index;
159 const int min_cluster = real_cluster_index > other_index ? other_index : real_cluster_index;
160 final_clusters->cells.tags[this_cell_index] = ClusterTag::make_tag(max_cluster, weight_as_int, min_cluster);
161 }
162 else /*if (weight < 0.5f)*/
163 {
164 final_clusters->cells.tags[this_cell_index] = ClusterTag::make_tag(other_index, weight_as_int, real_cluster_index);
165 }
166
167 //All of this logic assumes a cell is shared by at most two clusters
168 //with weights such that w_1 + w_2 = 1.
169 //This is not necessarily valid with local calibrations.
170
171 }
172 }
173 else
174 {
175 for (int i = 0; i < clusters->number_cells; ++i)
176 {
177 const ClusterTag this_tag = clusters->cells.tags[i];
178
179 const int primary_index = ( this_tag.is_part_of_cluster() ?
180 reverse_cluster_order[this_tag.cluster_index()] :
181 -1
182 );
183 const int secondary_index = ( this_tag.is_part_of_cluster() && this_tag.is_shared_between_clusters() ?
184 reverse_cluster_order[this_tag.secondary_cluster_index()] :
185 -1
186 );
187
188 const unsigned int weight = this_tag.secondary_cluster_weight();
189
190 if (primary_index >= 0 && secondary_index >= 0)
191 {
192 final_clusters->cells.tags[i] = ClusterTag::make_tag(primary_index, weight, secondary_index);
193 }
194 else if (primary_index >= 0)
195 {
196 final_clusters->cells.tags[i] = ClusterTag::make_tag(primary_index);
197 }
198 else if (secondary_index >= 0)
199 {
200 final_clusters->cells.tags[i] = ClusterTag::make_tag(secondary_index);
201 }
202 else
203 {
204 final_clusters->cells.tags[i] = 0;
205 }
206 }
207 }
208
209 final_clusters->number_cells = cell_info->number;
210 final_clusters->state = ClusterInformationState::TagsWithBasicInfo;
211 }
212 else
213 {
214 auto update_prefix_sum = [&]()
215 {
216 int running_count = 0;
217 for (int i = 1; i <= final_clusters->number; ++i)
218 {
219 running_count += final_clusters->cellsPrefixSum[i];
220 final_clusters->cellsPrefixSum[i] = running_count;
221 }
222 final_clusters->number_cells = running_count;
223 };
224
225 for (int i = 0; i <= final_clusters->number; ++i)
226 {
227 final_clusters->cellsPrefixSum[i] = 0;
228 if (i < final_clusters->number)
229 {
230 clusters->clusterIndices[i] = 0;
231 //Temporary storage for the index within the cluster.
232 }
233 }
234
235 if (!clusters->has_cells_per_cluster())
236 {
237 for (int i = 0; i < clusters->number_cells; ++i)
238 {
239 const ClusterTag this_tag = clusters->cells.tags[i];
240
241 const int primary_index = ( this_tag.is_part_of_cluster() ?
242 reverse_cluster_order[this_tag.cluster_index()] :
243 -1
244 );
245 const int secondary_index = ( this_tag.is_part_of_cluster() && this_tag.is_shared_between_clusters() ?
246 reverse_cluster_order[this_tag.secondary_cluster_index()] :
247 -1
248 );
249
250 if (primary_index >= 0)
251 {
252 final_clusters->cellsPrefixSum[primary_index + 1] += 1;
253 }
254
255 if (secondary_index >= 0)
256 {
257 final_clusters->cellsPrefixSum[secondary_index + 1] += 1;
258 }
259 }
260
261 update_prefix_sum();
262
263 for (int i = 0; i < clusters->number_cells; ++i)
264 {
265 const ClusterTag this_tag = clusters->cells.tags[i];
266
267 const int primary_index = ( this_tag.is_part_of_cluster() ?
268 reverse_cluster_order[this_tag.cluster_index()] :
269 -1
270 );
271 const int secondary_index = ( this_tag.is_part_of_cluster() && this_tag.is_shared_between_clusters() ?
272 reverse_cluster_order[this_tag.secondary_cluster_index()] :
273 -1
274 );
275
276 const unsigned int weight_as_int = this_tag.secondary_cluster_weight();
277
278 float weight;
279
280 std::memcpy(&weight, &weight_as_int, sizeof(float));
281
282 if (primary_index >= 0)
283 {
284 const int this_cell_start = final_clusters->cellsPrefixSum[primary_index];
285
286 int & this_cell_count = clusters->clusterIndices[primary_index];
287
288 ++this_cell_count;
289
290 const bool is_seed_cell = (i == clusters->seedCellIndex[this_tag.cluster_index()]);
291
292 const int this_index_in_cluster = this_cell_start + this_cell_count * is_seed_cell;
293
294 final_clusters->cells.indices[this_index_in_cluster] = i;
295 final_clusters->cellWeights[this_index_in_cluster] = 1.0f - weight;
296 final_clusters->clusterIndices[this_index_in_cluster] = primary_index;
297 }
298
299 if (secondary_index >= 0)
300 {
301 const int this_cell_start = final_clusters->cellsPrefixSum[secondary_index];
302
303 int & this_cell_count = clusters->clusterIndices[secondary_index];
304
305 ++this_cell_count;
306
307 const bool is_seed_cell = (i == clusters->seedCellIndex[this_tag.secondary_cluster_index()]);
308
309 const int this_index_in_cluster = this_cell_start + this_cell_count * is_seed_cell;
310
311 final_clusters->cells.indices[this_index_in_cluster] = i;
312 final_clusters->cellWeights[this_index_in_cluster] = weight;
313 final_clusters->clusterIndices[this_index_in_cluster] = primary_index;
314 }
315 }
316 }
317 else
318 {
319 final_clusters->cellsPrefixSum[0] = 0;
320
321 for (unsigned int i = 0; i < cluster_order.size(); ++i)
322 {
323 const int original_cluster = cluster_order[i];
324 final_clusters->cellsPrefixSum[i + 1] = clusters->cellsPrefixSum[original_cluster + 1] - clusters->cellsPrefixSum[original_cluster];
325 }
326
327 update_prefix_sum();
328
329 for (unsigned int i = 0; i < cluster_order.size(); ++i)
330 {
331 const int original_cluster = cluster_order[i];
332
333 int new_index = final_clusters->cellsPrefixSum[i];
334
335 for (int j = clusters->cellsPrefixSum[original_cluster]; j < clusters->cellsPrefixSum[original_cluster + 1]; ++j, ++new_index)
336 {
337 final_clusters->cells.indices[new_index] = clusters->cells.indices[j];
338 final_clusters->cellWeights[new_index] = clusters->cellWeights[j];
339 final_clusters->clusterIndices[new_index] = clusters->clusterIndices[j];
340 }
341 }
342
343 }
344
345 final_clusters->state = ClusterInformationState::WithBasicInfo;
346 }
347
348 for (unsigned int i = 0; i < cluster_order.size(); ++i)
349 {
350 final_clusters->clusterEnergy[i] = clusters->clusterEnergy[cluster_order[i]];
351 final_clusters->clusterEt[i] = clusters->clusterEt[cluster_order[i]];
352 final_clusters->clusterEta[i] = clusters->clusterEta[cluster_order[i]];
353 final_clusters->clusterPhi[i] = clusters->clusterPhi[cluster_order[i]];
354 final_clusters->seedCellIndex[i] = clusters->seedCellIndex[cluster_order[i]];
355 }
356
357 const auto err2 = StandaloneDataIO::save_event_to_folder(ctx.evt(), std::string(m_savePath), cell_info, final_clusters,
358 m_filePrefix, m_fileSuffix, m_numWidth);
359
361 {
362 return StatusCode::FAILURE;
363 }
364
365 return StatusCode::SUCCESS;
366
367}
static Double_t a
if(febId1==febId2)
Gaudi::Property< std::string > m_savePath
The path specifying the folder to which the files should be saved.
std::mutex m_mutex
This mutex is locked when saving the constant data on the first event to ensure thread safety.
Gaudi::Property< std::string > m_filePrefix
The prefix of the saved files.
Gaudi::Property< unsigned int > m_numWidth
The number of digits to reserve for the events.
virtual StatusCode execute(const EventContext &ctx, const CaloRecGPU::ConstantDataHolder &constant_data, CaloRecGPU::EventDataHolder &event_data, void *temporary_buffer) const override
std::atomic< bool > m_constantDataSaved
A flag to signal that the constant data has been adequately saved.
Gaudi::Property< bool > m_onlyCellInfo
If true, only output cell info (useful for reducing disk usage when running the full standalone versi...
Gaudi::Property< bool > m_sortedAndCutClusters
If true, sort the clusters by transverse energy and compactify the tags to ensure sequentiality.
Gaudi::Property< std::string > m_fileSuffix
The suffix of the saved files.
CaloGPUOutput(const std::string &type, const std::string &name, const IInterface *parent)
Holds CPU and GPU versions of the geometry and cell noise information, which are assumed to be consta...
Definition DataHolders.h:27
CaloRecGPU::Helpers::CUDA_object< CaloRecGPU::CellNoiseArr > m_cell_noise_dev
Definition DataHolders.h:38
CaloRecGPU::Helpers::CUDA_object< CaloRecGPU::GeometryArr > m_geometry_dev
Definition DataHolders.h:36
Holds the mutable per-event information (clusters and cells) and provides utilities to convert betwee...
Definition DataHolders.h:73
CaloRecGPU::Helpers::CUDA_object< CaloRecGPU::CellInfoArr > m_cell_info_dev
CaloRecGPU::Helpers::CUDA_object< CaloRecGPU::ClusterInfoArr > m_clusters_dev
STL class.
SimpleHolder< T, MemoryContext::CPU, true > CPU_object
Holds an object of type T in CPU memory.
Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
setEventNumber uint32_t
The class that actually expresses the cluster assignment.
constexpr int32_t secondary_cluster_index() const
constexpr int32_t secondary_cluster_weight() const
constexpr bool is_shared_between_clusters() const
constexpr bool is_part_of_cluster() const
constexpr int32_t cluster_index() const
static constexpr carrier make_tag(const uint16_t cluster_index=0, const int32_t weight=0, const uint16_t second_cluster_index=0)
static ErrorState save_constants_to_folder(const std::filesystem::path &folder, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::GeometryArr > &geo, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::CellNoiseArr > &noise, const std::string &prefix="", const std::string &suffix="", const bool output_errors=true)
static ErrorState save_event_to_folder(const size_t event_number, const std::filesystem::path &folder, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::CellInfoArr > &cell_info, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::ClusterInfoArr > &clusters, const std::string &prefix="", const std::string &suffix="", const unsigned int num_width=9, const bool output_errors=true)
static ErrorState save_cell_info_to_folder(const size_t event_number, const std::filesystem::path &folder, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::CellInfoArr > &cell_info, const std::string &prefix="", const std::string &suffix="", const unsigned int num_width=9, const bool output_errors=true)
std::string number(const double &d, const std::string &s)
Definition utils.cxx:186