ATLAS Offline Software
Loading...
Searching...
No Matches
CaloCellsCounterGPU.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
9
10#include <map>
11#include <vector>
12#include <filesystem>
13
14using namespace CaloRecGPU;
15
16CaloCellsCounterGPU::CaloCellsCounterGPU(const std::string & type, const std::string & name, const IInterface * parent):
17 base_class(type, name, parent)
18{
19}
20
21
22namespace
23{
24 struct size_struct
25 {
26 unsigned int total = 0, seed = 0, grow = 0, term = 0, invalid = 0, shared = 0;
27 template <class Str>
28 friend Str & operator << (Str & s, const size_struct & sst)
29 {
30 s << sst.total << " " << sst.seed << " " << sst.grow << " " << sst.term << " " << sst.invalid << " " << sst.shared;
31 return s;
32 }
33 };
34
35 struct cluster_info_struct
36 {
37 size_struct size;
38 float seed_snr = -9e99;
39 float seed_energy = -9e99;
40 template <class Str>
41 friend Str & operator << (Str & s, const cluster_info_struct & cis)
42 {
43 s << cis.size << " (" << cis.seed_snr << " " << cis.seed_energy << ")";
44 return s;
45 }
46 };
47
48} // anonymous namespace
49
50StatusCode CaloCellsCounterGPU::execute(const EventContext & ctx, const ConstantDataHolder & constant_data, EventDataHolder & event_data, void * /*temporary_buffer*/) const
51{
53 //We could try to keep this in CPU memory by default,
54 //but, since it isn't quite needed and we don't mind taking a bit longer for this
55 //since we're only debugging, let this be as generic as possible.
56
59
60 unsigned int gain_counts[GainConversion::num_gain_values()] = {0};
61
62 size_struct global_counts, global_cluster_counts;
63
64 std::vector<int> cluster_max_cell(clusters->number, -1);
65 std::vector<float> cluster_max_snr(clusters->number, -9e99);
66 std::vector<float> cluster_max_energy(clusters->number, -9e99);
67
68 std::vector<size_struct> cluster_counts(clusters->number);
69
70 if (clusters->has_cells_per_cluster())
71 {
72 for (int i = 0; i < cell_info->number; ++i)
73 {
74 if (!cell_info->is_valid(i))
75 {
76 continue;
77 }
78
79 const int gain = cell_info->gain[i];
80 ++gain_counts[gain - GainConversion::min_gain_value()];
81
82 const float energy = cell_info->energy[i];
83
84 const float SNR = std::abs( energy / cell_noise->get_noise(cell_info->hashID[i], gain) );
85
86 if (SNR > m_seedThreshold)
87 {
88 ++global_counts.seed;
89 }
90 else if (SNR > m_growThreshold)
91 {
92 ++global_counts.grow;
93 }
94 else if (SNR > m_cellThreshold)
95 {
96 ++global_counts.term;
97 }
98 else
99 {
100 ++global_counts.invalid;
101 }
102 }
103
104 std::vector<char> counted_cells(NCaloCells, 0);
105
106 for (int i = 0; i < clusters->number_cells; ++i)
107 {
108 const int cell_index = clusters->cells.indices[i];
109 const int cell_hash_ID = cell_info->hashID[cell_index];
110
111
112 const int gain = cell_info->gain[cell_index];
113 ++gain_counts[gain - GainConversion::min_gain_value()];
114
115 const float energy = cell_info->energy[cell_index];
116
117 const float SNR = std::abs( energy / cell_noise->get_noise(cell_hash_ID, gain) );
118
119 const bool is_new_cell = !counted_cells[cell_index];
120
121 if (is_new_cell)
122 {
123 counted_cells[cell_index] = 1;
124 ++global_cluster_counts.total;
125 }
126
127 const int cluster_index = clusters->clusterIndices[i];
128
129 if (SNR > cluster_max_snr[cluster_index] || (SNR == cluster_max_snr[cluster_index] && cell_hash_ID > cluster_max_cell[cluster_index]))
130 {
131 cluster_max_snr[cluster_index] = SNR;
132 cluster_max_cell[cluster_index] = cell_hash_ID;
133 cluster_max_energy[cluster_index] = std::abs(energy);
134 }
135
136 if (SNR > m_seedThreshold)
137 {
138 global_cluster_counts.seed += is_new_cell;
139 ++cluster_counts[cluster_index].seed;
140 }
141 else if (SNR > m_growThreshold)
142 {
143 global_cluster_counts.grow += is_new_cell;
144 ++cluster_counts[cluster_index].grow;
145 }
146 else if (SNR > m_cellThreshold)
147 {
148 global_cluster_counts.term += is_new_cell;
149 ++cluster_counts[cluster_index].term;
150 }
151 else
152 {
153 global_cluster_counts.invalid += is_new_cell;
154 ++cluster_counts[cluster_index].invalid;
155 }
156
157
158 ++cluster_counts[cluster_index].total;
159
160 global_cluster_counts.shared += !is_new_cell;
161 cluster_counts[cluster_index].shared += !is_new_cell;
162
163 }
164
165 }
166 else
167 {
168 for (int i = 0; i < cell_info->number; ++i)
169 {
170 if (!cell_info->is_valid(i))
171 {
172 continue;
173 }
174
175 const int gain = cell_info->gain[i];
176 ++gain_counts[gain - GainConversion::min_gain_value()];
177
178 const float energy = cell_info->energy[i];
179
180 const float SNR = std::abs( energy / cell_noise->get_noise(cell_info->hashID[i], gain) );
181
182 const ClusterTag tag = clusters->cells.tags[i];
183
184 const bool is_cluster = tag.is_part_of_cluster();
185
186 global_cluster_counts.total += is_cluster;
187
188 if (SNR > m_seedThreshold)
189 {
190 ++global_counts.seed;
191 global_cluster_counts.seed += is_cluster;
192 }
193 else if (SNR > m_growThreshold)
194 {
195 ++global_counts.grow;
196 global_cluster_counts.grow += is_cluster;
197 }
198 else if (SNR > m_cellThreshold)
199 {
200 ++global_counts.term;
201 global_cluster_counts.term += is_cluster;
202 }
203 else
204 {
205 ++global_counts.invalid;
206 global_cluster_counts.invalid += is_cluster;
207 }
208
209 if (is_cluster)
210 {
211 const int cluster = tag.cluster_index();
212 const int other_cluster = tag.is_shared_between_clusters() ? tag.secondary_cluster_index() : cluster;
213 if (!tag.is_shared_between_clusters() && (SNR > cluster_max_snr[cluster] || (SNR == cluster_max_snr[cluster] && i > cluster_max_cell[cluster])))
214 {
215 cluster_max_snr[cluster] = SNR;
216 cluster_max_cell[cluster] = i;
217 cluster_max_energy[cluster] = std::abs(energy);
218 }
219 ++cluster_counts[cluster].total;
220 cluster_counts[other_cluster].total += (cluster != other_cluster);
221
222 global_cluster_counts.shared += tag.is_shared_between_clusters();
223 cluster_counts[cluster].shared += tag.is_shared_between_clusters();
224 cluster_counts[other_cluster].shared += tag.is_shared_between_clusters();
225
226 if (SNR > m_seedThreshold)
227 {
228 ++cluster_counts[cluster].seed;
229 cluster_counts[other_cluster].seed += (cluster != other_cluster);
230 }
231 else if (SNR > m_growThreshold)
232 {
233 ++cluster_counts[cluster].grow;
234 cluster_counts[other_cluster].grow += (cluster != other_cluster);
235 }
236 else if (SNR > m_cellThreshold)
237 {
238 ++cluster_counts[cluster].term;
239 cluster_counts[other_cluster].term += (cluster != other_cluster);
240 }
241 else
242 {
243 ++cluster_counts[cluster].invalid;
244 cluster_counts[other_cluster].invalid += (cluster != other_cluster);
245 }
246 }
247 }
248 }
249
250 std::map<int, cluster_info_struct> cluster_sizes;
251
252 for (int i = 0; i < clusters->number; ++i)
253 {
254 if (cluster_max_cell[i] >= 0)
255 {
256 cluster_sizes[cluster_max_cell[i]] = cluster_info_struct{cluster_counts[i], cluster_max_snr[i], cluster_max_energy[i]};
257 }
258 }
259
260 const auto err1 = StandaloneDataIO::prepare_folder_for_output(std::string(m_savePath));
262 {
263 return StatusCode::FAILURE;
264 }
265
266 const std::filesystem::path save_file = m_savePath + "/" + StandaloneDataIO::build_filename((m_filePrefix.size() > 0 ? m_filePrefix + "_counts" : "counts"),
267 ctx.evt(), m_fileSuffix, "txt", m_numWidth);
268
269 std::ofstream out_file(save_file);
270
271 if (!out_file.is_open())
272 {
273 return StatusCode::FAILURE;
274 }
275
276 out_file << "Cell counts: " << global_counts << "\n\n";
277
278 out_file << "Cells in clusters count: " << global_cluster_counts << "\n\n";
279 out_file << "Clusters:\n\n";
280
281 for (const auto & it : cluster_sizes)
282 {
283 out_file << it.first << " " << it.second << "\n";
284 }
285
286 out_file << std::endl;
287
288 if (!out_file.good())
289 {
290 return StatusCode::FAILURE;
291 }
292
293 out_file.close();
294
295 return StatusCode::SUCCESS;
296
297}
std::ostream & operator<<(std::ostream &lhs, const TestGaudiProperty &rhs)
Gaudi::Property< float > m_cellThreshold
Value to consider for the seed threshold.
Gaudi::Property< std::string > m_savePath
The path specifying the folder to which the files should be saved.
CaloCellsCounterGPU(const std::string &type, const std::string &name, const IInterface *parent)
Gaudi::Property< std::string > m_fileSuffix
The suffix of the saved files.
virtual StatusCode execute(const EventContext &ctx, const CaloRecGPU::ConstantDataHolder &constant_data, CaloRecGPU::EventDataHolder &event_data, void *temporary_buffer) const override
Gaudi::Property< float > m_seedThreshold
Value to consider for the seed threshold.
Gaudi::Property< float > m_growThreshold
Value to consider for the seed threshold.
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.
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
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
static constexpr GainType min_gain_value()
static constexpr GainType num_gain_values()
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.
constexpr int NCaloCells
The class that actually expresses the cluster assignment.
static std::string build_filename(const std::string &prefix, const std::string &text, const std::string &suffix, const std::string &ext)
static ErrorState prepare_folder_for_output(const std::filesystem::path &folder, const bool output_errors=true)