ATLAS Offline Software
Loading...
Searching...
No Matches
CaloRecGPU::EventDataHolder Class Reference

Holds the mutable per-event information (clusters and cells) and provides utilities to convert between this representation and the Athena data structures (i. More...

#include <DataHolders.h>

Collaboration diagram for CaloRecGPU::EventDataHolder:

Public Member Functions

void importCells (const void *cell_collection, const std::vector< int > &extra_cells_to_fill={})
 We are using a void* for API to make this able to compile on the GPU without Athena-specific dependencies.
void importClusters (const void *cluster_collection, const MomentsOptionsArray &moments_to_add, const bool output_tags=true, const bool consider_shared_cells=true, const bool output_moments=false, const bool output_extra_moments=false, const std::vector< int > &extra_cells_to_fill={})
 We are using a void* for API to make this able to compile on the GPU without Athena-specific dependencies.
void sendToGPU (const MomentsOptionsArray &moments_to_add, const bool full_copy=false, const bool clear_CPU=false, const bool synchronize=false, CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream={})
 This function is asynchronous if clear_CPU and synchronize are false.
void returnToCPU (const MomentsOptionsArray &moments_to_add, const bool full_copy=false, const bool clear_GPU=false, const bool synchronize=false, CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream={}, const bool also_return_cells=false)
 moments_to_add specifies which moments we will transfer from the GPU.
void exportClusters (void *cluster_collection, const void *cell_collection_link, const MomentsOptionsArray &moments_to_add, const bool sort_clusters=true, const bool save_uncalibrated=true, const bool output_extra_moments=false, const std::vector< int > &extra_cells_to_fill={}, size_t *time_measurements=nullptr)
 We are using a void* for API to make this able to compile on the GPU without Athena-specific dependencies.
void returnAndExportClusters (void *cluster_collection, const void *cell_collection_link, const MomentsOptionsArray &moments_to_add, const bool sort_clusters=true, const bool save_uncalibrated=true, const bool output_extra_moments=false, const std::vector< int > &extra_cells_to_fill={}, size_t *time_measurements=nullptr, CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream={})
 We are using a void* for API to make this able to compile on the GPU without Athena-specific dependencies.
void allocate (const bool also_GPU=true)
void clear_GPU ()

Public Attributes

CaloRecGPU::Helpers::CUDA_pinned_CPU_object< CaloRecGPU::CellInfoArrm_cell_info
CaloRecGPU::Helpers::CUDA_pinned_CPU_object< CaloRecGPU::ClusterInfoArrm_clusters
CaloRecGPU::Helpers::CUDA_object< CaloRecGPU::CellInfoArrm_cell_info_dev
CaloRecGPU::Helpers::CUDA_object< CaloRecGPU::ClusterInfoArrm_clusters_dev

Detailed Description

Holds the mutable per-event information (clusters and cells) and provides utilities to convert between this representation and the Athena data structures (i.

e. xAOD::CaloClusterContainer).

Definition at line 72 of file DataHolders.h.

Member Function Documentation

◆ allocate()

void CaloRecGPU::EventDataHolder::allocate ( const bool also_GPU = true)

Definition at line 1347 of file DataHolders.cxx.

1348{
1349 m_cell_info.allocate();
1350 m_clusters.allocate();
1351
1352 if (also_GPU)
1353 {
1354 m_cell_info_dev.allocate();
1355 m_clusters_dev.allocate();
1356 }
1357}
CaloRecGPU::Helpers::CUDA_pinned_CPU_object< CaloRecGPU::CellInfoArr > m_cell_info
CaloRecGPU::Helpers::CUDA_object< CaloRecGPU::CellInfoArr > m_cell_info_dev
CaloRecGPU::Helpers::CUDA_pinned_CPU_object< CaloRecGPU::ClusterInfoArr > m_clusters
CaloRecGPU::Helpers::CUDA_object< CaloRecGPU::ClusterInfoArr > m_clusters_dev

◆ clear_GPU()

void CaloRecGPU::EventDataHolder::clear_GPU ( )

Definition at line 1359 of file DataHolders.cxx.

1360{
1361 m_cell_info_dev.clear();
1362 m_clusters_dev.clear();
1363}

◆ exportClusters()

void CaloRecGPU::EventDataHolder::exportClusters ( void * cluster_collection,
const void * cell_collection_link,
const MomentsOptionsArray & moments_to_add,
const bool sort_clusters = true,
const bool save_uncalibrated = true,
const bool output_extra_moments = false,
const std::vector< int > & extra_cells_to_fill = {},
size_t * time_measurements = nullptr )

We are using a void* for API to make this able to compile on the GPU without Athena-specific dependencies.

The user should pass a xAOD::CaloClusterContainer * and a const DataLink<CaloCellContainer> *. moments_to_add specifies which moments we will import. If sort_clusters is true, the clusters will be sorted based on the transverse energy, otherwise the same order will be kept. If save_uncalibrated, the basic cluster information will be saved as raw. If time_measurements is not null, separate time measurements for the five stages (cell link creation, cell assignment, sorting, basic info filling and moments filling) will be stored.

Definition at line 1214 of file DataHolders.cxx.

1222{
1223 using clock_type = boost::chrono::thread_clock;
1224 auto time_cast = [](const auto & before, const auto & after)
1225 {
1226 return boost::chrono::duration_cast<boost::chrono::microseconds>(after - before).count();
1227 };
1228
1229 xAOD::CaloClusterContainer * cluster_collection = static_cast<xAOD::CaloClusterContainer *>(p_cluster_collection);
1230 const DataLink<CaloCellContainer> & cell_collection_link = *(static_cast<const DataLink<CaloCellContainer> *>(p_cell_collection_link));
1231
1232 const auto start = clock_type::now();
1233
1234 std::vector<std::unique_ptr<CaloClusterCellLink>> cell_links;
1235
1236 export_cluster_initialize_links(m_clusters, cell_links, cell_collection_link, false);
1237
1238 const auto after_link_creation = clock_type::now();
1239
1240 export_cluster_process_cells(m_clusters, m_cell_info, cell_links, extra_cells_to_fill);
1241
1242 const auto after_cell_processing = clock_type::now();
1243
1244 std::vector<int> cluster_order;
1245
1246 export_cluster_sort(m_clusters, cluster_order, sort_clusters);
1247
1248 const auto after_sorting = clock_type::now();
1249
1250 export_cluster_fill_cells_and_basic_info(m_clusters, cluster_collection, cell_links, cluster_order, save_uncalibrated);
1251
1252 const auto after_basic_info = clock_type::now();
1253
1254 export_cluster_fill_moments(m_clusters, cluster_collection, cluster_order, moments_to_add, output_extra_moments);
1255
1256 const auto after_moments = clock_type::now();
1257
1258 if (time_measurements)
1259 {
1260 time_measurements[0] = time_cast(start, after_link_creation);
1261 time_measurements[1] = time_cast(after_link_creation, after_cell_processing);
1262 time_measurements[2] = time_cast(after_cell_processing, after_sorting);
1263 time_measurements[3] = time_cast(after_sorting, after_basic_info);
1264 time_measurements[4] = time_cast(after_basic_info, after_moments);
1265 }
1266}
static void export_cluster_fill_moments(const ClusterInfoArr *clusters, xAOD::CaloClusterContainer *cluster_collection, std::vector< int > &cluster_order, const MomentsOptionsArray &moments_to_add, const bool output_extra_moments)
static void export_cluster_fill_cells_and_basic_info(const ClusterInfoArr *clusters, xAOD::CaloClusterContainer *cluster_collection, std::vector< std::unique_ptr< CaloClusterCellLink > > &cell_links, std::vector< int > &cluster_order, const bool save_uncalibrated)
static void export_cluster_sort(const ClusterInfoArr *clusters, std::vector< int > &cluster_order, const bool really_sort)
static void export_cluster_process_cells(const ClusterInfoArr *clusters, const CellInfoArr *cells, std::vector< std::unique_ptr< CaloClusterCellLink > > &cell_links, const std::vector< int > &extra_cells_to_fill)
static void export_cluster_initialize_links(const ClusterInfoArr *clusters, std::vector< std::unique_ptr< CaloClusterCellLink > > &cell_links, const DataLink< CaloCellContainer > &cell_collection_link, const bool skip_validation)
CaloClusterContainer_v1 CaloClusterContainer
Define the latest version of the calorimeter cluster container.

◆ importCells()

void CaloRecGPU::EventDataHolder::importCells ( const void * cell_collection,
const std::vector< int > & extra_cells_to_fill = {} )

We are using a void* for API to make this able to compile on the GPU without Athena-specific dependencies.

The user should pass a const CaloCellCollection *.

Definition at line 210 of file DataHolders.cxx.

211{
212 const CaloCellContainer * cell_collection = static_cast<const CaloCellContainer *>(p_cell_collection);
213
214 m_cell_info.allocate();
215
216 auto export_cell = [&](const CaloCell * cell, const int hash_ID, const int index_inside)
217 {
218 const float energy = cell->energy();
219 const unsigned int gain = GainConversion::from_standard_gain(cell->gain());
220 m_cell_info->energy[index_inside] = energy;
221 m_cell_info->gain[index_inside] = gain;
222 m_cell_info->time[index_inside] = cell->time();
223
225 {
226 const TileCell * tile_cell = static_cast<const TileCell *>(cell);
227
228 m_cell_info->qualityProvenance[index_inside] = QualityProvenance{tile_cell->qual1(),
229 tile_cell->qual2(),
230 tile_cell->qbit1(),
231 tile_cell->qbit2()};
232 }
233 else
234 {
235 m_cell_info->qualityProvenance[index_inside] = QualityProvenance{cell->quality(), cell->provenance()};
236 }
237
238 m_cell_info->hashID[index_inside] = hash_ID;
239 m_cell_info->hashIDToCollection[hash_ID] = index_inside;
240 };
241
242 if (cell_collection->isOrderedAndComplete())
243 //Fast path: cell indices within the collection and identifierHashes match!
244 {
245 int cell_index = 0;
246 for (auto cell_it = cell_collection->begin(); cell_it != cell_collection->end(); ++cell_it, ++cell_index)
247 {
248 const CaloCell * cell = (*cell_it);
249 export_cell(cell, cell_index, cell_index);
250 }
251
253 m_cell_info->complete = true;
254 m_cell_info->all_cells_valid = true;
255 }
256 else if (cell_collection->isOrdered() && extra_cells_to_fill.size() > 0)
257 //Remediated: we know the missing cells, force them to be invalid.
258 //(Tests so far, on samples both oldish and newish, had 186986 and 187352 missing...)
259 {
260 int cell_index = 0;
261 size_t missing_cell_count = 0;
262
263 for (CaloCellContainer::const_iterator cell_it = cell_collection->begin(); cell_it != cell_collection->end(); ++cell_it, ++cell_index)
264 {
265 const CaloCell * cell = (*cell_it);
266
267 if (missing_cell_count < extra_cells_to_fill.size() && cell_index == extra_cells_to_fill[missing_cell_count])
268 {
269 --cell_it;
270 m_cell_info->gain[cell_index] = GainConversion::invalid_gain();
271 ++missing_cell_count;
272 m_cell_info->hashID[cell_index] = cell_index;
273 m_cell_info->hashIDToCollection[cell_index] = -1;
274 continue;
275 }
276 else
277 {
278 export_cell(cell, cell_index, cell_index);
279 }
280 }
281
283 m_cell_info->complete = true;
284 m_cell_info->all_cells_valid = false;
285 }
286 else
287 {
288 for (unsigned int cell_index = 0; cell_index < CaloRecGPU::NCaloCells; ++cell_index)
289 {
290 m_cell_info->hashIDToCollection[cell_index] = -1;
291 }
292
293 int index_inside = 0;
294
295 const auto cells_end = cell_collection->end();
296
297 for (CaloCellContainer::const_iterator cell_it = cell_collection->begin(); cell_it != cells_end; ++cell_it, ++index_inside)
298 {
299 CaloPrefetch::nextDDE(cell_it, cells_end, 2);
300 //May be adjusted later...
301
302 const CaloCell * cell = (*cell_it);
303
304 const int cell_index = cell->caloDDE()->calo_hash();
305 export_cell(cell, cell_index, index_inside);
306 }
307
308 m_cell_info->number = cell_collection->size();
309 m_cell_info->complete = false;
310 m_cell_info->all_cells_valid = true;
311 }
312}
bool isOrdered() const
tell wether container is ordered
bool isOrderedAndComplete() const
tell wether container is complete and in order
static constexpr GainType from_standard_gain(const int gain)
static constexpr GainType invalid_gain()
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
const_iterator end() const noexcept
Return a const_iterator pointing past the end of the collection.
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
uint8_t qual1(void) const
get quality of first PMT (data member)
Definition TileCell.h:197
uint8_t qbit2(void) const
get quality bits of second PMT (data member)
Definition TileCell.h:206
uint8_t qual2(void) const
get quality of second PMT (data member)
Definition TileCell.h:200
uint8_t qbit1(void) const
get quality bits of first PMT (data member)
Definition TileCell.h:203
void nextDDE(Iter iter, Iter endIter)
Prefetch next CaloDDE.
constexpr int NCaloCells
static constexpr bool is_tile(const int cell)

◆ importClusters()

void CaloRecGPU::EventDataHolder::importClusters ( const void * cluster_collection,
const MomentsOptionsArray & moments_to_add,
const bool output_tags = true,
const bool consider_shared_cells = true,
const bool output_moments = false,
const bool output_extra_moments = false,
const std::vector< int > & extra_cells_to_fill = {} )

We are using a void* for API to make this able to compile on the GPU without Athena-specific dependencies.

The user should pass a const xAOD::CaloClusterContainer *. moments_to_add specifies which moments we will import.

Definition at line 315 of file DataHolders.cxx.

322{
323 const xAOD::CaloClusterContainer * cluster_collection = static_cast<const xAOD::CaloClusterContainer *>(p_cluster_collection);
324
325 m_clusters.allocate();
326
327 if (cluster_collection->size() > 0)
328 {
329 std::vector<int> real_cells_to_fill;
330
331 if (m_cell_info->number == CaloRecGPU::NCaloCells && !m_cell_info->all_cells_valid)
332 {
333 real_cells_to_fill.reserve(extra_cells_to_fill.size());
334
335 for (const int cell : extra_cells_to_fill)
336 {
337 if (m_cell_info->hashIDToCollection[cell] <= 0)
338 {
339 real_cells_to_fill.push_back(cell);
340 }
341 }
342 }
343
344 auto index_to_corrected_index = [&](const int index)
345 {
346 if (m_cell_info->all_cells_valid)
347 {
348 return index;
349 }
350
351 int ret = index;
352
353 for (const int cell : real_cells_to_fill)
354 {
355 ret += (index > cell);
356 }
357
358 return ret;
359 };
360
361 auto get_cell_tag = [&](const int index) -> tag_type &
362 {
363 if (output_tags)
364 {
365 return m_clusters->cells.tags[index];
366 }
367 else
368 {
369 return m_clusters->get_extra_cell_info(index);
370 }
371
372 };
373
374 for (int i = 0; i < CaloRecGPU::NCaloCells; ++i)
375 {
376 get_cell_tag(i) = ClusterTag::make_invalid_tag();
377 }
378
379 if (output_tags)
380 {
382 }
383 else
384 {
385 m_clusters->state = (output_moments ?
388 m_clusters->cellsPrefixSum[0] = 0;
389 }
390
391 m_clusters->has_deleted_clusters = false;
392
393 const auto cluster_end = cluster_collection->end();
394 auto cluster_iter = cluster_collection->begin();
395
396 int overall_cell_index = 0;
397
398 for (int cluster_number = 0; cluster_iter != cluster_end; ++cluster_iter, ++cluster_number)
399 {
400 const xAOD::CaloCluster * cluster = (*cluster_iter);
401 const CaloClusterCellLink * cell_links = cluster->getCellLinks();
402
403 m_clusters->clusterEnergy[cluster_number] = cluster->e();
404 m_clusters->clusterEt[cluster_number] = cluster->et();
405 m_clusters->clusterEta[cluster_number] = cluster->eta();
406 m_clusters->clusterPhi[cluster_number] = cluster->phi();
407
408 const int seed_cell_index = (cluster->cell_begin() != cluster->cell_end() ? cluster->cell_begin().index() : -1);
409
410 if (cluster->cell_begin() == cluster->cell_end())
411 {
412 m_clusters->has_deleted_clusters = true;
413 m_clusters->seedCellIndex[cluster_number] = -1;
414 }
415 else
416 {
417 m_clusters->seedCellIndex[cluster_number] = index_to_corrected_index(seed_cell_index);
418 }
419
420 for (auto it = cell_links->begin(); it != cell_links->end(); ++it)
421 {
422 const int cell_index_in_collection = index_to_corrected_index(it.index());
423 if (consider_shared_cells)
424 {
425 const float weight = it.weight();
426
427 uint32_t weight_as_int = 0;
428 std::memcpy(&weight_as_int, &weight, sizeof(float));
429 //On the platforms we expect to be running this, it should be fine.
430 //Still UB.
431 //With C++20, we could do that bit-cast thing.
432
433 if (weight_as_int == 0)
434 {
435 weight_as_int = 1;
436 //Subnormal,
437 //but just to distinguish from
438 //a non-shared cluster.
439 }
440
441 const ClusterTag other_tag = get_cell_tag(cell_index_in_collection);
442
443 const int other_index = other_tag.is_part_of_cluster() ? other_tag.cluster_index() : -1;
444
445 if (other_index < 0)
446 {
447 if (weight < 0.5f)
448 {
449 get_cell_tag(cell_index_in_collection) = ClusterTag::make_tag(cluster_number, weight_as_int, 0);
450 }
451 else
452 {
453 get_cell_tag(cell_index_in_collection) = ClusterTag::make_tag(cluster_number);
454 }
455 }
456 else if (weight > 0.5f)
457 {
458 get_cell_tag(cell_index_in_collection) = ClusterTag::make_tag(cluster_number, other_tag.secondary_cluster_weight(), other_index);
459 }
460 else if (weight == 0.5f)
461 //Unlikely, but...
462 {
463 const int max_cluster = cluster_number > other_index ? cluster_number : other_index;
464 const int min_cluster = cluster_number > other_index ? other_index : cluster_number;
465 get_cell_tag(cell_index_in_collection) = ClusterTag::make_tag(max_cluster, weight_as_int, min_cluster);
466 }
467 else /*if (weight < 0.5f)*/
468 {
469 get_cell_tag(cell_index_in_collection) = ClusterTag::make_tag(other_index, weight_as_int, cluster_number);
470 }
471
472 //All of this logic assumes a cell is shared by at most two clusters
473 //with weights such that w_1 + w_2 = 1.
474 //This is not necessarily valid with local calibrations.
475
476 }
477 else
478 {
479 get_cell_tag(cell_index_in_collection) = ClusterTag::make_tag(cluster_number);
480 }
481 }
482
483 if (!output_tags)
484 {
485 for (auto it = cell_links->begin(); it != cell_links->end(); ++it, ++overall_cell_index)
486 {
487 m_clusters->cells.indices[overall_cell_index] = index_to_corrected_index(it.index());
488 m_clusters->clusterIndices[overall_cell_index] = cluster_number;
489 m_clusters->cellWeights[overall_cell_index] = it.weight();
490 }
491
492 m_clusters->cellsPrefixSum[cluster_number + 1] = overall_cell_index;
493 }
494
495 if (output_moments)
496 {
497 for (int s = 0; s < NumSamplings; ++s)
498 {
499 m_clusters->moments.nCellSampling[s][cluster_number] = cluster->numberCellsInSampling(static_cast<CaloSampling::CaloSample>(s), false);
500 }
501
502 m_clusters->moments.nExtraCellSampling[cluster_number] = cluster->numberCellsInSampling(CaloSampling::EME2, true);
503
504 for (int s = 0; s < NumSamplings; ++s)
505 {
506 m_clusters->moments.energyPerSample[s][cluster_number] = cluster->eSample(static_cast<CaloSampling::CaloSample>(s));
507 }
508 for (int s = 0; s < NumSamplings; ++s)
509 {
510 m_clusters->moments.maxEPerSample[s][cluster_number] = cluster->energy_max(static_cast<CaloSampling::CaloSample>(s));
511 }
512 for (int s = 0; s < NumSamplings; ++s)
513 {
514 m_clusters->moments.maxEtaPerSample[s][cluster_number] = cluster->etamax(static_cast<CaloSampling::CaloSample>(s));
515 }
516 for (int s = 0; s < NumSamplings; ++s)
517 {
518 m_clusters->moments.maxPhiPerSample[s][cluster_number] = cluster->phimax(static_cast<CaloSampling::CaloSample>(s));
519 }
520 for (int s = 0; s < NumSamplings; ++s)
521 {
522 m_clusters->moments.etaPerSample[s][cluster_number] = cluster->etaSample(static_cast<CaloSampling::CaloSample>(s));
523 }
524 for (int s = 0; s < NumSamplings; ++s)
525 {
526 m_clusters->moments.phiPerSample[s][cluster_number] = cluster->phiSample(static_cast<CaloSampling::CaloSample>(s));
527 }
528
529 m_clusters->moments.time[cluster_number] = cluster->time();
530
531#define CALORECGPU_MOMENTS_INPUT_HELPER(VAR_NAME, PROPER_MOMENT, NORMAL_ASSIGN, IS_CALCULATED, MOMENT_NAME, ...) \
532 CRGPU_CONCAT(CRGPU_CONCAT(CALORECGPU_MOMENTS_INPUT_HELPER_, NORMAL_ASSIGN), IS_CALCULATED) (VAR_NAME, MOMENT_NAME)
533
534#define CALORECGPU_MOMENTS_INPUT_HELPER_11(VAR_NAME, MOMENT_NAME) \
535 if (moments_to_add[xAOD::CaloCluster:: MOMENT_NAME]) \
536 { \
537 m_clusters->moments. VAR_NAME [cluster_number] = cluster->getMomentValue(xAOD::CaloCluster:: MOMENT_NAME ); \
538 }
539
540#define CALORECGPU_MOMENTS_INPUT_HELPER_10(VAR_NAME, MOMENT_NAME) \
541 if (output_extra_moments && moments_to_add[xAOD::CaloCluster:: MOMENT_NAME]) \
542 { \
543 m_clusters->moments. VAR_NAME [cluster_number] = cluster->getMomentValue(xAOD::CaloCluster:: MOMENT_NAME ); \
544 }
545
546#define CALORECGPU_MOMENTS_INPUT_HELPER_00(...)
547#define CALORECGPU_MOMENTS_INPUT_HELPER_01(...)
548
550
551 double second_time_retriever = 0;
552
553 if (!cluster->retrieveMoment(xAOD::CaloCluster::SECOND_TIME, second_time_retriever))
554 {
555 m_clusters->moments.secondTime[cluster_number] = cluster->secondTime();
556 //Special casing for SECOND_TIME as it comes from CalculateKine instead,
557 //thus stored in a member variable instead of the moment.
558 }
559 else
560 {
561 m_clusters->moments.secondTime[cluster_number] = second_time_retriever;
562 }
563 }
564 }
565
566 m_clusters->number = cluster_collection->size();
567 m_clusters->number_cells = (output_tags ? m_cell_info->number : overall_cell_index);
568 }
569 else
570 {
572 m_clusters->has_deleted_clusters = false;
573 m_clusters->number = 0;
574 m_clusters->number_cells = 0;
575 }
576}
#define CALORECGPU_MOMENTS_INPUT_HELPER(VAR_NAME, PROPER_MOMENT, NORMAL_ASSIGN, IS_CALCULATED, MOMENT_NAME,...)
#define CALORECGPU_FORALLMOMENTS_INSTANTIATE(MACRO,...)
bool retrieveMoment(MomentType type, double &value) const
Retrieve individual moment.
const CaloClusterCellLink * getCellLinks() const
Get a pointer to the CaloClusterCellLink object (const version).
float phiSample(const CaloSample sampling) const
Retrieve barycenter in a given sample.
float energy_max(const CaloSample sampling) const
Retrieve maximum cell energy in given sampling.
int numberCellsInSampling(const CaloSample samp, bool isInnerWheel=false) const
Returns number of cells in given sampling.
flt_t time() const
Access cluster time.
virtual double eta() const
The pseudorapidity ( ) of the particle.
virtual double e() const
The total energy of the particle.
const_cell_iterator cell_end() const
float eSample(const CaloSample sampling) const
flt_t secondTime() const
Access second moment of cell timing distribution.
virtual double phi() const
The azimuthal angle ( ) of the particle.
float etamax(const CaloSample sampling) const
Retrieve of cell with maximum energy in given sampling.
@ SECOND_TIME
Second moment of cell time distribution in cluster.
const_cell_iterator cell_begin() const
Iterator of the underlying CaloClusterCellLink (const version).
float etaSample(const CaloSample sampling) const
Retrieve barycenter in a given sample.
float phimax(const CaloSample sampling) const
Retrieve of cell with maximum energy in given sampling.
constexpr int NumSamplings
TagBase::carrier tag_type
str index
Definition DeMoScan.py:362
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
setEventNumber uint32_t
constexpr int32_t secondary_cluster_weight() const
constexpr bool is_part_of_cluster() const
constexpr int32_t cluster_index() const
static constexpr carrier make_tag(const uint16_t cluster_index=0, const int32_t weight=0, const uint16_t second_cluster_index=0)
static constexpr carrier make_invalid_tag()

◆ returnAndExportClusters()

void CaloRecGPU::EventDataHolder::returnAndExportClusters ( void * cluster_collection,
const void * cell_collection_link,
const MomentsOptionsArray & moments_to_add,
const bool sort_clusters = true,
const bool save_uncalibrated = true,
const bool output_extra_moments = false,
const std::vector< int > & extra_cells_to_fill = {},
size_t * time_measurements = nullptr,
CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream = {} )

We are using a void* for API to make this able to compile on the GPU without Athena-specific dependencies.

The user should pass a xAOD::CaloClusterContainer * and a const DataLink<CaloCellContainer> *. moments_to_add specifies which moments we will import. If sort_clusters is true, the clusters will be sorted based on the transverse energy, otherwise the same order will be kept. If save_uncalibrated, the basic cluster information will be saved as raw. If time_measurements is not null, separate time measurements for the six stages (initial transfer, cell link creation, cell assignment, sorting, basic info filling and moments filling) will be stored.

Definition at line 1269 of file DataHolders.cxx.

1278{
1279 using clock_type = boost::chrono::thread_clock;
1280 auto time_cast = [](const auto & before, const auto & after)
1281 {
1282 return boost::chrono::duration_cast<boost::chrono::microseconds>(after - before).count();
1283 };
1284
1285 xAOD::CaloClusterContainer * cluster_collection = static_cast<xAOD::CaloClusterContainer *>(p_cluster_collection);
1286 const DataLink<CaloCellContainer> & cell_collection_link = *(static_cast<const DataLink<CaloCellContainer> *>(p_cell_collection_link));
1287
1288 const auto start = clock_type::now();
1289
1290 m_clusters.allocate();
1291
1292 CaloRecGPU::CUDA_Helpers::GPU_to_CPU_async(static_cast<ClusterBaseInfo *>(m_clusters),
1293 static_cast<const ClusterBaseInfo *>(m_clusters_dev),
1294 sizeof(ClusterBaseInfo), stream);
1295
1297
1298 const auto after_first_transfer = clock_type::now();
1299
1301
1302 std::vector<std::unique_ptr<CaloClusterCellLink>> cell_links;
1303
1304 export_cluster_initialize_links(m_clusters, cell_links, cell_collection_link, true);
1305
1306 const auto after_link_creation = clock_type::now();
1307
1309
1311
1312 export_cluster_process_cells(m_clusters, m_cell_info, cell_links, extra_cells_to_fill);
1313
1314 const auto after_cell_processing = clock_type::now();
1315
1316 std::vector<int> cluster_order;
1317
1318 export_cluster_sort(m_clusters, cluster_order, sort_clusters);
1319
1320 const auto after_sorting = clock_type::now();
1321
1323
1325
1326 export_cluster_fill_cells_and_basic_info(m_clusters, cluster_collection, cell_links, cluster_order, save_uncalibrated);
1327
1328 const auto after_basic_info = clock_type::now();
1329
1331
1332 export_cluster_fill_moments(m_clusters, cluster_collection, cluster_order, moments_to_add, output_extra_moments);
1333
1334 const auto after_moments = clock_type::now();
1335
1336 if (time_measurements)
1337 {
1338 time_measurements[0] = time_cast(start, after_first_transfer);
1339 time_measurements[1] = time_cast(after_first_transfer, after_link_creation);
1340 time_measurements[2] = time_cast(after_link_creation, after_cell_processing);
1341 time_measurements[3] = time_cast(after_cell_processing, after_sorting);
1342 time_measurements[4] = time_cast(after_sorting, after_basic_info);
1343 time_measurements[5] = time_cast(after_basic_info, after_moments);
1344 }
1345}
static void cluster_transfer_helper_moments(ReadStateFrom &state_holder, OutputClusters &output_clusters, InputClusters &input_clusters, const MomentsOptionsArray &moments_to_add, CopyFunc copy_func, CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream)
static void cluster_transfer_helper_cell_assignment(ReadStateFrom &state_holder, OutputClusters &output_clusters, InputClusters &input_clusters, CopyFunc copy_func, CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream, const int num_total_cells=NCaloCells)
static void cluster_transfer_helper_basic_info(ReadStateFrom &state_holder, OutputClusters &output_clusters, InputClusters &input_clusters, CopyFunc copy_func, CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream)
void GPU_synchronize(CUDAStreamPtrHolder stream={})
Synchronizes the stream.
void GPU_to_CPU_async(void *dest, const void *const source, const size_t num, CUDAStreamPtrHolder stream={})
Copies num bytes from source in GPU memory to dest in CPU memory, asynchronously.

◆ returnToCPU()

void CaloRecGPU::EventDataHolder::returnToCPU ( const MomentsOptionsArray & moments_to_add,
const bool full_copy = false,
const bool clear_GPU = false,
const bool synchronize = false,
CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream = {},
const bool also_return_cells = false )

moments_to_add specifies which moments we will transfer from the GPU.

If full_copy is true, we will memcopy the whole structure in bulk instead of enqueuing separate transfers up to the necessary size (this will also ignore the moments_to_add). If full_copy is false, we will have a synchronization point before enqueuing the transfers to know the sizes. If clear_GPU is true, we will wait until the transfers are finished before deallocating. If synchronize is true, we will synchronize anyway.

Definition at line 842 of file DataHolders.cxx.

848{
849 if (also_return_cells)
850 {
851 m_cell_info.allocate();
852 }
853 m_clusters.allocate();
854
855 if (!full_copy)
856 {
857 if (also_return_cells)
858 {
859 CaloRecGPU::CUDA_Helpers::GPU_to_CPU_async(static_cast<CellBaseInfo *>(m_cell_info),
860 static_cast<CellBaseInfo *>(m_cell_info_dev),
861 sizeof(CellBaseInfo), stream);
862 }
863
864 CaloRecGPU::CUDA_Helpers::GPU_to_CPU_async(static_cast<ClusterBaseInfo *>(m_clusters),
865 static_cast<ClusterBaseInfo *>(m_clusters_dev),
866 sizeof(ClusterBaseInfo), stream);
867
869
870 }
871
872 if (also_return_cells)
873 {
876 }
877
880
881 if (clear_GPU)
882 {
884
885 m_clusters_dev.clear();
886 m_cell_info_dev.clear();
887 }
888 else if (synchronize)
889 {
891 }
892}
static void cell_transfer_helper(ReadStateFrom &state_holder, OutputCells &output_cells, InputCells &input_cells, CopyFunc copy_func, const bool full_copy, CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream)
static void cluster_transfer_helper(ReadStateFrom &state_holder, OutputClusters &output_clusters, InputClusters &input_clusters, const MomentsOptionsArray &moments_to_add, CopyFunc copy_func, const bool full_copy, CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream, const int num_total_cells=CaloRecGPU::NCaloCells)

◆ sendToGPU()

void CaloRecGPU::EventDataHolder::sendToGPU ( const MomentsOptionsArray & moments_to_add,
const bool full_copy = false,
const bool clear_CPU = false,
const bool synchronize = false,
CaloRecGPU::CUDA_Helpers::CUDAStreamPtrHolder stream = {} )

This function is asynchronous if clear_CPU and synchronize are false.

moments_to_add specifies which moments we will transfer to the GPU. If full_copy is true, we will memcopy the whole structure in bulk instead of enqueuing separate transfers up to the necessary size (this will also ignore the moments_to_add). If clear_CPU is true, we will wait until the transfers are finished before deallocating. If synchronize is true, we will synchronize anyway.

Definition at line 801 of file DataHolders.cxx.

806{
807 m_cell_info_dev.allocate();
808 m_clusters_dev.allocate();
809
810 if (!full_copy)
811 {
813 static_cast<const CellBaseInfo *>(m_cell_info),
814 sizeof(CellBaseInfo), stream);
815
816 CaloRecGPU::CUDA_Helpers::CPU_to_GPU_async(static_cast<ClusterBaseInfo *>(m_clusters_dev),
817 static_cast<const ClusterBaseInfo *>(m_clusters),
818 sizeof(ClusterBaseInfo), stream);
819
820 }
821
824
827 m_cell_info->number);
828
829 if (clear_CPU)
830 {
832
833 m_clusters.clear();
834 m_cell_info.clear();
835 }
836 else if (synchronize)
837 {
839 }
840}
void CPU_to_GPU_async(void *dest, const void *const source, const size_t num, CUDAStreamPtrHolder stream={})
Copies num bytes from source in CPU memory to dest in GPU memory, asynchronously.

Member Data Documentation

◆ m_cell_info

CaloRecGPU::Helpers::CUDA_pinned_CPU_object<CaloRecGPU::CellInfoArr> CaloRecGPU::EventDataHolder::m_cell_info

Definition at line 168 of file DataHolders.h.

◆ m_cell_info_dev

CaloRecGPU::Helpers::CUDA_object<CaloRecGPU::CellInfoArr> CaloRecGPU::EventDataHolder::m_cell_info_dev

Definition at line 178 of file DataHolders.h.

◆ m_clusters

Definition at line 169 of file DataHolders.h.

◆ m_clusters_dev

CaloRecGPU::Helpers::CUDA_object<CaloRecGPU::ClusterInfoArr> CaloRecGPU::EventDataHolder::m_clusters_dev

Definition at line 179 of file DataHolders.h.


The documentation for this class was generated from the following files: