ATLAS Offline Software
BasicEventDataGPUExporter.cxx
Go to the documentation of this file.
1 //
2 // Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 //
4 // Dear emacs, this is -*- c++ -*-
5 //
6 
8 
10 
13 #include "StoreGate/DataHandle.h"
15 #include "TileEvent/TileCell.h"
16 
17 #include "boost/chrono/chrono.hpp"
18 #include "boost/chrono/thread_clock.hpp"
19 
20 using namespace CaloRecGPU;
21 
22 BasicEventDataGPUExporter::BasicEventDataGPUExporter(const std::string & type, const std::string & name, const IInterface * parent):
24  CaloGPUTimed(this)
25 {
26  declareInterface<ICaloClusterGPUInputTransformer> (this);
27 }
28 
30 {
31 
32  //ATH_CHECK(m_noiseCDOKey.initialize());
33  //For Two Gaussian Noise comparisons.
34 
36 
37  ATH_CHECK( detStore()->retrieve(m_calo_id, "CaloCell_ID") );
38 
39  return StatusCode::SUCCESS;
40 }
41 
43  const ConstantDataHolder & /*cd*/,
44  const xAOD::CaloClusterContainer * cluster_collection,
45  EventDataHolder & ed) const
46 {
47  using clock_type = boost::chrono::thread_clock;
48  auto time_cast = [](const auto & before, const auto & after)
49  {
50  return boost::chrono::duration_cast<boost::chrono::microseconds>(after - before).count();
51  };
52 
53  const auto start = clock_type::now();
54 
55  ed.m_cell_info.allocate();
56 
57  SG::ReadHandle<CaloCellContainer> cell_collection(m_cellsKey, ctx);
58  if ( !cell_collection.isValid() )
59  {
60  ATH_MSG_ERROR( " Cannot retrieve CaloCellContainer: " << cell_collection.name() );
61  return StatusCode::FAILURE;
62  }
63 
64  /*
65  SG::ReadCondHandle<CaloNoise> noise_handle(m_noiseCDOKey, ctx);
66  const CaloNoise * noise_tool = *noise_handle;
67  //For Two Gaussian Noise comparisons.
68  */
69 
70  auto export_cell = [&](const CaloCell * cell, const int cell_index)
71  {
72  const float energy = cell->energy();
73  const unsigned int gain = GainConversion::from_standard_gain(cell->gain());
74  ed.m_cell_info->energy[cell_index] = energy;
75  ed.m_cell_info->gain[cell_index] = gain;
76  ed.m_cell_info->time[cell_index] = cell->time();
77 
78 
79  if (CaloRecGPU::GeometryArr::is_tile(cell_index))
80  {
81  const TileCell * tile_cell = (TileCell *) cell;
82 
83  ed.m_cell_info->qualityProvenance[cell_index] = QualityProvenance{tile_cell->qual1(),
84  tile_cell->qual2(),
85  tile_cell->qbit1(),
86  tile_cell->qbit2()};
87 
88  /*
89  //For Two Gaussian Noise comparisons.
90 
91  const float original_snr = noise_tool->getEffectiveSigma(cell->ID(),cell->gain(),cell->energy());
92  const float our_snr = cd.m_cell_noise->get_double_gaussian_noise(cell_index, gain, energy);
93  if (our_snr != original_snr)
94  {
95  std::cout << "---------------------------------------- ERR: " << cell_index << " " << our_snr << " " << original_snr << " " << our_snr - original_snr << std::endl;
96  }
97  */
98  }
99  else
100  {
101  ed.m_cell_info->qualityProvenance[cell_index] = QualityProvenance{cell->quality(), cell->provenance()};
102  }
103 
104  };
105 
106  //For Two Gaussian Noise comparisons.
107  //std::cout << "-------------------------------------------------------------------------- START" << std::endl;
108 
109  if (cell_collection->isOrderedAndComplete())
110  //Fast path: cell indices within the collection and identifierHashes match!
111  {
112  ATH_MSG_DEBUG("Taking quick path on event " << ctx.evt());
113  int cell_index = 0;
114  for (CaloCellContainer::const_iterator iCells = cell_collection->begin(); iCells != cell_collection->end(); ++iCells, ++cell_index)
115  {
116  const CaloCell * cell = (*iCells);
117  export_cell(cell, cell_index);
118  }
119  }
120  else if (cell_collection->isOrdered() && m_missingCellsToFill.size() > 0)
121  //Remediated: we know the missing cells, force them to be invalid.
122  //(Tests so far, on samples both oldish and newish, had 186986 and 187352 missing...)
123  {
124  ATH_MSG_DEBUG("Taking remediated fast path on event " << ctx.evt());
125  int cell_index = 0;
126  size_t missing_cell_count = 0;
127  for (CaloCellContainer::const_iterator iCells = cell_collection->begin(); iCells != cell_collection->end(); ++iCells, ++cell_index)
128  {
129  const CaloCell * cell = (*iCells);
130 
131  if (missing_cell_count < m_missingCellsToFill.size() && cell_index == m_missingCellsToFill[missing_cell_count])
132  {
133  --iCells;
134  ed.m_cell_info->gain[cell_index] = GainConversion::invalid_gain();
135  ++missing_cell_count;
136  continue;
137  }
138  else
139  {
140  export_cell(cell, cell_index);
141  }
142  }
143  }
144  else
145  //Slow path: be careful.
146  {
147  /*
148  std::vector<bool> has_cell(NCaloCells, false);
149  // */
150  ATH_MSG_DEBUG("Taking slow path on event " << ctx.evt());
151  for (int cell_index = 0; cell_index < NCaloCells; ++cell_index)
152  {
153  ed.m_cell_info->gain[cell_index] = GainConversion::invalid_gain();
154  }
155 
156  for (CaloCellContainer::const_iterator iCells = cell_collection->begin(); iCells != cell_collection->end(); ++iCells)
157  {
158  const CaloCell * cell = (*iCells);
159 
160  //const int cell_index = m_calo_id->calo_cell_hash(cell->ID());
161  const int cell_index = cell->caloDDE()->calo_hash();
162  //See calodde
163 
164  export_cell(cell, cell_index);
165 
166  /*
167  has_cell[cell_index] = true;
168  // */
169 
170  }
171 
172  /*
173  //Useful output for detecting missing cells in the calorimeter collection...
174 
175  for (size_t i = 0; i < has_cell.size(); ++i)
176  {
177  if (!has_cell[i])
178  {
179  const auto identifier = m_calo_id->cell_id(i);
180  const auto sampling = m_calo_id->calo_sample(m_calo_id->cell_id((IdentifierHash) i));
181  std::cout << i << " " << sampling << std::endl;
182  }
183  }
184  // */
185  }
186 
187  //For Two Gaussian Noise comparisons.
188  //std::cout << "-------------------------------------------------------------------------- END" << std::endl;
189 
190  const auto post_cells = clock_type::now();
191 
192  ed.m_clusters.allocate();
193  ed.m_cell_state.allocate();
194 
195  if (cluster_collection->size() > 0)
196  {
197 
198  for (int i = 0; i < NCaloCells; ++i)
199  {
200  ed.m_cell_state->clusterTag[i] = ClusterTag::make_invalid_tag();
201  }
202 
203  const auto cluster_end = cluster_collection->end();
204  auto cluster_iter = cluster_collection->begin();
205 
206  for (int cluster_number = 0; cluster_iter != cluster_end; ++cluster_iter, ++cluster_number )
207  {
208  const xAOD::CaloCluster * cluster = (*cluster_iter);
209  const CaloClusterCellLink * cell_links = cluster->getCellLinks();
210 
211  ed.m_clusters->clusterEnergy[cluster_number] = cluster->e();
212  ed.m_clusters->clusterEt[cluster_number] = cluster->et();
213  ed.m_clusters->clusterEta[cluster_number] = cluster->eta();
214  ed.m_clusters->clusterPhi[cluster_number] = cluster->phi();
215 
216  const int seed_cell_index = m_calo_id->calo_cell_hash(cluster->cell_begin()->ID());
217 
218  ed.m_clusters->seedCellID[cluster_number] = seed_cell_index;
219 
220  for (auto it = cell_links->begin(); it != cell_links->end(); ++it)
221  {
223  {
224  const int cell_ID = m_calo_id->calo_cell_hash(it->ID());
225  const float weight = it.weight();
226 
227  uint32_t weight_as_int = 0;
228  std::memcpy(&weight_as_int, &weight, sizeof(float));
229  //On the platforms we expect to be running this, it should be fine.
230  //Still UB.
231  //With C++20, we could do that bit-cast thing.
232 
233  if (weight_as_int == 0)
234  {
235  weight_as_int = 1;
236  //Subnormal,
237  //but just to distinguish from
238  //a non-shared cluster.
239  }
240 
241  const ClusterTag other_tag = ed.m_cell_state->clusterTag[cell_ID];
242 
243  const int other_index = other_tag.is_part_of_cluster() ? other_tag.cluster_index() : -1;
244 
245  if (other_index < 0)
246  {
247  if (weight < 0.5f)
248  {
249  ed.m_cell_state->clusterTag[cell_ID] = ClusterTag::make_tag(cluster_number, weight_as_int, 0);
250  }
251  else
252  {
253  ed.m_cell_state->clusterTag[cell_ID] = ClusterTag::make_tag(cluster_number);
254  }
255  }
256  else if (weight > 0.5f)
257  {
258  ed.m_cell_state->clusterTag[cell_ID] = ClusterTag::make_tag(cluster_number, other_tag.secondary_cluster_weight(), other_index);
259  }
260  else if (weight == 0.5f)
261  //Unlikely, but...
262  {
263  const int max_cluster = cluster_number > other_index ? cluster_number : other_index;
264  const int min_cluster = cluster_number > other_index ? other_index : cluster_number;
265  ed.m_cell_state->clusterTag[cell_ID] = ClusterTag::make_tag(max_cluster, weight_as_int, min_cluster);
266  }
267  else /*if (weight < 0.5f)*/
268  {
269  ed.m_cell_state->clusterTag[cell_ID] = ClusterTag::make_tag(other_index, weight_as_int, cluster_number);
270  }
271  }
272  else
273  {
274  ed.m_cell_state->clusterTag[m_calo_id->calo_cell_hash(it->ID())] = ClusterTag::make_tag(cluster_number);
275  }
276  }
277  }
278 
279  ed.m_clusters->number = cluster_collection->size();
280  }
281 
282  const auto post_clusters = clock_type::now();
283 
284  const bool has_cluster_info = cluster_collection->size() > 0;
285 
286  ed.sendToGPU(!m_keepCPUData, has_cluster_info, has_cluster_info, false);
287 
288  const auto post_send = clock_type::now();
289 
290  if (m_measureTimes)
291  {
292  record_times(ctx.evt(),
293  time_cast(start, post_cells),
294  time_cast(post_cells, post_clusters),
295  time_cast(post_clusters, post_send)
296  );
297  }
298 
299  return StatusCode::SUCCESS;
300 
301 }
302 
303 
305 {
306 
307  if (m_measureTimes)
308  {
309  print_times("Cells Clusters Transfer_to_GPU", 3);
310  }
311  return StatusCode::SUCCESS;
312 }
python.PyKernel.retrieve
def retrieve(aClass, aKey=None)
Definition: PyKernel.py:110
xAOD::CaloCluster_v1::phi
virtual double phi() const
The azimuthal angle ( ) of the particle.
Definition: CaloCluster_v1.cxx:256
TileCell
Definition: TileCell.h:57
BasicEventDataGPUExporter::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: BasicEventDataGPUExporter.h:68
python.CaloRecoConfig.f
f
Definition: CaloRecoConfig.py:127
xAOD::CaloCluster_v1::cell_begin
const_cell_iterator cell_begin() const
Iterator of the underlying CaloClusterCellLink (const version)
Definition: CaloCluster_v1.h:812
DataModel_detail::const_iterator
Const iterator class for DataVector/DataList.
Definition: DVLIterator.h:82
ReadCellNoiseFromCool.cell
cell
Definition: ReadCellNoiseFromCool.py:53
BasicEventDataGPUExporter.h
BasicEventDataGPUExporter::m_cellsKey
SG::ReadHandleKey< CaloCellContainer > m_cellsKey
vector of names of the cell containers to use as input.
Definition: BasicEventDataGPUExporter.h:57
xAOD::uint32_t
setEventNumber uint32_t
Definition: EventInfo_v1.cxx:127
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
mergePhysValFiles.start
start
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:14
CaloCondBlobAlgs_fillNoiseFromASCII.gain
gain
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:110
skel.it
it
Definition: skel.GENtoEVGEN.py:423
CaloCellContainer::isOrdered
bool isOrdered() const
tell wether container is ordered
Definition: CaloCellContainer.h:293
xAOD::CaloCluster_v1::et
double et() const
Definition: CaloCluster_v1.h:856
DataHandle.h
BasicEventDataGPUExporter::m_considerSharedCells
Gaudi::Property< bool > m_considerSharedCells
If true, into account the possibility of a cell being shared between clusters.
Definition: BasicEventDataGPUExporter.h:64
CaloGPUTimed
Base class to provide some basic common infrastructure for timing measurements...
Definition: CaloGPUTimed.h:25
CaloDetDescrManager.h
Definition of CaloDetDescrManager.
CaloRecGPU::ClusterTag
Definition: TagDefinitions.h:222
CaloCell_ID.h
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
BasicEventDataGPUExporter::finalize
virtual StatusCode finalize() override
Definition: BasicEventDataGPUExporter.cxx:304
dqt_zlumi_pandas.weight
int weight
Definition: dqt_zlumi_pandas.py:200
BasicEventDataGPUExporter::BasicEventDataGPUExporter
BasicEventDataGPUExporter(const std::string &type, const std::string &name, const IInterface *parent)
Definition: BasicEventDataGPUExporter.cxx:22
CaloRecGPU::ClusterTag::cluster_index
constexpr int32_t cluster_index() const
Definition: TagDefinitions.h:243
TileCell::qual2
uint8_t qual2(void) const
get quality of second PMT (data member)
Definition: TileCell.h:206
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
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
ParticleGun_FastCalo_ChargeFlip_Config.energy
energy
Definition: ParticleGun_FastCalo_ChargeFlip_Config.py:78
BasicEventDataGPUExporter::m_calo_id
const CaloCell_ID * m_calo_id
Pointer to Calo ID Helper.
Definition: BasicEventDataGPUExporter.h:73
xAOD::CaloCluster_v1::eta
virtual double eta() const
The pseudorapidity ( ) of the particle.
Definition: CaloCluster_v1.cxx:251
lumiFormat.i
int i
Definition: lumiFormat.py:92
CaloRecGPU::GeometryArr::is_tile
constexpr static bool is_tile(const int cell)
Definition: ConstantInfoDefinitions.h:246
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
TileCell.h
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
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
TileCell::qbit1
uint8_t qbit1(void) const
get quality bits of first PMT (data member)
Definition: TileCell.h:209
CaloRecGPU::NCaloCells
constexpr int NCaloCells
Definition: BaseDefinitions.h:13
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
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
xAOD::CaloCluster_v1::getCellLinks
const CaloClusterCellLink * getCellLinks() const
Get a pointer to the CaloClusterCellLink object (const version)
Definition: CaloCluster_v1.cxx:905
SG::ReadHandle::isValid
virtual bool isValid() override final
Can the handle be successfully dereferenced?
BasicEventDataGPUExporter::m_keepCPUData
Gaudi::Property< bool > m_keepCPUData
If true, do not delete the CPU version of the GPU-friendly data representation.
Definition: BasicEventDataGPUExporter.h:52
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:192
errorcheck.h
Helpers for checking error return status codes and reporting errors.
CaloCell::ID
Identifier ID() const
get ID (from cached data member) non-virtual and inline for fast access
Definition: CaloCell.h:279
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.
BasicEventDataGPUExporter::convert
virtual StatusCode convert(const EventContext &ctx, const CaloRecGPU::ConstantDataHolder &constant_data, const xAOD::CaloClusterContainer *cluster_collection, CaloRecGPU::EventDataHolder &event_data) const override
Fill the CaloRecGPU::EventDataHolder with the relevant information.
Definition: BasicEventDataGPUExporter.cxx:42
BasicEventDataGPUExporter::initialize
virtual StatusCode initialize() override
Definition: BasicEventDataGPUExporter.cxx:29
TileCell::qbit2
uint8_t qbit2(void) const
get quality bits of second PMT (data member)
Definition: TileCell.h:212
CaloCellContainer::isOrderedAndComplete
bool isOrderedAndComplete() const
tell wether container is complete and in order
Definition: CaloCellContainer.h:298
CaloCell
Data object for each calorimeter readout cell.
Definition: CaloCell.h:57
CaloRecGPU::EventDataHolder::m_clusters
CaloRecGPU::Helpers::CUDA_pinned_CPU_object< CaloRecGPU::ClusterInfoArr > m_clusters
Definition: DataHolders.h:76
CaloGPUTimed::record_times
void record_times(const size_t event_num, const std::vector< size_t > &times) const
Definition: CaloGPUTimed.h:84
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
CaloRecGPU::QualityProvenance
Definition: EventInfoDefinitions.h:116
CUDAFriendlyClasses.h
CaloRecGPU::ConstantDataHolder
Definition: DataHolders.h:19
CaloRecGPU::EventDataHolder::sendToGPU
void sendToGPU(const bool clear_CPU=false, const bool has_state=false, const bool has_clusters=false, const bool has_moments=false)
TileCell::qual1
uint8_t qual1(void) const
get quality of first PMT (data member)
Definition: TileCell.h:203
AthAlgTool
Definition: AthAlgTool.h:26
CaloRecGPU
Definition: BaseDefinitions.h:11
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
xAOD::CaloCluster_v1::e
virtual double e() const
The total energy of the particle.
Definition: CaloCluster_v1.cxx:265
CaloRecGPU::ClusterTag::secondary_cluster_weight
constexpr int32_t secondary_cluster_weight() const
Definition: TagDefinitions.h:263
CaloRecGPU::EventDataHolder::m_cell_info
CaloRecGPU::Helpers::CUDA_pinned_CPU_object< CaloRecGPU::CellInfoArr > m_cell_info
Definition: DataHolders.h:74
DataVector::begin
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.