ATLAS Offline Software
Loading...
Searching...
No Matches
TopoAutomatonSplitting.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
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;
43 PreSamplerB,
44 EMB1,
45 EMB2,
46 EMB3,
47 PreSamplerE,
48 EME1,
49 EME2,
50 EME3,
51 HEC0,
52 HEC1,
53 HEC2,
54 HEC3,
55 TileBar0,
56 TileBar1,
57 TileBar2,
58 TileGap1,
59 TileGap2,
60 TileGap3,
61 TileExt0,
62 TileExt1,
63 TileExt2,
64 FCAL0,
65 FCAL1,
66 FCAL2
67 )
68 )
69 else
70 {
71 failed = true;
72 return CaloCell_ID::Unknown;
73 }
74 };
75
76
77 auto process_sampling = [&get_option_from_string](const std::vector<std::string> & sampling_names, std::string & invalid_names, PackType & sampling_option)
78 {
79 sampling_option = 0;
80 for (const std::string & samp_name : sampling_names)
81 {
82 bool failed = false;
83 const PackType sampling = (PackType) get_option_from_string(samp_name, failed);
84
85 if (failed)
86 {
87 if (invalid_names.size() == 0)
88 {
89 invalid_names = "'" + samp_name + "'";
90 }
91 else
92 {
93 invalid_names += ", '" + samp_name + "'";
94 }
95 }
96 else
97 {
98 sampling_option |= ((PackType) 1) << sampling;
99 }
100 }
101 };
102
103 std::string invalid_names;
104
105 process_sampling(m_samplingNames, invalid_names, m_options.m_options->valid_sampling_primary);
106
107 if (invalid_names.size() > 0)
108 {
109 ATH_MSG_ERROR( "Calorimeter samplings " << invalid_names
110 << " are not a valid Calorimeter sampling name and will be ignored! "
111 << "Valid names are: "
112 << "PreSamplerB, EMB1, EMB2, EMB3, "
113 << "PreSamplerE, EME1, EME2, EME3, "
114 << "HEC0, HEC1, HEC2, HEC3, "
115 << "TileBar0, TileBar1, TileBar2, "
116 << "TileGap1, TileGap2, TileGap3, "
117 << "TileExt0, TileExt1, TileExt2, "
118 << "FCAL0, FCAL1, FCAL2." );
119 }
120
121 invalid_names.clear();
122
123 process_sampling(m_secondarySamplingNames, invalid_names, m_options.m_options->valid_sampling_secondary);
124
125 if (invalid_names.size() > 0)
126 {
127 ATH_MSG_ERROR( "Calorimeter samplings " << invalid_names
128 << " are not a valid Calorimeter sampling name and will be ignored! "
129 << "Valid names are: "
130 << "PreSamplerB, EMB1, EMB2, EMB3, "
131 << "PreSamplerE, EME1, EME2, EME3, "
132 << "HEC0, HEC1, HEC2, HEC3, "
133 << "TileBar0, TileBar1, TileBar2, "
134 << "TileGap1, TileGap2, TileGap3, "
135 << "TileExt0, TileExt1, TileExt2, "
136 << "FCAL0, FCAL1, FCAL2." );
137 }
138
139 auto get_neighbour_option_from_string = [](const std::string & str, bool & failed)
140 {
141 failed = false;
144 prevInPhi,
145 nextInPhi,
146 prevInEta,
147 nextInEta,
148 faces2D,
149 corners2D,
150 all2D,
151 prevInSamp,
152 nextInSamp,
153 upAndDown,
154 prevSubDet,
155 nextSubDet,
156 all3D,
157 corners3D,
158 all3DwithCorners,
159 prevSuperCalo,
160 nextSuperCalo,
161 super3D
162 )
163 )
164 //I know Topological Clustering only supports a subset of those,
165 //but this is supposed to be a general data exporting tool...
166 else
167 {
168 failed = true;
170 }
171 };
172
173 bool neigh_failed = false;
174 m_options.m_options->neighbour_options = (unsigned int) get_neighbour_option_from_string(m_neighborOptionString, neigh_failed);
175
176 if (neigh_failed)
177 {
178 ATH_MSG_ERROR("Invalid Neighbour Option: " << m_neighborOptionString);
179 }
180
181 //We must repeat this printing part because ATH_MSG_ERROR
182 //is a macro that apparently calls a this->msg(...) function.
183 //Of course it won't work within a lambda...
184
185 m_options.m_options->min_num_cells = m_nCells;
186 m_options.m_options->min_maximum_energy = m_minEnergy;
187 m_options.m_options->EM_shower_scale = m_emShowerScale;
188 m_options.m_options->share_border_cells = m_shareBorderCells;
189 m_options.m_options->use_absolute_energy = m_absOpt;
190 m_options.m_options->treat_L1_predicted_as_good = m_treatL1PredictedCellsAsGood;
191
192 m_options.m_options->limit_HECIW_and_FCal_neighs = m_restrictHECIWandFCalNeighbors;
193 m_options.m_options->limit_PS_neighs = m_restrictPSNeighbors;
194
195 ATH_CHECK( m_kernelSizeOptimizer.retrieve() );
196
197 return StatusCode::SUCCESS;
198}
199
201{
202 m_options.sendToGPU();
204
205 return StatusCode::SUCCESS;
206}
207
208StatusCode TopoAutomatonSplitting::execute(const EventContext & ctx, const ConstantDataHolder & constant_data,
209 EventDataHolder & event_data, void * /*temporary_buffer*/ ) const
210{
211 using clock_type = boost::chrono::thread_clock;
212 auto time_cast = [](const auto & before, const auto & after)
213 {
214 return boost::chrono::duration_cast<boost::chrono::microseconds>(after - before).count();
215 };
216
217 const auto start = clock_type::now();
218 const auto preprocessing_end = clock_type::now();
219
220 fillNeighbours(event_data, constant_data, m_options, *(m_kernelSizeOptimizer.get()), m_measureTimes);
221
222 const auto after_neighs = clock_type::now();
223
224 findLocalMaxima(event_data, constant_data, m_options, *(m_kernelSizeOptimizer.get()), m_measureTimes);
225
226 const auto after_maxima = clock_type::now();
227
228 excludeSecondaryMaxima(event_data, constant_data, m_options, *(m_kernelSizeOptimizer.get()), m_measureTimes);
229
230 const auto after_secondary_maxima = clock_type::now();
231
232 splitClusterGrowing(event_data, constant_data, m_options, *(m_kernelSizeOptimizer.get()), m_measureTimes);
233
234 const auto after_growing = clock_type::now();
235
236 cellWeightingAndFinalization(event_data, constant_data, m_options, *(m_kernelSizeOptimizer.get()), m_measureTimes);
237
238 const auto end = clock_type::now();
239
240 if (m_measureTimes)
241 {
242 record_times(ctx.evt(),
243 time_cast(start, preprocessing_end),
244 time_cast(preprocessing_end, after_neighs),
245 time_cast(after_neighs, after_maxima),
246 time_cast(after_maxima, after_secondary_maxima),
247 time_cast(after_secondary_maxima, after_growing),
248 time_cast(after_growing, end)
249 );
250 }
251
252 return StatusCode::SUCCESS;
253
254
255}
256
257
259{
260 if (m_measureTimes)
261 {
262 print_times("Preprocessing Fill_List_of_Intra-Cluster_Neighbours Find_Local_Maxima Find_Secondary_Maxima Splitter_Tag_Propagation Cell_Weighting_And_Finalization", 6);
263 }
264 return StatusCode::SUCCESS;
265}
#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={})