ATLAS Offline Software
Loading...
Searching...
No Matches
TFCSBinnedShowerONNX.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <cmath>
8#include <cstdlib>
9
10#include "HepPDT/ParticleData.hh"
19
20#if defined(__FastCaloSimStandAlone__)
21#include "CLHEP/Random/TRandomEngine.h"
22#else
23#include <CLHEP/Random/RanluxEngine.h>
24#endif
25
26#include <H5Cpp.h>
27#include <TFile.h>
28#include <TH2.h>
29#include <TKey.h>
30#include <TMatrixD.h>
31
32#include <algorithm>
33#include <iostream>
34#include <map>
35#include <regex>
36#include <string>
37#include <vector>
38
39#include "CLHEP/Random/RandFlat.h"
41#include "TBuffer.h"
42#include "TClass.h"
43
44//=============================================
45//======= TFCSBinnedShowerONNX =========
46//=============================================
47
48// using namespace TFCSBinnedShowerEventTypes;
49
50TFCSBinnedShowerONNX::TFCSBinnedShowerONNX(const char *name, const char *title)
51 : TFCSBinnedShowerBase(name, title) {}
52
54 // Delete the AI simulator
55 if (m_ai_simulator) {
56 delete m_ai_simulator;
57 m_ai_simulator = nullptr;
58 }
59}
60
62 TFCSSimulationState &simulstate, float eta_center, float phi_center,
63 float e_init, long unsigned int reference_layer_index) const {
64
65 (void)reference_layer_index; // Unused parameter
66 (void)phi_center; // Unused parameter
67
69 m_ai_simulator->getEvent(simulstate, eta_center, e_init);
70
71 // Store a pointer to the event
74 simulstate.setAuxInfo<void *>("BSEventData"_FCShash, event_ptr);
75 simulstate.setAuxInfo<float>("BSEinit"_FCShash, e_init);
76
77 compute_n_hits_and_elayer(simulstate);
78}
79
81 const std::string &filename, std::vector<long unsigned int> &layers) {
82
83 m_coordinates.clear();
84
85 if (m_use_upscaling) {
87 }
88
89 // layer dependent variables
90 for (long unsigned int layer_index : layers) {
91
92 ATH_MSG_INFO("Loading layer " << layer_index << " from file: " << filename);
93
94 // Load the bin boundaries for this layer
95 load_bin_boundaries(filename, layer_index);
96 }
97
98 return;
99}
100
101std::tuple<std::vector<float>, std::vector<hsize_t>, bool>
102TFCSBinnedShowerONNX::load_hdf5_dataset(const std::string &filename,
103 const std::string &datasetname) {
104
105 // Open the HDF5 file and dataset
106 H5::H5File file(filename, H5F_ACC_RDONLY);
107
108 // check if the dataset exists
109 if (!file.exists(datasetname)) {
110 return std::make_tuple(std::vector<float>{}, std::vector<hsize_t>{}, false);
111 }
112
113 H5::DataSet dataset = file.openDataSet(datasetname);
114
115 // Get the dataspace of the dataset
116 H5::DataSpace dataspace = dataset.getSpace();
117
118 // Get the number of dimensions and the size of each dimension
119 int rank = dataspace.getSimpleExtentNdims();
120 std::vector<hsize_t> dims_out(rank);
121 dataspace.getSimpleExtentDims(dims_out.data(), NULL);
122
123 // Calculate the total number of elements
124 hsize_t totalSize = 1;
125 for (const auto &dim : dims_out) {
126 totalSize *= dim;
127 }
128
129 // Read the dataset into a buffer
130 std::vector<float> data(totalSize);
131 dataset.read(data.data(), H5::PredType::NATIVE_FLOAT);
132 file.close();
133 return std::make_tuple(data, dims_out, true);
134}
135
136void TFCSBinnedShowerONNX::load_bin_boundaries(const std::string &filename,
137 long unsigned int layer_index) {
138
139 // Assert that the layer index is valid
140 if (layer_index >= m_coordinates.size()) {
141 m_coordinates.resize(layer_index + 1);
142 }
143
144 std::vector<std::string> datasetnames = {
145 "binstart_radius_layer_", "binsize_radius_layer_",
146 "binstart_alpha_layer_", "binsize_alpha_layer_"};
147
148 for (long unsigned int i = 0; i < datasetnames.size(); i++) {
149 std::string datasetname = datasetnames.at(i) + std::to_string(layer_index);
150 std::vector<float> data;
151 std::vector<hsize_t> dims;
152 bool success;
153 std::tie(data, dims, success) = load_hdf5_dataset(filename, datasetname);
154 if (!success) {
155 ATH_MSG_ERROR("Error while extracting the bin boundaries for layer "
156 << layer_index << " from " << filename << "."
157 << "Specifically, the key " << datasetname
158 << " could not be loaded.");
159 return;
160 }
161
162 // Fill the corresponding vector in the layer_bins_t structure
163 auto &event_bins = m_coordinates.at(layer_index);
164 switch (i) {
165 case 0:
166 event_bins.R_lower = std::move(data);
167 break;
168 case 1:
169 event_bins.R_size = std::move(data);
170 break;
171 case 2:
172 event_bins.alpha_lower = std::move(data);
173 break;
174 case 3:
175 event_bins.alpha_size = std::move(data);
176 break;
177 }
178 }
179}
180
181// TODO: Could probably be removed in the end
182void TFCSBinnedShowerONNX::Streamer(TBuffer &R__b) {
183 // Stream an object of class TFCSBinnedShowerONNX
184
185 if (R__b.IsReading()) {
186 R__b.ReadClassBuffer(TFCSBinnedShowerONNX::Class(), this);
187
188 } else {
189
190 R__b.WriteClassBuffer(TFCSBinnedShowerONNX::Class(), this);
191 }
192}
193
194void TFCSBinnedShowerONNX::set_bin_boundaries(long unsigned int layer_index,
195 const std::vector<float>& R_lower,
196 const std::vector<float>& R_size,
197 const std::vector<float>& alpha_lower,
198 const std::vector<float>& alpha_size) {
199 if (layer_index >= m_coordinates.size()) {
200 m_coordinates.resize(layer_index + 1);
201 }
202 m_coordinates.at(layer_index).R_lower = R_lower;
203 m_coordinates.at(layer_index).R_size = R_size;
204 m_coordinates.at(layer_index).alpha_lower = alpha_lower;
205 m_coordinates.at(layer_index).alpha_size = alpha_size;
206}
207
209 TFCSSimulationState &simulstate) const {
210
213 simulstate.getAuxInfo<void *>("BSEventData"_FCShash));
214 float e_init = simulstate.getAuxInfo<float>("BSEinit"_FCShash);
215
216 // Loop over all layers
217 long unsigned int n_layers = event->event_data.size();
218 std::vector<std::vector<long unsigned int>> hits_per_layer;
219 std::vector<float> elayer;
220 hits_per_layer.resize(n_layers);
221 elayer.resize(n_layers, 0.0f);
222
223 for (long unsigned int layer_index = 0; layer_index < n_layers;
224 ++layer_index) {
225
226 TFCSMLCalorimeterSimulator::layer_t &layer = event->event_data.at(layer_index);
227
228 // Loop over all voxels in the layer
229 long unsigned int n_hits = 0;
230 for (float e_voxel : layer.E_vector) {
231 long unsigned int hits_per_bin;
232 if (e_voxel > std::numeric_limits<float>::epsilon()) {
233 hits_per_bin =
234 std::min(std::max(int(e_voxel * e_init / m_default_hit_energy), 1),
236 elayer.at(layer_index) += e_voxel * e_init;
237
238 } else {
239 hits_per_bin = 0;
240 }
241 n_hits += hits_per_bin;
242 hits_per_layer.at(layer_index).push_back(n_hits);
243 }
244 }
245 // Store the hits per layer vector
246 std::vector<std::vector<long unsigned int>> *hits_per_layer_ptr =
247 new std::vector<std::vector<long unsigned int>>(std::move(hits_per_layer));
248 simulstate.setAuxInfo<void *>("BSNHits"_FCShash, hits_per_layer_ptr);
249
250 // Store the energy per layer
251 std::vector<float> *elayer_ptr = new std::vector<float>(std::move(elayer));
252 simulstate.setAuxInfo<void *>("BSELayer"_FCShash, elayer_ptr);
253}
254
256 TFCSSimulationState &simulstate, long unsigned int layer_index) const {
257
258 std::vector<std::vector<long unsigned int>> *hits_per_layer_ptr =
259 static_cast<std::vector<std::vector<long unsigned int>> *>(
260 simulstate.getAuxInfo<void *>("BSNHits"_FCShash));
261
262 if (!hits_per_layer_ptr) {
263 ATH_MSG_ERROR("Invalid hits per layer information");
264 return 0;
265 }
266
267 return hits_per_layer_ptr->at(layer_index).back();
268}
269
271 TFCSSimulationState &simulstate, long unsigned int layer_index) const {
272 std::vector<float> *elayer_ptr = static_cast<std::vector<float> *>(
273 simulstate.getAuxInfo<void *>("BSELayer"_FCShash));
274 if (!elayer_ptr) {
275 ATH_MSG_ERROR("Invalid layer energy information");
276 return 0.0f;
277 }
278 if (layer_index >= elayer_ptr->size()) {
279 return 0.0f;
280 }
281
282 ATH_MSG_DEBUG("returning energy for layer " << layer_index
283 << ": " << elayer_ptr->at(layer_index));
284
285 return elayer_ptr->at(layer_index);
286}
287
289 TFCSSimulationState &simulstate, long unsigned int layer_index,
290 long unsigned int hit_index) const {
291 std::vector<std::vector<long unsigned int>> *hits_per_layer_ptr =
292 static_cast<std::vector<std::vector<long unsigned int>> *>(
293 simulstate.getAuxInfo<void *>("BSNHits"_FCShash));
294 if (!hits_per_layer_ptr) {
295 ATH_MSG_ERROR("Invalid hits per layer information");
296 return 0;
297 }
298
299 if (layer_index >= hits_per_layer_ptr->size()) {
300 ATH_MSG_ERROR("Layer index out of bounds: " << layer_index << " >= "
301 << hits_per_layer_ptr->size());
302 return 0;
303 }
304
305 // Find the hit index in the hit vector for the given layer
306 const std::vector<long unsigned int> &hits =
307 hits_per_layer_ptr->at(layer_index);
308 auto it = std::upper_bound(hits.begin(), hits.end(), hit_index);
309 long unsigned int energy_index = std::distance(hits.begin(), it);
310
311 if (energy_index >= hits.size()) {
312 ATH_MSG_ERROR("Energy index out of bounds: " << energy_index
313 << " >= " << hits.size());
314 // Print full hits for debugging
315 ATH_MSG_ERROR("Hits per layer: ");
316 for (const auto &hit : hits) {
317 ATH_MSG_ERROR("Hit: " << hit);
318 }
319 return 0;
320 }
321
322 return energy_index;
323}
324
326 TFCSSimulationState &simulstate, long unsigned int layer_index,
327 int bin_index) const {
328 float R_min = m_coordinates.at(layer_index).R_lower.at(bin_index);
329 float R_max = m_coordinates.at(layer_index).R_size.at(bin_index) +
330 m_coordinates.at(layer_index).R_lower.at(bin_index);
331
332 float alpha_min = m_coordinates.at(layer_index).alpha_lower.at(bin_index);
333 float alpha_max = m_coordinates.at(layer_index).alpha_size.at(bin_index) +
334 m_coordinates.at(layer_index).alpha_lower.at(bin_index);
335
336 if (m_use_upscaling) {
337 upscale(simulstate, R_min, R_max, alpha_min, alpha_max, layer_index,
338 bin_index);
339 }
340
341 float R = CLHEP::RandFlat::shoot(simulstate.randomEngine(), R_min, R_max);
342 float alpha =
343 CLHEP::RandFlat::shoot(simulstate.randomEngine(), alpha_min, alpha_max);
344
345 return std::make_tuple(R, alpha);
346}
347
349 float &R_min, float &R_max, float &alpha_min,
350 float &alpha_max,
351 long unsigned int layer_index,
352 int bin_index) const {
353
354 float p = CLHEP::RandFlat::shoot(simulstate.randomEngine(), 0, 1);
355
356 float e_init = simulstate.getAuxInfo<float>("BSEinit"_FCShash);
357 std::vector<float> available_energies = m_upscaling_energies;
358
359 unsigned int e_index = 0;
360
361 std::vector<float> probabilities = {0.25f, 0.5f, 0.75f};
362
363 if (available_energies.size() > 1) {
364 // find closest energy index using binary search
365 auto it = std::upper_bound(available_energies.begin(),
366 available_energies.end(), e_init);
367 if (it != available_energies.end()) {
368 e_index = std::distance(available_energies.begin(), it);
369 } else {
370 e_index = available_energies.size() - 1;
371 }
372
373 float e_high = available_energies.at(e_index);
374 if (e_high < e_init || e_index == 0) {
375 if (m_sub_bin_distribution.at(e_index).size() > layer_index) {
376 probabilities =
377 m_sub_bin_distribution.at(e_index).at(layer_index).at(bin_index);
378 }
379 } else {
380 if (m_sub_bin_distribution.at(e_index).size() > layer_index &&
381 m_sub_bin_distribution.at(e_index - 1).size() > layer_index) {
382 float e_low = available_energies.at(e_index - 1);
383 float f_low = std::log(e_high / e_init) / (std::log(e_high / e_low));
384 float f_high = 1 - f_low;
385 for (unsigned int i = 0; i < 3; ++i) {
386 float p_low = m_sub_bin_distribution.at(e_index - 1)
387 .at(layer_index)
388 .at(bin_index)
389 .at(i);
390 float p_high = m_sub_bin_distribution.at(e_index)
391 .at(layer_index)
392 .at(bin_index)
393 .at(i);
394 probabilities[i] = f_low * p_low + f_high * p_high;
395 }
396 }
397 }
398 }
399
400 else if (available_energies.size() == 1) {
401 probabilities = m_sub_bin_distribution.at(0).at(layer_index).at(bin_index);
402 }
403
404float p_alpha_low = probabilities[2] - probabilities[1] + probabilities[0];
405 float p_r;
406
407 if (p < p_alpha_low) {
408 alpha_max = (alpha_min + alpha_max) / 2.;
409 p_r = probabilities[0] / (p_alpha_low);
410 } else {
411 alpha_min = (alpha_min + alpha_max) / 2.;
412 p_r = (probabilities[1] - probabilities[0]) / (1 - p_alpha_low);
413 }
414
415 p = CLHEP::RandFlat::shoot(simulstate.randomEngine(), 0, 1);
416 if (layer_index != 2){
417 // if ((layer_index != 2) && (layer_index != 0)) {
418 if (p > p_r) {
419 R_min = (R_min + R_max) / 2.;
420 return;
421 } else {
422 R_max = (R_min + R_max) / 2.;
423 return;
424 }
425 }
426
427
428 // Use linear interpolation for layer 2
429 // It works better than uniform sampling for the second layer...
430 if (p_r < 0.25) {
431 p_r = 0.25; // Values below 0.25 are not allowed for linear pdf
432 } else if (p_r > 0.75) {
433 p_r = 0.75; // Values above 0.75 are not allowed for linear pdf
434 } else if (TMath::Abs(p_r - 0.5) < std::numeric_limits<float>::epsilon()) {
435 return; // Best upscaling is uniform sampling. Nothing to do here.
436 }
437
438 // Inverse CDF for linear pdf
439 float r = (1. - 4. * p_r) / (2. - 4. * p_r) -
440 TMath::Sqrt(((1. - 4. * p_r) / (2. - 4. * p_r)) *
441 ((1. - 4. * p_r) / (2. - 4. * p_r)) +
442 p / ((1. / 2.) - p_r));
443 if (r < 0) {
444 r = (1. - 4. * p_r) / (2. - 4. * p_r) +
445 TMath::Sqrt(((1. - 4. * p_r) / (2. - 4. * p_r)) *
446 ((1. - 4. * p_r) / (2. - 4. * p_r)) +
447 p / ((1. / 2.) - p_r));
448 }
449
450 R_min = R_min + r / 2 * (R_max - R_min);
451 R_max = R_min;
452}
453
454std::tuple<float, float, float>
456 TFCSSimulationState &simulstate, long unsigned int layer_index,
457 long unsigned int hit_index) const {
458
461 simulstate.getAuxInfo<void *>("BSEventData"_FCShash));
462
463 float e_init = simulstate.getAuxInfo<float>("BSEinit"_FCShash);
464
465 if (layer_index >= event->event_data.size()) {
466 ATH_MSG_ERROR("Layer index out of bounds: " << layer_index << " >= "
467 << event->event_data.size());
468 return std::make_tuple(0.0f, 0.0f, 0.0f);
469 }
470
471 long unsigned int energy_index = get_energy_index(
472 simulstate, layer_index, hit_index); // Get the bin index for the hit
473
474 std::vector<std::vector<long unsigned int>> *hits_per_layer_ptr =
475 static_cast<std::vector<std::vector<long unsigned int>> *>(
476 simulstate.getAuxInfo<void *>("BSNHits"_FCShash));
477
478 long unsigned int hits_per_bin;
479 if (energy_index == 0) {
480 hits_per_bin = hits_per_layer_ptr->at(layer_index).at(energy_index);
481 } else {
482 hits_per_bin = hits_per_layer_ptr->at(layer_index).at(energy_index) -
483 hits_per_layer_ptr->at(layer_index).at(energy_index - 1);
484 }
485
486 float r, alpha;
487
488 TFCSMLCalorimeterSimulator::layer_t &layer = event->event_data.at(layer_index);
489
490 std::tie(r, alpha) = get_coordinates(simulstate, layer_index,
491 layer.bin_index_vector.at(energy_index));
492
493 float E = layer.E_vector.at(energy_index) * e_init / hits_per_bin;
494
495 return std::make_tuple(r, alpha, E);
496}
497
499 // Delete the event data
500 void *event_ptr = simulstate.getAuxInfo<void *>("BSEventData"_FCShash);
501 if (event_ptr) {
502 delete static_cast<TFCSMLCalorimeterSimulator::event_t *>(event_ptr);
503 simulstate.setAuxInfo<void *>("BSEventData"_FCShash, nullptr);
504 } else {
505 ATH_MSG_ERROR("No event data found to delete.");
506 }
507
508 void *n_hits_ptr = simulstate.getAuxInfo<void *>("BSNHits"_FCShash);
509 if (n_hits_ptr) {
510 delete static_cast<std::vector<std::vector<long unsigned int>> *>(
511 n_hits_ptr);
512 simulstate.setAuxInfo<void *>("BSNHits"_FCShash, nullptr);
513 } else {
514 ATH_MSG_ERROR("No event hits data found to delete.");
515 }
516
517 void *elayer_ptr = simulstate.getAuxInfo<void *>("BSELayer"_FCShash);
518 if (elayer_ptr) {
519 delete static_cast<std::vector<float> *>(elayer_ptr);
520 simulstate.setAuxInfo<void *>("BSELayer"_FCShash, nullptr);
521 } else {
522 ATH_MSG_ERROR("No event layer energy data found to delete.");
523 }
524
525 return;
526}
527
529 const std::string &filename) {
530 m_use_upscaling = true;
531 TFile *file = TFile::Open(filename.c_str(), "READ");
532 if (!file || file->IsZombie()) {
533 std::cerr << "Failed to open file: " << filename << std::endl;
534 return;
535 }
536
537 std::regex pattern(R"(probabilities_layer_(\d+)_energy_([0-9.]+))");
538 std::map<float, std::map<int, std::vector<std::vector<float>>>> temp_storage;
539
540 TIter next(file->GetListOfKeys());
541 TKey *key;
542
543 while ((key = (TKey *)next())) {
544 std::string keyname = key->GetName();
545 std::smatch match;
546 if (std::regex_match(keyname, match, pattern)) {
547 int layer = std::stoi(match[1].str());
548 float energy = std::stod(match[2].str());
549
550 TMatrixD *matrix = dynamic_cast<TMatrixD *>(file->Get(keyname.c_str()));
551 if (matrix) {
552 std::vector<std::vector<float>> mat_vec(
553 matrix->GetNrows(), std::vector<float>(matrix->GetNcols()));
554 for (int i = 0; i < matrix->GetNrows(); ++i) {
555 for (int j = 0; j < matrix->GetNcols(); ++j) {
556 mat_vec[i][j] = static_cast<float>((*matrix)(i, j));
557 }
558 }
559 temp_storage[energy][layer] = std::move(mat_vec);
560 }
561 }
562 }
563
564 file->Close();
565 delete file;
566
567 // Output containers
568 std::vector<float> energies;
569 std::vector<std::vector<std::vector<std::vector<float>>>>
570 data; // [energy][layer][row][col]
571
572 for (const auto &[energy, layer_map] : temp_storage) {
573 energies.push_back(energy);
574 int max_layer = 0;
575 for (const auto &[l, _] : layer_map)
576 max_layer = std::max(max_layer, l);
577
578 std::vector<std::vector<std::vector<float>>> layer_vec(max_layer + 1);
579 for (const auto &[layer_idx, mat] : layer_map) {
580 layer_vec[layer_idx] = mat;
581 }
582 data.push_back(std::move(layer_vec));
583 }
584
585 // Example output
586 for (size_t i = 0; i < energies.size(); ++i) {
587 std::cout << "Energy index " << i << ": " << energies[i] << " GeV\n";
588 for (size_t j = 0; j < data[i].size(); ++j) {
589 if (!data[i][j].empty()) {
590 std::cout << " Layer " << j << " Shape: (" << data[i][j].size() << ", "
591 << data[i][j][0].size() << ")\n";
592 }
593 }
594 }
595
596 m_upscaling_energies = std::move(energies);
597 m_sub_bin_distribution = std::move(data);
598}
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
static unsigned int totalSize(const MultiDimArray< T, N > &ht)
static const Attributes_t empty
TFCSBinnedShowerBase(const char *name=nullptr, const char *title=nullptr)
virtual void compute_n_hits_and_elayer(TFCSSimulationState &simulstate) const
long unsigned int get_energy_index(TFCSSimulationState &simulstate, long unsigned int layer_index, long unsigned int hit_index) const
void load_bin_boundaries(const std::string &filename, long unsigned int layer_index)
std::vector< float > m_upscaling_energies
std::vector< std::vector< std::vector< std::vector< float > > > > m_sub_bin_distribution
TFCSMLCalorimeterSimulator * m_ai_simulator
const event_bins_t & get_coordinates()
virtual float get_layer_energy(TFCSSimulationState &simulstate, long unsigned int layer_index) const override
void load_sub_bin_distribution(const std::string &filename)
void set_bin_boundaries(long unsigned int layer_index, const std::vector< float > &R_lower, const std::vector< float > &R_size, const std::vector< float > &alpha_lower, const std::vector< float > &alpha_size)
void upscale(TFCSSimulationState &simulstate, float &R_min, float &R_max, float &alpha_min, float &alpha_max, long unsigned int layer_index, int bin_index) const
TFCSBinnedShowerONNX(const char *name=nullptr, const char *title=nullptr)
void load_meta_data(const std::string &filename, std::vector< long unsigned int > &layers)
std::tuple< std::vector< float >, std::vector< hsize_t >, bool > load_hdf5_dataset(const std::string &filename, const std::string &datasetname)
virtual void get_event(TFCSSimulationState &simulstate, float eta_center, float phi_center, float e_init, long unsigned int reference_layer_index) const override
do not persistify
virtual long unsigned int get_n_hits(TFCSSimulationState &simulstate, long unsigned int layer_index) const override
virtual std::tuple< float, float, float > get_hit_position_and_energy(TFCSSimulationState &simulstate, long unsigned int layer_index, long unsigned int hit_index) const override
virtual void delete_event(TFCSSimulationState &simulstate) const override
const T getAuxInfo(std::uint32_t index) const
void setAuxInfo(std::uint32_t index, const T &val)
CLHEP::HepRandomEngine * randomEngine()
int r
Definition globals.cxx:22
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:357
TFile * file