ATLAS Offline Software
BasicGPUToAthenaImporter.cxx
Go to the documentation of this file.
1 //
2 // Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 //
4 // Dear emacs, this is -*- c++ -*-
5 //
6 
8 
10 
12 
13 #include <vector>
14 #include <algorithm>
15 #include <memory>
16 
19 
20 #include "boost/chrono/chrono.hpp"
21 #include "boost/chrono/thread_clock.hpp"
22 
23 using namespace CaloRecGPU;
24 
25 BasicGPUToAthenaImporter::BasicGPUToAthenaImporter(const std::string & type, const std::string & name, const IInterface * parent):
27  CaloGPUTimed(this)
28 {
29  declareInterface<ICaloClusterGPUOutputTransformer> (this);
30 
31 }
32 
33 #include "MacroHelpers.h"
34 
36 {
38 
39  ATH_CHECK( detStore()->retrieve(m_calo_id, "CaloCell_ID") );
40 
41  auto get_option_from_string = [](const std::string & str, bool & failed)
42  {
43  failed = false;
46  SW_55ele,
47  SW_35ele,
48  SW_37ele,
49  SW_55gam,
50  SW_35gam,
51  SW_37gam,
52  SW_55Econv,
53  SW_35Econv,
54  SW_37Econv,
55  SW_softe,
56  Topo_420,
57  Topo_633,
58  SW_7_11,
59  SuperCluster,
60  Tower_01_01,
61  Tower_005_005,
62  Tower_fixed_area
63  )
64  )
65  //I know Topological Clustering only supports a subset of those,
66  //but this is supposed to be a general data exporting tool...
67  else
68  {
69  //failed = true;
71  }
72  };
73 
74  bool size_failed = false;
75  m_clusterSize = get_option_from_string(m_clusterSizeString, size_failed);
76 
78  {
79  ATH_MSG_ERROR("Invalid Cluster Size: " << m_clusterSizeString);
80  }
81 
82  if (size_failed)
83  {
84  return StatusCode::FAILURE;
85  }
86 
87  return StatusCode::SUCCESS;
88 }
89 
90 
91 
93  const ConstantDataHolder &,
94  EventDataHolder & ed,
95  xAOD::CaloClusterContainer * cluster_container) const
96 {
97 
98 
99  using clock_type = boost::chrono::thread_clock;
100  auto time_cast = [](const auto & before, const auto & after)
101  {
102  return boost::chrono::duration_cast<boost::chrono::microseconds>(after - before).count();
103  };
104 
105  const auto start = clock_type::now();
106 
107  SG::ReadHandle<CaloCellContainer> cell_collection(m_cellsKey, ctx);
108  if ( !cell_collection.isValid() )
109  {
110  ATH_MSG_ERROR( " Cannot retrieve CaloCellContainer: " << cell_collection.name() );
111  return StatusCode::FAILURE;
112  }
113  const DataLink<CaloCellContainer> cell_collection_link (cell_collection.name(), ctx);
114 
115  ed.returnToCPU(!m_keepGPUData, true, true, false);
116 
117  const auto after_send = clock_type::now();
118 
119  std::vector<std::unique_ptr<CaloClusterCellLink>> cell_links;
120 
121  cell_links.reserve(ed.m_clusters->number);
122 
123  for (int i = 0; i < ed.m_clusters->number; ++i)
124  {
125  if (ed.m_clusters->seedCellID[i] >= 0)
126  {
127  cell_links.emplace_back(std::make_unique<CaloClusterCellLink>(cell_collection_link));
128  cell_links.back()->reserve(256);
129  //To be adjusted.
130  }
131  else
132  {
133  cell_links.emplace_back(nullptr);
134  //The excluded clusters don't have any cells.
135  }
136  }
137 
138  const auto after_creation = clock_type::now();
139 
140 
141  //cell_index is the actual cell index in the full set of cells (identifier hash)
142  //cell_count is the cell position in the cell collection (what we want for the weight)
143  const auto process_cell = [&](const int cell_index, const int cell_count)
144  {
145  const ClusterTag this_tag = ed.m_cell_state->clusterTag[cell_index];
146  if (this_tag.is_part_of_cluster())
147  {
148  const int this_index = this_tag.cluster_index();
149  const int32_t weight_pattern = this_tag.secondary_cluster_weight();
150 
151  float tempf = 1.0f;
152 
153  std::memcpy(&tempf, &weight_pattern, sizeof(float));
154  //C++20 would give us bit cast to do this more properly.
155  //Still, given how the bit pattern is created,
156  //it should be safe.
157 
158  const float reverse_weight = tempf;
159 
160  const float this_weight = 1.0f - reverse_weight;
161 
162  if (cell_links[this_index])
163  {
164  cell_links[this_index]->addCell(cell_count, this_weight);
165 
166  if (cell_index == ed.m_clusters->seedCellID[this_index] && cell_links[this_index]->size() > 1)
167  //Seed cells aren't shared,
168  //so no need to check this on the other case.
169  {
170  CaloClusterCellLink::iterator begin_it = cell_links[this_index]->begin();
171  CaloClusterCellLink::iterator back_it = std::prev(cell_links[this_index]->end());
172 
173  const unsigned int first_idx = begin_it.index();
174  const double first_wgt = begin_it.weight();
175 
176  begin_it.reindex(back_it.index());
177  begin_it.reweight(back_it.weight());
178 
179  back_it.reindex(first_idx);
180  back_it.reweight(first_wgt);
181 
182  //Of course, this is to ensure the first cell is the seed cell,
183  //in accordance to the way some cluster properties
184  //(mostly phi-related) are calculated.
185  }
186  }
187 
188  if (this_tag.is_shared_between_clusters())
189  {
190  const int other_index = this_tag.secondary_cluster_index();
191  if (cell_links[other_index])
192  {
193  cell_links[other_index]->addCell(cell_count, reverse_weight);
194  }
195  }
196  }
197  };
198 
199  if (cell_collection->isOrderedAndComplete())
200  //Fast path: cell indices within the collection and identifierHashes match!
201  {
202  for (int cell_index = 0; cell_index < NCaloCells; ++cell_index)
203  {
204  process_cell(cell_index, cell_index);
205  }
206  }
207  else if (cell_collection->isOrdered() && m_missingCellsToFill.size() > 0)
208  {
209  size_t missing_cell_count = 0;
210  for (int cell_index = 0; cell_index < NCaloCells; ++cell_index)
211  {
212  if (missing_cell_count < m_missingCellsToFill.size() && cell_index == m_missingCellsToFill[missing_cell_count])
213  {
214  ++missing_cell_count;
215  continue;
216  }
217  process_cell(cell_index, cell_index - missing_cell_count);
218  }
219  }
220  else
221  //Slow path: be careful.
222  {
223  CaloCellContainer::const_iterator iCells = cell_collection->begin();
224 
225  for (int cell_count = 0; iCells != cell_collection->end(); ++iCells, ++cell_count)
226  {
227  const CaloCell * cell = (*iCells);
228 
229  //const int cell_index = m_calo_id->calo_cell_hash(cell->ID());
230  const int cell_index = cell->caloDDE()->calo_hash();
231 
232  process_cell(cell_index, cell_count);
233  }
234  }
235  const auto after_cells = clock_type::now();
236 
237  std::vector<int> cluster_order(ed.m_clusters->number);
238 
239  std::iota(cluster_order.begin(), cluster_order.end(), 0);
240 
241  std::sort(cluster_order.begin(), cluster_order.end(), [&](const int a, const int b) -> bool
242  {
243  const bool a_valid = ed.m_clusters->seedCellID[a] >= 0;
244  const bool b_valid = ed.m_clusters->seedCellID[b] >= 0;
245  if (a_valid && b_valid)
246  {
247  return ed.m_clusters->clusterEt[a]
248  > ed.m_clusters->clusterEt[b];
249  }
250  else if (a_valid)
251  {
252  return true;
253  }
254  else if (b_valid)
255  {
256  return false;
257  }
258  else
259  {
260  return b > a;
261  }
262  } );
263 
264  //Ordered by Et as in the default algorithm...
265  //The fact that some invalid clusters
266  //(with possibly trash values for Et)
267  //can crop up is irrelevant since
268  //we don't add those anyway:
269  //the rest is still ordered like we want it to be.
270 
271  const auto after_sort = clock_type::now();
272 
273  cluster_container->clear();
274  cluster_container->reserve(cell_links.size());
275 
276  for (size_t i = 0; i < cluster_order.size(); ++i)
277  {
278  const int cluster_index = cluster_order[i];
279 
280  if (cell_links[cluster_index] != nullptr && cell_links[cluster_index]->size() > 0)
281  {
282  xAOD::CaloCluster * cluster = new xAOD::CaloCluster();
283  cluster_container->push_back(cluster);
284 
285  cluster->addCellLink(cell_links[cluster_index].release());
286  cluster->setClusterSize(m_clusterSize);
287  if (m_useCPUPropertiesCalculation)
288  {
289  CaloClusterKineHelper::calculateKine(cluster, false, true, true);
290  }
291  else
292  {
293  cluster->setE(ed.m_clusters->clusterEnergy[cluster_index]);
294  cluster->setEta(ed.m_clusters->clusterEta[cluster_index]);
295  cluster->setPhi(ed.m_clusters->clusterPhi[cluster_index]);
296  }
297 
298  if (m_saveUncalibrated)
299  {
300  cluster->setRawE(cluster->calE());
301  cluster->setRawEta(cluster->calEta());
302  cluster->setRawPhi(cluster->calPhi());
303  cluster->setRawM(cluster->calM());
304  }
305 
306  }
307 
308  }
309 
310  const auto after_fill = clock_type::now();
311 
312  if (m_measureTimes)
313  {
314  record_times(ctx.evt(), time_cast(start, after_send),
315  time_cast(after_send, after_creation),
316  time_cast(after_creation, after_cells),
317  time_cast(after_cells, after_sort),
318  time_cast(after_sort, after_fill)
319  );
320  }
321 
322  return StatusCode::SUCCESS;
323 
324 }
325 
326 
328 {
329 
330  if (m_measureTimes)
331  {
332  print_times("Transfer_from_GPU Cluster_Creation Cell_Adding Sorting Collection_Filling", 5);
333  }
334  return StatusCode::SUCCESS;
335 }
336 
python.PyKernel.retrieve
def retrieve(aClass, aKey=None)
Definition: PyKernel.py:110
CaloClusterKineHelper.h
xAOD::CaloCluster_v1::CSize_Unknown
@ CSize_Unknown
Definition: CaloCluster_v1.h:112
DataModel_detail::const_iterator
Const iterator class for DataVector/DataList.
Definition: DVLIterator.h:82
xAOD::CaloCluster_v1::setRawM
void setRawM(flt_t)
Set mass for singal state UNCALIBRATED.
Definition: CaloCluster_v1.cxx:299
ReadCellNoiseFromCool.cell
cell
Definition: ReadCellNoiseFromCool.py:53
CaloRecGPU::ClusterTag::secondary_cluster_index
constexpr int32_t secondary_cluster_index() const
Definition: TagDefinitions.h:253
CaloRecGPU::ClusterTag::is_shared_between_clusters
constexpr bool is_shared_between_clusters() const
Definition: TagDefinitions.h:273
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:70
SG::VarHandleBase::name
const std::string & name() const
Return the StoreGate ID for the referenced object.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleBase.cxx:75
xAOD::CaloCluster_v1::calE
flt_t calE() const
Geet Energy in signal state CALIBRATED.
mergePhysValFiles.start
start
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:14
xAOD::CaloCluster_v1::calEta
flt_t calEta() const
Get in signal state CALIBRATED.
BasicGPUToAthenaImporter::m_clusterSizeString
Gaudi::Property< std::string > m_clusterSizeString
Cluster size. Should be set accordingly to the threshold.
Definition: BasicGPUToAthenaImporter.h:65
CaloCellContainer::isOrdered
bool isOrdered() const
tell wether container is ordered
Definition: CaloCellContainer.h:293
BasicGPUToAthenaImporter::convert
virtual StatusCode convert(const EventContext &ctx, const CaloRecGPU::ConstantDataHolder &constant_data, CaloRecGPU::EventDataHolder &event_data, xAOD::CaloClusterContainer *cluster_collection) const override
Fill the @xAODCaloClusterContainer with the relevant information.
Definition: BasicGPUToAthenaImporter.cxx:92
BasicGPUToAthenaImporter.h
BasicGPUToAthenaImporter::m_keepGPUData
Gaudi::Property< bool > m_keepGPUData
If true, do not delete the GPU data representation.
Definition: BasicGPUToAthenaImporter.h:51
xAOD::CaloCluster_v1::calM
flt_t calM() const
Get mass in signal state CALIBRATED.
CaloGPUTimed
Base class to provide some basic common infrastructure for timing measurements...
Definition: CaloGPUTimed.h:25
xAOD::CaloCluster
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
Definition: Event/xAOD/xAODCaloEvent/xAODCaloEvent/CaloCluster.h:19
CaloDetDescrManager.h
Definition of CaloDetDescrManager.
CaloRecGPU::ClusterTag
Definition: TagDefinitions.h:222
mergePhysValFiles.end
end
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:93
AthCommonDataStore< AthCommonMsg< AlgTool > >::detStore
const ServiceHandle< StoreGateSvc > & detStore() const
The standard StoreGateSvc/DetectorStore Returns (kind of) a pointer to the StoreGateSvc.
Definition: AthCommonDataStore.h:95
BasicGPUToAthenaImporter::m_clusterSize
xAOD::CaloCluster::ClusterSize m_clusterSize
Definition: BasicGPUToAthenaImporter.h:67
CRGPU_CHEAP_STRING_TO_ENUM
#define CRGPU_CHEAP_STRING_TO_ENUM(VAR, PREFIX, ONE,...)
Checks a string variable, VAR, for matching enum identifiers (ONE and the remaining variadic argument...
Definition: MacroHelpers.h:146
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
CaloRecGPU::ClusterTag::cluster_index
constexpr int32_t cluster_index() const
Definition: TagDefinitions.h:243
xAOD::CaloCluster_v1::setE
void setE(flt_t)
Definition: CaloCluster_v1.cxx:375
BasicGPUToAthenaImporter::m_cellsKey
SG::ReadHandleKey< CaloCellContainer > m_cellsKey
vector of names of the cell containers to use as input.
Definition: BasicGPUToAthenaImporter.h:62
xAOD::CaloCluster_v1
Description of a calorimeter cluster.
Definition: CaloCluster_v1.h:59
python.handimod.now
now
Definition: handimod.py:675
CaloRecGPU::EventDataHolder
Definition: DataHolders.h:35
xAOD::CaloCluster_v1::setRawE
void setRawE(flt_t)
Set Energy for signal state UNCALIBRATED.
Definition: CaloCluster_v1.cxx:284
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
lumiFormat.i
int i
Definition: lumiFormat.py:92
BasicGPUToAthenaImporter::m_missingCellsToFill
Gaudi::Property< std::vector< int > > m_missingCellsToFill
Cell indices to fill as disabled cells (useful if the cell vector is always missing the same cells).
Definition: BasicGPUToAthenaImporter.h:71
CRGPU_RECURSIVE_MACRO
#define CRGPU_RECURSIVE_MACRO(...)
Expands recursive macros.
Definition: MacroHelpers.h:68
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
BasicGPUToAthenaImporter::BasicGPUToAthenaImporter
BasicGPUToAthenaImporter(const std::string &type, const std::string &name, const IInterface *parent)
Definition: BasicGPUToAthenaImporter.cxx:25
CaloGPUTimed::print_times
void print_times(const std::string &header, const size_t time_size) const
Definition: CaloGPUTimed.h:138
test_pyathena.parent
parent
Definition: test_pyathena.py:15
xAOD::CaloCluster_v1::setRawEta
void setRawEta(flt_t)
Set for signal state UNCALIBRATED.
Definition: CaloCluster_v1.cxx:289
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
xAOD::CaloCluster_v1::calPhi
flt_t calPhi() const
Get in signal state CALIBRATED.
CaloRecGPU::NCaloCells
constexpr int NCaloCells
Definition: BaseDefinitions.h:13
CaloRecGPU::EventDataHolder::returnToCPU
void returnToCPU(const bool clear_GPU=false, const bool return_cells=true, const bool return_clusters=true, const bool return_moments=true)
SG::VarHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:103
BasicGPUToAthenaImporter::finalize
virtual StatusCode finalize() override
Definition: BasicGPUToAthenaImporter.cxx:327
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
SG::ReadHandle::isValid
virtual bool isValid() override final
Can the handle be successfully dereferenced?
MacroHelpers.h
BasicGPUToAthenaImporter::m_calo_id
const CaloCell_ID * m_calo_id
Pointer to Calo ID Helper.
Definition: BasicGPUToAthenaImporter.h:76
python.EventInfoMgtInit.release
release
Definition: EventInfoMgtInit.py:24
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:192
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
errorcheck.h
Helpers for checking error return status codes and reporting errors.
CaloRecGPU::ClusterTag::is_part_of_cluster
constexpr bool is_part_of_cluster() const
Definition: TagDefinitions.h:233
DataVector::end
const_iterator end() const noexcept
Return a const_iterator pointing past the end of the collection.
BasicGPUToAthenaImporter::initialize
virtual StatusCode initialize() override
Definition: BasicGPUToAthenaImporter.cxx:35
a
TList * a
Definition: liststreamerinfos.cxx:10
CaloCellContainer::isOrderedAndComplete
bool isOrderedAndComplete() const
tell wether container is complete and in order
Definition: CaloCellContainer.h:298
xAOD::CaloCluster_v1::addCellLink
void addCellLink(CaloClusterCellLink *CCCL)
Definition: CaloCluster_v1.h:721
CaloCell
Data object for each calorimeter readout cell.
Definition: CaloCell.h:57
xAOD::CaloCluster_v1::setClusterSize
void setClusterSize(const ClusterSize)
Get cluster size.
Definition: CaloCluster_v1.cxx:369
CaloRecGPU::EventDataHolder::m_clusters
CaloRecGPU::Helpers::CUDA_pinned_CPU_object< CaloRecGPU::ClusterInfoArr > m_clusters
Definition: DataHolders.h:76
python.CaloScaleNoiseConfig.str
str
Definition: CaloScaleNoiseConfig.py:78
CaloGPUTimed::m_measureTimes
Gaudi::Property< bool > m_measureTimes
If true, times are recorded to the file given by m_timeFileName.
Definition: CaloGPUTimed.h:46
CaloRecGPU::EventDataHolder::m_cell_state
CaloRecGPU::Helpers::CUDA_pinned_CPU_object< CaloRecGPU::CellStateArr > m_cell_state
Definition: DataHolders.h:75
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
CUDAFriendlyClasses.h
if
if(febId1==febId2)
Definition: LArRodBlockPhysicsV0.cxx:569
xAOD::CaloCluster_v1::setPhi
bool setPhi(const CaloSample sampling, const float phi)
Set in a given sampling. Returns false if the sample isn't part of the cluster.
Definition: CaloCluster_v1.cxx:556
CaloRecGPU::ConstantDataHolder
Definition: DataHolders.h:19
CaloClusterKineHelper::calculateKine
static void calculateKine(xAOD::CaloCluster *clu, const bool useweight=true, const bool updateLayers=true, const bool useGPUCriteria=false)
Helper class to calculate cluster kinematics based on cells.
Definition: CaloClusterKineHelper.cxx:223
str
Definition: BTagTrackIpAccessor.cxx:11
xAOD::CaloCluster_v1::setEta
bool setEta(const CaloSample sampling, const float eta)
Set in a given sampling. Returns false if the sample isn't part of the cluster.
Definition: CaloCluster_v1.cxx:541
AthAlgTool
Definition: AthAlgTool.h:26
CaloRecGPU
Definition: BaseDefinitions.h:11
CaloRecGPU::ClusterTag::secondary_cluster_weight
constexpr int32_t secondary_cluster_weight() const
Definition: TagDefinitions.h:263
physval_make_web_display.failed
bool failed
Definition: physval_make_web_display.py:290
DataVector::begin
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
xAOD::CaloCluster_v1::setRawPhi
void setRawPhi(flt_t)
Set for signal state UNCALIBRATED.
Definition: CaloCluster_v1.cxx:294