ATLAS Offline Software
Loading...
Searching...
No Matches
TopoAutomatonSplitting.cxx
Go to the documentation of this file.
1//
2// Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3//
4// Dear emacs, this is -*- c++ -*-
5//
6
9
10
11#include <string>
12#include <climits> //For CHAR_BIT... though it's a slightly inefficient way of saying 8.
13
15
16#include "boost/chrono/chrono.hpp"
17#include "boost/chrono/thread_clock.hpp"
18
19#include "MacroHelpers.h"
20
21using namespace CaloRecGPU;
22using namespace TASplitting;
23
24TopoAutomatonSplitting::TopoAutomatonSplitting(const std::string & type, const std::string & name, const IInterface * parent):
25 base_class(type, name, parent),
26 CaloGPUTimed(this)
27{
28}
29
31{
32 m_options.allocate();
33
34 using PackType = decltype(m_options.m_options->valid_sampling_primary);
35
36 static_assert(CaloCell_ID::getNumberOfSamplings() <= sizeof(PackType) * CHAR_BIT, "We are assuming that we have fewer samplings that bits per int!");
37
38 auto get_option_from_string = [](const std::string & str, bool & failed)
39 {
40 failed = false;
41 //cppcheck-suppress syntaxError
44 PreSamplerB,
45 EMB1,
46 EMB2,
47 EMB3,
48 PreSamplerE,
49 EME1,
50 EME2,
51 EME3,
52 HEC0,
53 HEC1,
54 HEC2,
55 HEC3,
56 TileBar0,
57 TileBar1,
58 TileBar2,
59 TileGap1,
60 TileGap2,
61 TileGap3,
62 TileExt0,
63 TileExt1,
64 TileExt2,
65 FCAL0,
66 FCAL1,
67 FCAL2
68 )
69 )
70 else
71 {
72 failed = true;
73 return CaloCell_ID::Unknown;
74 }
75 };
76
77 //cppcheck-suppress internalAstError
78 auto process_sampling = [&get_option_from_string](const std::vector<std::string> & sampling_names, std::string & invalid_names, PackType & sampling_option)
79 {
80 sampling_option = 0;
81 for (const std::string & samp_name : sampling_names)
82 {
83 bool failed = false;
84 const PackType sampling = (PackType) get_option_from_string(samp_name, failed);
85
86 if (failed)
87 {
88 if (invalid_names.size() == 0)
89 {
90 invalid_names = "'" + samp_name + "'";
91 }
92 else
93 {
94 invalid_names += ", '" + samp_name + "'";
95 }
96 }
97 else
98 {
99 sampling_option |= ((PackType) 1) << sampling;
100 }
101 }
102 };
103
104 std::string invalid_names;
105
106 process_sampling(m_samplingNames, invalid_names, m_options.m_options->valid_sampling_primary);
107
108 if (invalid_names.size() > 0)
109 {
110 ATH_MSG_ERROR( "Calorimeter samplings " << invalid_names
111 << " are not a valid Calorimeter sampling name and will be ignored! "
112 << "Valid names are: "
113 << "PreSamplerB, EMB1, EMB2, EMB3, "
114 << "PreSamplerE, EME1, EME2, EME3, "
115 << "HEC0, HEC1, HEC2, HEC3, "
116 << "TileBar0, TileBar1, TileBar2, "
117 << "TileGap1, TileGap2, TileGap3, "
118 << "TileExt0, TileExt1, TileExt2, "
119 << "FCAL0, FCAL1, FCAL2." );
120 }
121
122 invalid_names.clear();
123
124 process_sampling(m_secondarySamplingNames, invalid_names, m_options.m_options->valid_sampling_secondary);
125
126 if (invalid_names.size() > 0)
127 {
128 ATH_MSG_ERROR( "Calorimeter samplings " << invalid_names
129 << " are not a valid Calorimeter sampling name and will be ignored! "
130 << "Valid names are: "
131 << "PreSamplerB, EMB1, EMB2, EMB3, "
132 << "PreSamplerE, EME1, EME2, EME3, "
133 << "HEC0, HEC1, HEC2, HEC3, "
134 << "TileBar0, TileBar1, TileBar2, "
135 << "TileGap1, TileGap2, TileGap3, "
136 << "TileExt0, TileExt1, TileExt2, "
137 << "FCAL0, FCAL1, FCAL2." );
138 }
139
140 auto get_neighbour_option_from_string = [](const std::string & str, bool & failed)
141 {
142 failed = false;
145 prevInPhi,
146 nextInPhi,
147 prevInEta,
148 nextInEta,
149 faces2D,
150 corners2D,
151 all2D,
152 prevInSamp,
153 nextInSamp,
154 upAndDown,
155 prevSubDet,
156 nextSubDet,
157 all3D,
158 corners3D,
159 all3DwithCorners,
160 prevSuperCalo,
161 nextSuperCalo,
162 super3D
163 )
164 )
165 //I know Topological Clustering only supports a subset of those,
166 //but this is supposed to be a general data exporting tool...
167 else
168 {
169 failed = true;
171 }
172 };
173
174 bool neigh_failed = false;
175 m_options.m_options->neighbour_options = (unsigned int) get_neighbour_option_from_string(m_neighborOptionString, neigh_failed);
176
177 if (neigh_failed)
178 {
179 ATH_MSG_ERROR("Invalid Neighbour Option: " << m_neighborOptionString);
180 }
181
182 //We must repeat this printing part because ATH_MSG_ERROR
183 //is a macro that apparently calls a this->msg(...) function.
184 //Of course it won't work within a lambda...
185
186 m_options.m_options->min_num_cells = m_nCells;
187 m_options.m_options->min_maximum_energy = m_minEnergy;
188 m_options.m_options->EM_shower_scale = m_emShowerScale;
189 m_options.m_options->share_border_cells = m_shareBorderCells;
190 m_options.m_options->use_absolute_energy = m_absOpt;
191 m_options.m_options->treat_L1_predicted_as_good = m_treatL1PredictedCellsAsGood;
192
193 m_options.m_options->limit_HECIW_and_FCal_neighs = m_restrictHECIWandFCalNeighbors;
194 m_options.m_options->limit_PS_neighs = m_restrictPSNeighbors;
195
196 ATH_CHECK( m_kernelSizeOptimizer.retrieve() );
197
198 return StatusCode::SUCCESS;
199}
200
202{
203 m_options.sendToGPU();
205
206 return StatusCode::SUCCESS;
207}
208
209StatusCode TopoAutomatonSplitting::execute(const EventContext & ctx, const ConstantDataHolder & constant_data,
210 EventDataHolder & event_data, void * /*temporary_buffer*/ ) const
211{
212 using clock_type = boost::chrono::thread_clock;
213 auto time_cast = [](const auto & before, const auto & after)
214 {
215 return boost::chrono::duration_cast<boost::chrono::microseconds>(after - before).count();
216 };
217
218 const auto start = clock_type::now();
219 const auto preprocessing_end = clock_type::now();
220
221 fillNeighbours(event_data, constant_data, m_options, *(m_kernelSizeOptimizer.get()), m_measureTimes);
222
223 const auto after_neighs = clock_type::now();
224
225 findLocalMaxima(event_data, constant_data, m_options, *(m_kernelSizeOptimizer.get()), m_measureTimes);
226
227 const auto after_maxima = clock_type::now();
228
229 excludeSecondaryMaxima(event_data, constant_data, m_options, *(m_kernelSizeOptimizer.get()), m_measureTimes);
230
231 const auto after_secondary_maxima = clock_type::now();
232
233 splitClusterGrowing(event_data, constant_data, m_options, *(m_kernelSizeOptimizer.get()), m_measureTimes);
234
235 const auto after_growing = clock_type::now();
236
237 cellWeightingAndFinalization(event_data, constant_data, m_options, *(m_kernelSizeOptimizer.get()), m_measureTimes);
238
239 const auto end = clock_type::now();
240
241 if (m_measureTimes)
242 {
243 record_times(ctx.evt(),
244 time_cast(start, preprocessing_end),
245 time_cast(preprocessing_end, after_neighs),
246 time_cast(after_neighs, after_maxima),
247 time_cast(after_maxima, after_secondary_maxima),
248 time_cast(after_secondary_maxima, after_growing),
249 time_cast(after_growing, end)
250 );
251 }
252
253 return StatusCode::SUCCESS;
254
255
256}
257
258
260{
261 if (m_measureTimes)
262 {
263 print_times("Preprocessing Fill_List_of_Intra-Cluster_Neighbours Find_Local_Maxima Find_Secondary_Maxima Splitter_Tag_Propagation Cell_Weighting_And_Finalization", 6);
264 }
265 return StatusCode::SUCCESS;
266}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
Contains some helpful macros to help with repetitive code...
#define CRGPU_RECURSIVE_MACRO(...)
Expands recursive macros.
#define CRGPU_CHEAP_STRING_TO_ENUM(VAR, PREFIX, ONE,...)
Checks a string variable, VAR, for matching enum identifiers (ONE and the remaining variadic argument...
Helper class for offline cell identifiers.
Definition CaloCell_ID.h:34
Gaudi::Property< bool > m_measureTimes
If true, times are recorded to the file given by m_timeFileName.
CaloGPUTimed(T *ptr)
void print_times(const std::string &header, const size_t time_size) const
void record_times(const size_t event_num, const std::vector< size_t > &times) const
Holds CPU and GPU versions of the geometry and cell noise information, which are assumed to be consta...
Definition DataHolders.h:27
Holds the mutable per-event information (clusters and cells) and provides utilities to convert betwee...
Definition DataHolders.h:73
static constexpr unsigned int getNumberOfSamplings()
Get number of available samplings.
Gaudi::Property< std::vector< std::string > > m_secondarySamplingNames
vector of names of the secondary calorimeter samplings to consider.
Gaudi::Property< bool > m_restrictHECIWandFCalNeighbors
if set to true limit the neighbors in HEC IW and FCal2&3.
TASplitting::TASOptionsHolder m_options
Options for the algorithm, held in a GPU-friendly way.
TopoAutomatonSplitting(const std::string &type, const std::string &name, const IInterface *parent)
Gaudi::Property< bool > m_treatL1PredictedCellsAsGood
if set to true treat cells with a dead OTX which can be predicted by L1 trigger info as good instead ...
Gaudi::Property< float > m_emShowerScale
typical EM shower scale to use for distance criteria in shared cells
virtual StatusCode initialize_non_CUDA() override
Initialization that does not invoke CUDA functions.
Gaudi::Property< bool > m_absOpt
if set to true, splitter only looks at absolute value of Energy in order to identify potential seed c...
Gaudi::Property< float > m_minEnergy
local maxima need at least this energy content
ServiceHandle< IGPUKernelSizeOptimizerSvc > m_kernelSizeOptimizer
Handle to the CUDA kernel block and grid size optimization service.
Gaudi::Property< bool > m_shareBorderCells
share cells at the border between two local maxima
virtual StatusCode initialize_CUDA() override
Initialization that invokes CUDA functions.
virtual StatusCode execute(const EventContext &ctx, const CaloRecGPU::ConstantDataHolder &constant_data, CaloRecGPU::EventDataHolder &event_data, void *temporary_buffer) const override
virtual StatusCode finalize() override
Gaudi::Property< std::string > m_neighborOptionString
type of neighbor relations to use.
Gaudi::Property< bool > m_restrictPSNeighbors
if set to true limit the neighbors in presampler Barrel and Endcap.
Gaudi::Property< std::vector< std::string > > m_samplingNames
vector of names of the calorimeter samplings to consider for seeds.
Gaudi::Property< int > m_nCells
local maxima need at least this number of neighbors to become seeds
Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration.
void cellWeightingAndFinalization(CaloRecGPU::EventDataHolder &holder, const CaloRecGPU::ConstantDataHolder &instance_data, const TASOptionsHolder &options, const IGPUKernelSizeOptimizer &optimizer, const bool synchronize=false, CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream_to_use={})
void fillNeighbours(CaloRecGPU::EventDataHolder &holder, const CaloRecGPU::ConstantDataHolder &instance_data, const TASOptionsHolder &options, const IGPUKernelSizeOptimizer &optimizer, const bool synchronize=false, CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream_to_use={})
void splitClusterGrowing(CaloRecGPU::EventDataHolder &holder, const CaloRecGPU::ConstantDataHolder &instance_data, const TASOptionsHolder &options, const IGPUKernelSizeOptimizer &optimizer, const bool synchronize=false, CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream_to_use={})
void register_kernels(IGPUKernelSizeOptimizer &optimizer)
void findLocalMaxima(CaloRecGPU::EventDataHolder &holder, const CaloRecGPU::ConstantDataHolder &instance_data, const TASOptionsHolder &options, const IGPUKernelSizeOptimizer &optimizer, const bool synchronize=false, CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream_to_use={})
void excludeSecondaryMaxima(CaloRecGPU::EventDataHolder &holder, const CaloRecGPU::ConstantDataHolder &instance_data, const TASOptionsHolder &options, const IGPUKernelSizeOptimizer &optimizer, const bool synchronize=false, CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream_to_use={})