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
18
19#if defined(__FastCaloSimStandAlone__)
20#include "CLHEP/Random/TRandomEngine.h"
21#else
22#include <CLHEP/Random/RanluxEngine.h>
23#endif
24
25#include <H5Cpp.h>
26#include <TFile.h>
27#include <TH2.h>
28#include <TKey.h>
29#include <TMatrixD.h>
30
31#include <algorithm>
32#include <iostream>
33#include <map>
34#include <regex>
35#include <string>
36#include <vector>
37
38#include "CLHEP/Random/RandFlat.h"
40#include "TBuffer.h"
41#include "TClass.h"
42
43//=============================================
44//======= TFCSBinnedShowerONNX =========
45//=============================================
46
47// using namespace TFCSBinnedShowerEventTypes;
48
49TFCSBinnedShowerONNX::TFCSBinnedShowerONNX(const char *name, const char *title)
50 : TFCSBinnedShowerBase(name, title) {}
51
53 // Delete the AI simulator
54 if (m_ai_simulator) {
55 delete m_ai_simulator;
56 m_ai_simulator = nullptr;
57 }
58}
59
61 TFCSSimulationState &simulstate, float eta_center, float phi_center,
62 float e_init, long unsigned int reference_layer_index) const {
63
64 (void)reference_layer_index; // Unused parameter
65 (void)phi_center; // Unused parameter
66
68 m_ai_simulator->getEvent(simulstate, eta_center, e_init);
69
70 // Store a pointer to the event
73 simulstate.setAuxInfo<void *>("BSEventData"_FCShash, event_ptr);
74 simulstate.setAuxInfo<float>("BSEinit"_FCShash, e_init);
75
76 compute_n_hits_and_elayer(simulstate);
77}
78
80 const std::string &filename, std::vector<long unsigned int> &layers) {
81
82 m_coordinates.clear();
83
84 if (m_use_upscaling) {
86 }
87
88 // layer dependent variables
89 for (long unsigned int layer_index : layers) {
90
91 ATH_MSG_INFO("Loading layer " << layer_index << " from file: " << filename);
92
93 // Load the bin boundaries for this layer
94 load_bin_boundaries(filename, layer_index);
95 }
96
97 return;
98}
99
100std::tuple<std::vector<float>, std::vector<hsize_t>, bool>
101TFCSBinnedShowerONNX::load_hdf5_dataset(const std::string &filename,
102 const std::string &datasetname) {
103
104 // Open the HDF5 file and dataset
105 H5::H5File file(filename, H5F_ACC_RDONLY);
106
107 // check if the dataset exists
108 if (!file.exists(datasetname)) {
109 return std::make_tuple(std::vector<float>{}, std::vector<hsize_t>{}, false);
110 }
111
112 H5::DataSet dataset = file.openDataSet(datasetname);
113
114 // Get the dataspace of the dataset
115 H5::DataSpace dataspace = dataset.getSpace();
116
117 // Get the number of dimensions and the size of each dimension
118 int rank = dataspace.getSimpleExtentNdims();
119 std::vector<hsize_t> dims_out(rank);
120 dataspace.getSimpleExtentDims(dims_out.data(), NULL);
121
122 // Calculate the total number of elements
123 hsize_t totalSize = 1;
124 for (const auto &dim : dims_out) {
125 totalSize *= dim;
126 }
127
128 // Read the dataset into a buffer
129 std::vector<float> data(totalSize);
130 dataset.read(data.data(), H5::PredType::NATIVE_FLOAT);
131 file.close();
132 return std::make_tuple(data, dims_out, true);
133}
134
135void TFCSBinnedShowerONNX::load_bin_boundaries(const std::string &filename,
136 long unsigned int layer_index) {
137
138 // Assert that the layer index is valid
139 if (layer_index >= m_coordinates.size()) {
140 m_coordinates.resize(layer_index + 1);
141 }
142
143 std::vector<std::string> datasetnames = {
144 "binstart_radius_layer_", "binsize_radius_layer_",
145 "binstart_alpha_layer_", "binsize_alpha_layer_"};
146
147 for (long unsigned int i = 0; i < datasetnames.size(); i++) {
148 std::string datasetname = datasetnames.at(i) + std::to_string(layer_index);
149 std::vector<float> data;
150 std::vector<hsize_t> dims;
151 bool success;
152 std::tie(data, dims, success) = load_hdf5_dataset(filename, datasetname);
153 if (!success) {
154 ATH_MSG_ERROR("Error while extracting the bin boundaries for layer "
155 << layer_index << " from " << filename << "."
156 << "Specifically, the key " << datasetname
157 << " could not be loaded.");
158 return;
159 }
160
161 // Fill the corresponding vector in the layer_bins_t structure
162 auto &event_bins = m_coordinates.at(layer_index);
163 switch (i) {
164 case 0:
165 event_bins.R_lower = std::move(data);
166 break;
167 case 1:
168 event_bins.R_size = std::move(data);
169 break;
170 case 2:
171 event_bins.alpha_lower = std::move(data);
172 break;
173 case 3:
174 event_bins.alpha_size = std::move(data);
175 break;
176 }
177 }
178}
179
180// TODO: Could probably be removed in the end
181void TFCSBinnedShowerONNX::Streamer(TBuffer &R__b) {
182 // Stream an object of class TFCSBinnedShowerONNX
183
184 if (R__b.IsReading()) {
185 R__b.ReadClassBuffer(TFCSBinnedShowerONNX::Class(), this);
186
187 } else {
188
189 R__b.WriteClassBuffer(TFCSBinnedShowerONNX::Class(), this);
190 }
191}
192
193void TFCSBinnedShowerONNX::set_bin_boundaries(long unsigned int layer_index,
194 const std::vector<float>& R_lower,
195 const std::vector<float>& R_size,
196 const std::vector<float>& alpha_lower,
197 const std::vector<float>& alpha_size) {
198 if (layer_index >= m_coordinates.size()) {
199 m_coordinates.resize(layer_index + 1);
200 }
201 m_coordinates.at(layer_index).R_lower = R_lower;
202 m_coordinates.at(layer_index).R_size = R_size;
203 m_coordinates.at(layer_index).alpha_lower = alpha_lower;
204 m_coordinates.at(layer_index).alpha_size = alpha_size;
205}
206
208 TFCSSimulationState &simulstate) const {
209
212 simulstate.getAuxInfo<void *>("BSEventData"_FCShash));
213 float e_init = simulstate.getAuxInfo<float>("BSEinit"_FCShash);
214
215 // Loop over all layers
216 long unsigned int n_layers = event->event_data.size();
217 std::vector<std::vector<long unsigned int>> hits_per_layer;
218 std::vector<float> elayer;
219 hits_per_layer.resize(n_layers);
220 elayer.resize(n_layers, 0.0f);
221
222 for (long unsigned int layer_index = 0; layer_index < n_layers;
223 ++layer_index) {
224
225 TFCSMLCalorimeterSimulator::layer_t &layer = event->event_data.at(layer_index);
226
227 // Loop over all voxels in the layer
228 long unsigned int n_hits = 0;
229 for (float e_voxel : layer.E_vector) {
230 long unsigned int hits_per_bin;
231 if (e_voxel > std::numeric_limits<float>::epsilon()) {
232 hits_per_bin =
233 std::min(std::max(int(e_voxel * e_init / m_default_hit_energy), 1),
235 elayer.at(layer_index) += e_voxel * e_init;
236
237 } else {
238 hits_per_bin = 0;
239 }
240 n_hits += hits_per_bin;
241 hits_per_layer.at(layer_index).push_back(n_hits);
242 }
243 }
244 // Store the hits per layer vector
245 std::vector<std::vector<long unsigned int>> *hits_per_layer_ptr =
246 new std::vector<std::vector<long unsigned int>>(std::move(hits_per_layer));
247 simulstate.setAuxInfo<void *>("BSNHits"_FCShash, hits_per_layer_ptr);
248
249 // Store the energy per layer
250 std::vector<float> *elayer_ptr = new std::vector<float>(std::move(elayer));
251 simulstate.setAuxInfo<void *>("BSELayer"_FCShash, elayer_ptr);
252}
253
255 TFCSSimulationState &simulstate, long unsigned int layer_index) const {
256
257 std::vector<std::vector<long unsigned int>> *hits_per_layer_ptr =
258 static_cast<std::vector<std::vector<long unsigned int>> *>(
259 simulstate.getAuxInfo<void *>("BSNHits"_FCShash));
260
261 if (!hits_per_layer_ptr) {
262 ATH_MSG_ERROR("Invalid hits per layer information");
263 return 0;
264 }
265
266 return hits_per_layer_ptr->at(layer_index).back();
267}
268
270 TFCSSimulationState &simulstate, long unsigned int layer_index) const {
271 std::vector<float> *elayer_ptr = static_cast<std::vector<float> *>(
272 simulstate.getAuxInfo<void *>("BSELayer"_FCShash));
273 if (!elayer_ptr) {
274 ATH_MSG_ERROR("Invalid layer energy information");
275 return 0.0f;
276 }
277 if (layer_index >= elayer_ptr->size()) {
278 return 0.0f;
279 }
280
281 ATH_MSG_DEBUG("returning energy for layer " << layer_index
282 << ": " << elayer_ptr->at(layer_index));
283
284 return elayer_ptr->at(layer_index);
285}
286
288 TFCSSimulationState &simulstate, long unsigned int layer_index,
289 long unsigned int hit_index) const {
290 std::vector<std::vector<long unsigned int>> *hits_per_layer_ptr =
291 static_cast<std::vector<std::vector<long unsigned int>> *>(
292 simulstate.getAuxInfo<void *>("BSNHits"_FCShash));
293 if (!hits_per_layer_ptr) {
294 ATH_MSG_ERROR("Invalid hits per layer information");
295 return 0;
296 }
297
298 if (layer_index >= hits_per_layer_ptr->size()) {
299 ATH_MSG_ERROR("Layer index out of bounds: " << layer_index << " >= "
300 << hits_per_layer_ptr->size());
301 return 0;
302 }
303
304 // Find the hit index in the hit vector for the given layer
305 const std::vector<long unsigned int> &hits =
306 hits_per_layer_ptr->at(layer_index);
307 auto it = std::upper_bound(hits.begin(), hits.end(), hit_index);
308 long unsigned int energy_index = std::distance(hits.begin(), it);
309
310 if (energy_index >= hits.size()) {
311 ATH_MSG_ERROR("Energy index out of bounds: " << energy_index
312 << " >= " << hits.size());
313 // Print full hits for debugging
314 ATH_MSG_ERROR("Hits per layer: ");
315 for (const auto &hit : hits) {
316 ATH_MSG_ERROR("Hit: " << hit);
317 }
318 return 0;
319 }
320
321 return energy_index;
322}
323
325 TFCSSimulationState &simulstate, long unsigned int layer_index,
326 int bin_index) const {
327 float R_min = m_coordinates.at(layer_index).R_lower.at(bin_index);
328 float R_max = m_coordinates.at(layer_index).R_size.at(bin_index) +
329 m_coordinates.at(layer_index).R_lower.at(bin_index);
330
331 float alpha_min = m_coordinates.at(layer_index).alpha_lower.at(bin_index);
332 float alpha_max = m_coordinates.at(layer_index).alpha_size.at(bin_index) +
333 m_coordinates.at(layer_index).alpha_lower.at(bin_index);
334
335 if (m_use_upscaling) {
336 upscale(simulstate, R_min, R_max, alpha_min, alpha_max, layer_index,
337 bin_index);
338 }
339
340 float R = CLHEP::RandFlat::shoot(simulstate.randomEngine(), R_min, R_max);
341 float alpha =
342 CLHEP::RandFlat::shoot(simulstate.randomEngine(), alpha_min, alpha_max);
343
344 return std::make_tuple(R, alpha);
345}
346
348 float &R_min, float &R_max, float &alpha_min,
349 float &alpha_max,
350 long unsigned int layer_index,
351 int bin_index) const {
352
353 float p = CLHEP::RandFlat::shoot(simulstate.randomEngine(), 0, 1);
354
355 float e_init = simulstate.getAuxInfo<float>("BSEinit"_FCShash);
356 std::vector<float> available_energies = m_upscaling_energies;
357
358 unsigned int e_index = 0;
359
360 std::vector<float> probabilities = {0.25f, 0.5f, 0.75f};
361
362 if (available_energies.size() > 1) {
363 // find closest energy index using binary search
364 auto it = std::upper_bound(available_energies.begin(),
365 available_energies.end(), e_init);
366 if (it != available_energies.end()) {
367 e_index = std::distance(available_energies.begin(), it);
368 } else {
369 e_index = available_energies.size() - 1;
370 }
371
372 float e_high = available_energies.at(e_index);
373 if (e_high < e_init || e_index == 0) {
374 if (m_sub_bin_distribution.at(e_index).size() > layer_index) {
375 probabilities =
376 m_sub_bin_distribution.at(e_index).at(layer_index).at(bin_index);
377 }
378 } else {
379 if (m_sub_bin_distribution.at(e_index).size() > layer_index &&
380 m_sub_bin_distribution.at(e_index - 1).size() > layer_index) {
381 float e_low = available_energies.at(e_index - 1);
382 float f_low = std::log(e_high / e_init) / (std::log(e_high / e_low));
383 float f_high = 1 - f_low;
384 for (unsigned int i = 0; i < 3; ++i) {
385 float p_low = m_sub_bin_distribution.at(e_index - 1)
386 .at(layer_index)
387 .at(bin_index)
388 .at(i);
389 float p_high = m_sub_bin_distribution.at(e_index)
390 .at(layer_index)
391 .at(bin_index)
392 .at(i);
393 probabilities[i] = f_low * p_low + f_high * p_high;
394 }
395 }
396 }
397 }
398
399 else if (available_energies.size() == 1) {
400 probabilities = m_sub_bin_distribution.at(0).at(layer_index).at(bin_index);
401 }
402
403float p_alpha_low = probabilities[2] - probabilities[1] + probabilities[0];
404 float p_r;
405
406 if (p < p_alpha_low) {
407 alpha_max = (alpha_min + alpha_max) / 2.;
408 p_r = probabilities[0] / (p_alpha_low);
409 } else {
410 alpha_min = (alpha_min + alpha_max) / 2.;
411 p_r = (probabilities[1] - probabilities[0]) / (1 - p_alpha_low);
412 }
413
414 p = CLHEP::RandFlat::shoot(simulstate.randomEngine(), 0, 1);
415 if (layer_index != 2){
416 // if ((layer_index != 2) && (layer_index != 0)) {
417 if (p > p_r) {
418 R_min = (R_min + R_max) / 2.;
419 return;
420 } else {
421 R_max = (R_min + R_max) / 2.;
422 return;
423 }
424 }
425
426
427 // Use linear interpolation for layer 2
428 // It works better than uniform sampling for the second layer...
429 if (p_r < 0.25) {
430 p_r = 0.25; // Values below 0.25 are not allowed for linear pdf
431 } else if (p_r > 0.75) {
432 p_r = 0.75; // Values above 0.75 are not allowed for linear pdf
433 } else if (TMath::Abs(p_r - 0.5) < std::numeric_limits<float>::epsilon()) {
434 return; // Best upscaling is uniform sampling. Nothing to do here.
435 }
436
437 // Inverse CDF for linear pdf
438 float r = (1. - 4. * p_r) / (2. - 4. * p_r) -
439 TMath::Sqrt(((1. - 4. * p_r) / (2. - 4. * p_r)) *
440 ((1. - 4. * p_r) / (2. - 4. * p_r)) +
441 p / ((1. / 2.) - p_r));
442 if (r < 0) {
443 r = (1. - 4. * p_r) / (2. - 4. * p_r) +
444 TMath::Sqrt(((1. - 4. * p_r) / (2. - 4. * p_r)) *
445 ((1. - 4. * p_r) / (2. - 4. * p_r)) +
446 p / ((1. / 2.) - p_r));
447 }
448
449 R_min = R_min + r / 2 * (R_max - R_min);
450 R_max = R_min;
451}
452
453std::tuple<float, float, float>
455 TFCSSimulationState &simulstate, long unsigned int layer_index,
456 long unsigned int hit_index) const {
457
460 simulstate.getAuxInfo<void *>("BSEventData"_FCShash));
461
462 float e_init = simulstate.getAuxInfo<float>("BSEinit"_FCShash);
463
464 if (layer_index >= event->event_data.size()) {
465 ATH_MSG_ERROR("Layer index out of bounds: " << layer_index << " >= "
466 << event->event_data.size());
467 return std::make_tuple(0.0f, 0.0f, 0.0f);
468 }
469
470 long unsigned int energy_index = get_energy_index(
471 simulstate, layer_index, hit_index); // Get the bin index for the hit
472
473 std::vector<std::vector<long unsigned int>> *hits_per_layer_ptr =
474 static_cast<std::vector<std::vector<long unsigned int>> *>(
475 simulstate.getAuxInfo<void *>("BSNHits"_FCShash));
476
477 long unsigned int hits_per_bin;
478 if (energy_index == 0) {
479 hits_per_bin = hits_per_layer_ptr->at(layer_index).at(energy_index);
480 } else {
481 hits_per_bin = hits_per_layer_ptr->at(layer_index).at(energy_index) -
482 hits_per_layer_ptr->at(layer_index).at(energy_index - 1);
483 }
484
485 float r, alpha;
486
487 TFCSMLCalorimeterSimulator::layer_t &layer = event->event_data.at(layer_index);
488
489 std::tie(r, alpha) = get_coordinates(simulstate, layer_index,
490 layer.bin_index_vector.at(energy_index));
491
492 float E = layer.E_vector.at(energy_index) * e_init / hits_per_bin;
493
494 return std::make_tuple(r, alpha, E);
495}
496
498 // Delete the event data
499 void *event_ptr = simulstate.getAuxInfo<void *>("BSEventData"_FCShash);
500 if (event_ptr) {
501 delete static_cast<TFCSMLCalorimeterSimulator::event_t *>(event_ptr);
502 simulstate.setAuxInfo<void *>("BSEventData"_FCShash, nullptr);
503 } else {
504 ATH_MSG_ERROR("No event data found to delete.");
505 }
506
507 void *n_hits_ptr = simulstate.getAuxInfo<void *>("BSNHits"_FCShash);
508 if (n_hits_ptr) {
509 delete static_cast<std::vector<std::vector<long unsigned int>> *>(
510 n_hits_ptr);
511 simulstate.setAuxInfo<void *>("BSNHits"_FCShash, nullptr);
512 } else {
513 ATH_MSG_ERROR("No event hits data found to delete.");
514 }
515
516 void *elayer_ptr = simulstate.getAuxInfo<void *>("BSELayer"_FCShash);
517 if (elayer_ptr) {
518 delete static_cast<std::vector<float> *>(elayer_ptr);
519 simulstate.setAuxInfo<void *>("BSELayer"_FCShash, nullptr);
520 } else {
521 ATH_MSG_ERROR("No event layer energy data found to delete.");
522 }
523
524 return;
525}
526
528 const std::string &filename) {
529 m_use_upscaling = true;
530 TFile *file = TFile::Open(filename.c_str(), "READ");
531 if (!file || file->IsZombie()) {
532 ATH_MSG_ERROR("Failed to open file: " << filename);
533 delete file;
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)
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:359
TFile * file