diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index 287536ff118f7..02caa63df0d43 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -41,8 +41,6 @@ o2_add_library(Generators src/GeneratorTParticleParam.cxx src/GeneratorService.cxx src/FlowMapper.cxx - src/TPCLoopers.cxx - src/TPCLoopersParam.cxx $<$:src/GeneratorPythia8.cxx> $<$:src/DecayerPythia8.cxx> $<$:src/GeneratorPythia8Param.cxx> @@ -55,7 +53,6 @@ o2_add_library(Generators PUBLIC_LINK_LIBRARIES FairRoot::Base O2::SimConfig O2::CommonUtils O2::DetectorsBase O2::ZDCBase O2::SimulationDataFormat ${pythiaTarget} ${hepmcTarget} FairRoot::Gen - onnxruntime::onnxruntime TARGETVARNAME targetName) if(pythia_FOUND) @@ -66,8 +63,6 @@ if(HepMC3_FOUND) target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_HEPMC3) endif() -target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_TPCLOOPERS) - set(headers include/Generators/Generator.h include/Generators/Trigger.h @@ -93,10 +88,6 @@ set(headers include/Generators/FlowMapper.h ) -list(APPEND headers - include/Generators/TPCLoopers.h - include/Generators/TPCLoopersParam.h) - if(pythia_FOUND) list(APPEND headers include/Generators/GeneratorPythia8.h @@ -167,5 +158,4 @@ endif() o2_data_file(COPY share/external DESTINATION Generators) o2_data_file(COPY share/egconfig DESTINATION Generators) -o2_data_file(COPY share/TPCLoopers DESTINATION Generators) o2_data_file(COPY share/pythia8 DESTINATION Generators) diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index 3484601aa42bb..bd35a00793e2d 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -17,10 +17,6 @@ #include "FairGenerator.h" #include "TParticle.h" #include "Generators/Trigger.h" -#ifdef GENERATORS_WITH_TPCLOOPERS -#include "Generators/TPCLoopers.h" -#include "Generators/TPCLoopersParam.h" -#endif #include #include #include @@ -77,7 +73,6 @@ class Generator : public FairGenerator /** methods to override **/ virtual Bool_t generateEvent() = 0; // generates event (in structure internal to generator) virtual Bool_t importParticles() = 0; // fills the mParticles vector (transfer from generator state) - Bool_t finalizeEvent(); // final part of event generation that can be customised using external macros virtual void updateHeader(o2::dataformats::MCEventHeader* eventHeader) {}; Bool_t triggerEvent(); @@ -159,8 +154,6 @@ class Generator : public FairGenerator private: void updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const; - // loopers flag - Bool_t mAddTPCLoopers = kFALSE; // Flag is automatically set to true if TPC is in readout detectors, loopers are not vetoed and transport is enabled // collect an ID and a short description of sub-generator entities std::unordered_map mSubGeneratorsIdToDesc; // the current ID of the sub-generator used in the current event (if applicable) @@ -169,12 +162,6 @@ class Generator : public FairGenerator // global static information about (upper limit of) number of events to be generated static unsigned int gTotalNEvents; -#ifdef GENERATORS_WITH_TPCLOOPERS - // Loopers generator instance - std::unique_ptr mTPCLoopersGen = nullptr; - bool initTPCLoopersGen(); -#endif - ClassDefOverride(Generator, 2); }; /** class Generator **/ diff --git a/Generators/include/Generators/TPCLoopers.h b/Generators/include/Generators/TPCLoopers.h deleted file mode 100644 index 6a1d3ef262e22..0000000000000 --- a/Generators/include/Generators/TPCLoopers.h +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2024-2025 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \author M+Giacalone - September 2025 - -#ifndef ALICEO2_EVENTGEN_TPCLOOPERS_H_ -#define ALICEO2_EVENTGEN_TPCLOOPERS_H_ - -#ifdef GENERATORS_WITH_TPCLOOPERS -#include -#endif -#include -#include -#include "TRandom3.h" -#include -#include "TParticle.h" - -#ifdef GENERATORS_WITH_TPCLOOPERS -// Static Ort::Env instance for multiple onnx model loading -extern Ort::Env global_env; - -// This class is responsible for loading the scaler parameters from a JSON file -// and applying the inverse transformation to the generated data. -// Inferenced output is scaled (min-max normalization or robust scaling for outlier features) during training, -// so we need to revert this transformation to get physical values. -struct Scaler { - std::vector normal_min; - std::vector normal_max; - std::vector outlier_center; - std::vector outlier_scale; - - void load(const std::string& filename); - - std::vector inverse_transform(const std::vector& input); - - private: - std::vector jsonArrayToVector(const rapidjson::Value& jsonArray); -}; - -// This class loads the ONNX model and generates samples using it. -class ONNXGenerator -{ - public: - ONNXGenerator(Ort::Env& shared_env, const std::string& model_path); - - std::vector generate_sample(); - - private: - Ort::Env& env; - Ort::Session session; - TRandom3 rand_gen; -}; -#endif // GENERATORS_WITH_TPCLOOPERS - -namespace o2 -{ -namespace eventgen -{ - -#ifdef GENERATORS_WITH_TPCLOOPERS -/** - * Generator for TPC Loopers based on pre-trained ONNX models. - * Currently it generates loopers as electron-positron pairs and Compton electrons - * according to specified distributions and parameters. - * This can be extended to other types of background processes in the future (e.g. slow neutron spallation products, saturation tail). - * Multiple configuration options are available: - * - Flat gas: loopers are generated uniformly per event taking a reference value which can be either the LHC orbit time or the average interaction time record interval from the collision context. - * ==> Current automatic setup (default) sets the interaction rate automatically from the collision context and the reference value per orbit is calculated from an external file. - * ==> Number of loopers per orbit can be adjusted via a specific parameter. - * - Poisson + Gaussian sampling: number of loopers are sampled from Poissonian (for pairs) and Gaussian (for Compton electrons) distributions based on provided parameters. - * ==> flat gas must be disabled to use this option. - * - Fixed number of loopers per event - * ==> flat gas must be disabled to use this option and Poissonian/Gaussian parameters file should be set to None - */ -class GenTPCLoopers -{ - public: - GenTPCLoopers(std::string model_pairs = "tpcloopmodel.onnx", std::string model_compton = "tpcloopmodelcompton.onnx", - std::string poisson = "poisson.csv", std::string gauss = "gauss.csv", std::string scaler_pair = "scaler_pair.json", - std::string scaler_compton = "scaler_compton.json"); - - Bool_t generateEvent(); - - Bool_t generateEvent(double time_limit); - - std::vector importParticles(); - - unsigned int PoissonPairs(); - - unsigned int GaussianElectrons(); - - void SetNLoopers(unsigned int nsig_pair, unsigned int nsig_compton); - - void SetMultiplier(const std::array& mult); - - void setFlatGas(Bool_t flat, Int_t number = -1, Int_t nloopers_orbit = -1); - - void setFractionPairs(float fractionPairs); - - void SetRate(const std::string& rateFile, bool isPbPb, int intRate = 50000); - - void SetAdjust(float adjust = 0.f); - - unsigned int getNLoopers() const { return (mNLoopersPairs + mNLoopersCompton); } - - private: - std::unique_ptr mONNX_pair = nullptr; - std::unique_ptr mONNX_compton = nullptr; - std::unique_ptr mScaler_pair = nullptr; - std::unique_ptr mScaler_compton = nullptr; - double mPoisson[3] = {0.0, 0.0, 0.0}; // Mu, Min and Max of Poissonian - double mGauss[4] = {0.0, 0.0, 0.0, 0.0}; // Mean, Std, Min, Max - std::vector> mGenPairs; - std::vector> mGenElectrons; - unsigned int mNLoopersPairs = -1; - unsigned int mNLoopersCompton = -1; - std::array mMultiplier = {1., 1.}; - bool mPoissonSet = false; - bool mGaussSet = false; - // Random number generator - TRandom3 mRandGen; - int mCurrentEvent = 0; // Current event number, used for adaptive loopers - TFile* mContextFile = nullptr; // Input collision context file - o2::steer::DigitizationContext* mCollisionContext = nullptr; // Pointer to the digitization context - std::vector mInteractionTimeRecords; // Interaction time records from collision context - Bool_t mFlatGas = false; // Flag to indicate if flat gas loopers are used - Bool_t mFlatGasOrbit = false; // Flag to indicate if flat gas loopers are per orbit - Int_t mFlatGasNumber = -1; // Number of flat gas loopers per event - double mIntTimeRecMean = 1.0; // Average interaction time record used for the reference - double mTimeLimit = 0.0; // Time limit for the current event - double mTimeEnd = 0.0; // Time limit for the last event - float mLoopsFractionPairs = 0.08; // Fraction of loopers from Pairs - int mInteractionRate = 50000; // Interaction rate in Hz -}; -#endif // GENERATORS_WITH_TPCLOOPERS - -} // namespace eventgen -} // namespace o2 - -#endif // ALICEO2_EVENTGEN_TPCLOOPERS_H_ \ No newline at end of file diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h deleted file mode 100644 index 87e4510d6e617..0000000000000 --- a/Generators/include/Generators/TPCLoopersParam.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2024-2025 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \author M+Giacalone - September 2025 - -#ifndef ALICEO2_EVENTGEN_TPCLOOPERSPARAM_H_ -#define ALICEO2_EVENTGEN_TPCLOOPERSPARAM_H_ - -#include "CommonUtils/ConfigurableParam.h" -#include "CommonUtils/ConfigurableParamHelper.h" - -namespace o2 -{ -namespace eventgen -{ - -/** - ** a parameter class/struct to keep the settings of - ** the TPC loopers event-generator and - ** allow the user to modify them - **/ -struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper { - bool loopersVeto = false; // if true, no loopers are generated - // Current files are set to custom user CCDB paths, TO BE CHANGED - std::string model_pairs = "ccdb://Users/m/mgiacalo/WGAN_ExtGenPair"; // ONNX model for e+e- pair production - std::string model_compton = "ccdb://Users/m/mgiacalo/WGAN_ExtGenCompton"; // ONNX model for Compton scattering - std::string poisson = "${O2_ROOT}/share/Generators/TPCLoopers/poisson_params.csv"; // file with Poissonian parameters - std::string gauss = "${O2_ROOT}/share/Generators/TPCLoopers/gaussian_params.csv"; // file with Gaussian parameters - std::string scaler_pair = "${O2_ROOT}/share/Generators/TPCLoopers/ScalerPairParams.json"; // file with scaler parameters for e+e- pair production - std::string scaler_compton = "${O2_ROOT}/share/Generators/TPCLoopers/ScalerComptonParams.json"; // file with scaler parameters for Compton scattering - std::string nclxrate = "ccdb://Users/m/mgiacalo/ClustersTrackRatio"; // file with clusters/rate information per orbit - std::string colsys = "PbPb"; // collision system (PbPb or pp) - int intrate = -1; // Automatic IR from collision context if -1, else user-defined interaction rate in Hz - bool flat_gas = true; // if true, the gas density is considered flat in the TPC volume - unsigned int nFlatGasLoopers = 500; // number of loopers to be generated per event in case of flat gas [currently unused, kept for possible future debug developments] - float fraction_pairs = 0.08; // fraction of loopers [currently unused, kept for possible future debug developments] - float multiplier[2] = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling - unsigned int fixedNLoopers[2] = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty - float adjust_flatgas = 0.f; // adjustment for the number of flat gas loopers per orbit (in percentage, e.g. -0.1 = -10%) [-1, inf)] - O2ParamDef(GenTPCLoopersParam, "GenTPCLoopers"); -}; - -} // end namespace eventgen -} // end namespace o2 - -#endif // ALICEO2_EVENTGEN_TPCLOOPERSPARAM_H_ diff --git a/Generators/share/TPCLoopers/README.md b/Generators/share/TPCLoopers/README.md deleted file mode 100644 index 0e0ac858b8809..0000000000000 --- a/Generators/share/TPCLoopers/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# TPC Loopers Generator - Parameter Files - -This directory contains parameter files used by the TPC Loopers event generator in ALICE O2. - -## Overview - -The TPC Loopers generator uses pre-trained ONNX models to generate realistic looper particles based on machine learning models trained on full GEANT4 slow neutron transport simulations. The parameter files in this directory provide: -- Example statistical distribution parameters for sampling the number of loopers per event -- **Mandatory** scaling parameters for transforming the ONNX model outputs to physical values - -## Files Description - -### Statistical Sampling Parameters - -The files provided in the folder are examples based on the training dataset. - -#### `gaussian_params.csv` -Parameters for Gaussian distribution used to sample the number of Compton electrons per event. - -**Format:** Four values (one per line) -1. Mean (μ) -2. Standard deviation (σ) -3. Minimum value -4. Maximum value - -#### `poisson_params.csv` -Parameters for Poisson distribution used to sample the number of electron-positron pairs per event. - -**Format:** Three values (one per line) -1. Lambda (λ) parameter -2. Minimum value -3. Maximum value - -### Scaler Parameters - -These JSON files contain the parameters for inverse transformation of the ONNX models output. They should be kept as they are -unless a new version of the models is released. - -#### `ScalerComptonParams.json` -Scaler parameters for Compton electron generation model. - -**Structure:** -```json -{ - "normal": { - "min": [array of 5 min values for min-max normalization], - "max": [array of 5 max values for min-max normalization] - }, - "outlier": { - "center": [array of 2 center values for robust scaling], - "scale": [array of 2 scale values for robust scaling] - } -} -``` - -- **normal**: Min-max normalization parameters for standard features (`Px`, `Py`, `Pz`, `VertexCoordinatesX`, `VertexCoordinatesY`) -- **outlier**: Robust scaler parameters (center and scale) for outlier features (`VertexCoordinatesZ`,`time`) - -#### `ScalerPairParams.json` -Scaler parameters for electron-positron pair generation model. - -**Structure:** -```json -{ - "normal": { - "min": [array of 8 min values for min-max normalization], - "max": [array of 8 max values for min-max normalization] - }, - "outlier": { - "center": [array of 2 center values for robust scaling], - "scale": [array of 2 scale values for robust scaling] - } -} -``` - -- **normal**: Min-max normalization parameters for standard features (`Px_e`, `Py_e`, `Pz_e`,`Px_p`, `Py_p`, `Pz_p`, `VertexCoordinatesX`, `VertexCoordinatesY`) -- **outlier**: Robust scaler parameters (center and scale) for outlier features (`VertexCoordinatesZ`,`time`) ---- -*Author: M. Giacalone - September 2025* diff --git a/Generators/share/TPCLoopers/ScalerComptonParams.json b/Generators/share/TPCLoopers/ScalerComptonParams.json deleted file mode 100644 index 157647fee2db7..0000000000000 --- a/Generators/share/TPCLoopers/ScalerComptonParams.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "normal": { - "min": [ - -0.0108811147511005, - -0.0098758740350604, - -0.0103233363479375, - -260.0542297363281, - -259.80059814453125 - ], - "max": [ - 0.0108060473576188, - 0.0103057539090514, - 0.0106524610891938, - 260.0343933105469, - 259.62890625 - ] - }, - "outlier": { - "center": [ - -71.39387130737305, - 96791.23828125 - ], - "scale": [ - 265.9389114379883, - 230762.30981445312 - ] - } -} \ No newline at end of file diff --git a/Generators/share/TPCLoopers/ScalerPairParams.json b/Generators/share/TPCLoopers/ScalerPairParams.json deleted file mode 100644 index 57cdac421d3f6..0000000000000 --- a/Generators/share/TPCLoopers/ScalerPairParams.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "normal": { - "min": [ - -0.0073022879660129, - -0.0077305701561272, - -0.0076750442385673, - -0.0082916170358657, - -0.0079681202769279, - -0.0077468422241508, - -255.6164093017578, - -252.9441680908203 - ], - "max": [ - 0.007688719779253, - 0.0077241472899913, - 0.0075828479602932, - 0.00813714787364, - 0.0083825681358575, - 0.0073839174583554, - 256.2904968261719, - 253.4925842285156 - ] - }, - "outlier": { - "center": [ - -79.66580963134766, - 141535.640625 - ], - "scale": [ - 250.8921127319336, - 222363.16015625 - ] - } -} \ No newline at end of file diff --git a/Generators/share/TPCLoopers/gaussian_params.csv b/Generators/share/TPCLoopers/gaussian_params.csv deleted file mode 100644 index 8e07c22dd30bf..0000000000000 --- a/Generators/share/TPCLoopers/gaussian_params.csv +++ /dev/null @@ -1,4 +0,0 @@ -9.611554230339172022e+01 -1.963570744941765867e+01 -4.300000000000000000e+01 -1.690000000000000000e+02 diff --git a/Generators/share/TPCLoopers/poisson_params.csv b/Generators/share/TPCLoopers/poisson_params.csv deleted file mode 100644 index ef26bd973d34c..0000000000000 --- a/Generators/share/TPCLoopers/poisson_params.csv +++ /dev/null @@ -1,3 +0,0 @@ -3.165383056343737511e+00 -1.000000000000000000e+00 -1.200000000000000000e+01 diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 465a8ffb7ee22..9204ede98215e 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -17,16 +17,11 @@ #include "SimulationDataFormat/MCEventHeader.h" #include "SimulationDataFormat/ParticleStatus.h" #include "SimulationDataFormat/MCGenProperties.h" -#include #include "FairPrimaryGenerator.h" #include #include #include "TClonesArray.h" #include "TParticle.h" -#include "TSystem.h" -#include "TGrid.h" -#include "CCDB/BasicCCDBManager.h" -#include namespace o2 { @@ -44,25 +39,6 @@ Generator::Generator() : FairGenerator("ALICEo2", "ALICEo2 Generator"), /** default constructor **/ mThisInstanceID = Generator::InstanceCounter; Generator::InstanceCounter++; -#ifdef GENERATORS_WITH_TPCLOOPERS - const auto& simConfig = o2::conf::SimConfig::Instance(); - const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); - if (!loopersParam.loopersVeto) { - bool transport = (simConfig.getMCEngine() != "O2TrivialMCEngine"); - if (transport) { - bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); - if (tpcActive) { - if (initTPCLoopersGen()) { - mAddTPCLoopers = kTRUE; - } - } else { - LOG(info) << "TPC not active in readout detectors: loopers fast generator disabled."; - } - } - } else { - LOG(info) << "Loopers fast generator turned OFF with veto flag."; - } -#endif } /*****************************************************************/ @@ -73,126 +49,7 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na /** constructor **/ mThisInstanceID = Generator::InstanceCounter; Generator::InstanceCounter++; -#ifdef GENERATORS_WITH_TPCLOOPERS - const auto& simConfig = o2::conf::SimConfig::Instance(); - const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); - if (!loopersParam.loopersVeto) { - bool transport = (simConfig.getMCEngine() != "O2TrivialMCEngine"); - if (transport) { - bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); - if (tpcActive) { - if (initTPCLoopersGen()) { - mAddTPCLoopers = kTRUE; - } - } else { - LOG(info) << "TPC not active in readout detectors: loopers fast generator disabled."; - } - } - } else { - LOG(info) << "Loopers fast generator turned OFF with veto flag."; - } -#endif -} - -/*****************************************************************/ -#ifdef GENERATORS_WITH_TPCLOOPERS -bool Generator::initTPCLoopersGen() -{ - // Expand all environment paths - const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); - std::string model_pairs = gSystem->ExpandPathName(loopersParam.model_pairs.c_str()); - std::string model_compton = gSystem->ExpandPathName(loopersParam.model_compton.c_str()); - std::string nclxrate = gSystem->ExpandPathName(loopersParam.nclxrate.c_str()); - const auto& scaler_pair = gSystem->ExpandPathName(loopersParam.scaler_pair.c_str()); - const auto& scaler_compton = gSystem->ExpandPathName(loopersParam.scaler_compton.c_str()); - const auto& poisson = gSystem->ExpandPathName(loopersParam.poisson.c_str()); - const auto& gauss = gSystem->ExpandPathName(loopersParam.gauss.c_str()); - const auto& flat_gas = loopersParam.flat_gas; - const auto& colsys = loopersParam.colsys; - if (flat_gas) { - if (colsys != "PbPb" && colsys != "pp") { - LOG(warning) << "Automatic background loopers configuration supports only 'pp' and 'PbPb' systems."; - LOG(warning) << "Fast loopers generator will remain OFF."; - return kFALSE; - } - bool isContext = std::filesystem::exists("collisioncontext.root"); - if (!isContext) { - LOG(warning) << "Warning: No collisioncontext.root file found!"; - LOG(warning) << "Loopers will be kept OFF."; - return kFALSE; - } - } - std::array multiplier = {loopersParam.multiplier[0], loopersParam.multiplier[1]}; - unsigned int nLoopersPairs = loopersParam.fixedNLoopers[0]; - unsigned int nLoopersCompton = loopersParam.fixedNLoopers[1]; - const std::array models = {model_pairs, model_compton, nclxrate}; - const std::array local_names = {"WGANpair.onnx", "WGANcompton.onnx", "nclxrate.root"}; - const std::array isAlien = {models[0].starts_with("alien://"), models[1].starts_with("alien://"), models[2].starts_with("alien://")}; - const std::array isCCDB = {models[0].starts_with("ccdb://"), models[1].starts_with("ccdb://"), models[2].starts_with("ccdb://")}; - if (std::any_of(isAlien.begin(), isAlien.end(), [](bool v) { return v; })) { - if (!gGrid) { - TGrid::Connect("alien://"); - if (!gGrid) { - LOG(fatal) << "AliEn connection failed, check token."; - exit(1); - } - } - for (size_t i = 0; i < models.size(); ++i) { - if (isAlien[i] && !TFile::Cp(models[i].c_str(), local_names[i].c_str())) { - LOG(fatal) << "Error: Model file " << models[i] << " does not exist!"; - exit(1); - } - } - } - if (std::any_of(isCCDB.begin(), isCCDB.end(), [](bool v) { return v; })) { - auto& ccdb = o2::ccdb::BasicCCDBManager::instance(); - ccdb.setURL("http://alice-ccdb.cern.ch"); - // Get underlying CCDB API from BasicCCDBManager - auto& ccdb_api = ccdb.getCCDBAccessor(); - for (size_t i = 0; i < models.size(); ++i) { - if (isCCDB[i]) { - auto model_path = models[i].substr(7); // Remove "ccdb://" - // Treat filename if provided in the CCDB path - auto extension = model_path.find(".onnx"); - if (extension != std::string::npos) { - auto last_slash = model_path.find_last_of('/'); - model_path = model_path.substr(0, last_slash); - } - std::map filter; - if (!ccdb_api.retrieveBlob(model_path, "./", filter, o2::ccdb::getCurrentTimestamp(), false, local_names[i].c_str())) { - LOG(fatal) << "Error: issues in retrieving " << model_path << " from CCDB!"; - exit(1); - } - } - } - } - model_pairs = isAlien[0] || isCCDB[0] ? local_names[0] : model_pairs; - model_compton = isAlien[1] || isCCDB[1] ? local_names[1] : model_compton; - nclxrate = isAlien[2] || isCCDB[2] ? local_names[2] : nclxrate; - try { - // Create the TPC loopers generator with the provided parameters - mTPCLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); - const auto& intrate = loopersParam.intrate; - // Configure the generator with flat gas loopers defined per orbit with clusters/track info - // If intrate is negative (default), automatic IR from collisioncontext.root will be used - if (flat_gas) { - mTPCLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate); - mTPCLoopersGen->SetAdjust(loopersParam.adjust_flatgas); - } else { - // Otherwise, Poisson+Gauss sampling or fixed number of loopers per event will be used - // Multiplier is applied only with distribution sampling - // This configuration can be used for testing purposes, in all other cases flat gas is recommended - mTPCLoopersGen->SetNLoopers(nLoopersPairs, nLoopersCompton); - mTPCLoopersGen->SetMultiplier(multiplier); - } - LOG(info) << "TPC Loopers generator initialized successfully"; - } catch (const std::exception& e) { - LOG(error) << "Failed to initialize TPC Loopers generator: " << e.what(); - mTPCLoopersGen.reset(); - } - return kTRUE; } -#endif /*****************************************************************/ @@ -207,41 +64,6 @@ Bool_t /*****************************************************************/ -Bool_t - Generator::finalizeEvent() -{ -#ifdef GENERATORS_WITH_TPCLOOPERS - if (mAddTPCLoopers) { - if (!mTPCLoopersGen) { - LOG(error) << "Loopers generator not initialized"; - return kFALSE; - } - - // Generate loopers using the initialized TPC loopers generator - if (!mTPCLoopersGen->generateEvent()) { - LOG(error) << "Failed to generate loopers event"; - return kFALSE; - } - if (mTPCLoopersGen->getNLoopers() == 0) { - LOG(warning) << "No loopers generated for this event"; - return kTRUE; - } - const auto& looperParticles = mTPCLoopersGen->importParticles(); - if (looperParticles.empty()) { - LOG(error) << "Failed to import loopers particles"; - return kFALSE; - } - // Append the generated looper particles to the main particle list - mParticles.insert(mParticles.end(), looperParticles.begin(), looperParticles.end()); - - LOG(debug) << "Added " << looperParticles.size() << " looper particles"; - } -#endif - return kTRUE; -} - -/*****************************************************************/ - Bool_t Generator::ReadEvent(FairPrimaryGenerator* primGen) { @@ -269,12 +91,6 @@ Bool_t return kFALSE; } - /** Event finalization**/ - if (!finalizeEvent()) { - LOG(error) << "ReadEvent failed in finalizeEvent"; - return kFALSE; - } - if (mSubGeneratorsIdToDesc.empty() && mSubGeneratorId > -1) { LOG(fatal) << "ReadEvent failed because no SubGenerator description given"; } diff --git a/Generators/src/GeneratorsLinkDef.h b/Generators/src/GeneratorsLinkDef.h index 24b3f2e452498..2b8d42f86bf9b 100644 --- a/Generators/src/GeneratorsLinkDef.h +++ b/Generators/src/GeneratorsLinkDef.h @@ -35,10 +35,6 @@ #pragma link C++ class o2::eventgen::GeneratorFromEventPool + ; #pragma link C++ class o2::eventgen::GeneratorEventPoolParam + ; #pragma link C++ class o2::eventgen::EventPoolGenConfig + ; -#ifdef GENERATORS_WITH_TPCLOOPERS -#pragma link C++ class o2::eventgen::GenTPCLoopers + ; -#pragma link C++ class o2::eventgen::GenTPCLoopersParam + ; -#endif #pragma link C++ class o2::conf::ConfigurableParamPromoter < o2::eventgen::GeneratorEventPoolParam, o2::eventgen::EventPoolGenConfig> + ; #ifdef GENERATORS_WITH_HEPMC3 #pragma link C++ class o2::eventgen::GeneratorHepMC + ; diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx deleted file mode 100644 index 6e5af7c0c84d8..0000000000000 --- a/Generators/src/TPCLoopers.cxx +++ /dev/null @@ -1,486 +0,0 @@ -// Copyright 2024-2025 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \author M+Giacalone - September 2025 - -#include "Generators/TPCLoopers.h" -#include "CCDB/CCDBTimeStampUtils.h" -#include "CCDB/CcdbApi.h" -#include "DetectorsRaw/HBFUtils.h" -#include "TF1.h" -#include -#include -#include "SimulationDataFormat/MCGenProperties.h" -#include -#include -#include "TDatabasePDG.h" - -// Static Ort::Env instance for multiple onnx model loading -Ort::Env global_env(ORT_LOGGING_LEVEL_WARNING, "GlobalEnv"); - -// This class is responsible for loading the scaler parameters from a JSON file -// and applying the inverse transformation to the generated data. - -void Scaler::load(const std::string& filename) -{ - std::ifstream file(filename); - if (!file.is_open()) { - throw std::runtime_error("Error: Could not open scaler file!"); - } - - std::string json_str((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - file.close(); - - rapidjson::Document doc; - doc.Parse(json_str.c_str()); - - if (doc.HasParseError()) { - throw std::runtime_error("Error: JSON parsing failed!"); - } - - normal_min = jsonArrayToVector(doc["normal"]["min"]); - normal_max = jsonArrayToVector(doc["normal"]["max"]); - outlier_center = jsonArrayToVector(doc["outlier"]["center"]); - outlier_scale = jsonArrayToVector(doc["outlier"]["scale"]); -} - -std::vector Scaler::inverse_transform(const std::vector& input) -{ - std::vector output; - for (int i = 0; i < input.size(); ++i) { - if (i < input.size() - 2) { - output.push_back(input[i] * (normal_max[i] - normal_min[i]) + normal_min[i]); - } else { - output.push_back(input[i] * outlier_scale[i - (input.size() - 2)] + outlier_center[i - (input.size() - 2)]); - } - } - - return output; -} - -std::vector Scaler::jsonArrayToVector(const rapidjson::Value& jsonArray) -{ - std::vector vec; - for (int i = 0; i < jsonArray.Size(); ++i) { - vec.push_back(jsonArray[i].GetDouble()); - } - return vec; -} - -// This class loads the ONNX model and generates samples using it. - -ONNXGenerator::ONNXGenerator(Ort::Env& shared_env, const std::string& model_path) - : env(shared_env), session(env, model_path.c_str(), Ort::SessionOptions{}) -{ - // Create session options - Ort::SessionOptions session_options; - session = Ort::Session(env, model_path.c_str(), session_options); -} - -std::vector ONNXGenerator::generate_sample() -{ - Ort::AllocatorWithDefaultOptions allocator; - - // Generate a latent vector (z) - std::vector z(100); - for (auto& v : z) { - v = rand_gen.Gaus(0.0, 1.0); - } - - // Prepare input tensor - std::vector input_shape = {1, 100}; - // Get memory information - Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); - - // Create input tensor correctly - Ort::Value input_tensor = Ort::Value::CreateTensor( - memory_info, z.data(), z.size(), input_shape.data(), input_shape.size()); - // Run inference - const char* input_names[] = {"z"}; - const char* output_names[] = {"output"}; - auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor, 1, output_names, 1); - - // Extract output - float* output_data = output_tensors.front().GetTensorMutableData(); - // Get the size of the output tensor - auto output_tensor_info = output_tensors.front().GetTensorTypeAndShapeInfo(); - size_t output_data_size = output_tensor_info.GetElementCount(); // Total number of elements in the tensor - std::vector output; - for (int i = 0; i < output_data_size; ++i) { - output.push_back(output_data[i]); - } - - return output; -} - -namespace o2 -{ -namespace eventgen -{ - -GenTPCLoopers::GenTPCLoopers(std::string model_pairs, std::string model_compton, - std::string poisson, std::string gauss, std::string scaler_pair, - std::string scaler_compton) -{ - // Checking if the model files exist and are not empty - std::ifstream model_file[2]; - model_file[0].open(model_pairs); - model_file[1].open(model_compton); - if (!model_file[0].is_open() || model_file[0].peek() == std::ifstream::traits_type::eof()) { - LOG(fatal) << "Error: Pairs model file is empty or does not exist!"; - exit(1); - } - if (!model_file[1].is_open() || model_file[1].peek() == std::ifstream::traits_type::eof()) { - LOG(fatal) << "Error: Compton model file is empty or does not exist!"; - exit(1); - } - model_file[0].close(); - model_file[1].close(); - // Checking if the scaler files exist and are not empty - std::ifstream scaler_file[2]; - scaler_file[0].open(scaler_pair); - scaler_file[1].open(scaler_compton); - if (!scaler_file[0].is_open() || scaler_file[0].peek() == std::ifstream::traits_type::eof()) { - LOG(fatal) << "Error: Pairs scaler file is empty or does not exist!"; - exit(1); - } - if (!scaler_file[1].is_open() || scaler_file[1].peek() == std::ifstream::traits_type::eof()) { - LOG(fatal) << "Error: Compton scaler file is empty or does not exist!"; - exit(1); - } - scaler_file[0].close(); - scaler_file[1].close(); - // Checking if the poisson file exists and it's not empty - if (poisson != "" && poisson != "None" && poisson != "none") { - std::ifstream poisson_file(poisson); - if (!poisson_file.is_open() || poisson_file.peek() == std::ifstream::traits_type::eof()) { - LOG(fatal) << "Error: Poisson file is empty or does not exist!"; - exit(1); - } else { - poisson_file >> mPoisson[0] >> mPoisson[1] >> mPoisson[2]; - poisson_file.close(); - mPoissonSet = true; - } - } - // Checking if the gauss file exists and it's not empty - if (gauss != "" && gauss != "None" && gauss != "none") { - std::ifstream gauss_file(gauss); - if (!gauss_file.is_open() || gauss_file.peek() == std::ifstream::traits_type::eof()) { - LOG(fatal) << "Error: Gauss file is empty or does not exist!"; - exit(1); - } else { - gauss_file >> mGauss[0] >> mGauss[1] >> mGauss[2] >> mGauss[3]; - gauss_file.close(); - mGaussSet = true; - } - } - mONNX_pair = std::make_unique(global_env, model_pairs); - mScaler_pair = std::make_unique(); - mScaler_pair->load(scaler_pair); - mONNX_compton = std::make_unique(global_env, model_compton); - mScaler_compton = std::make_unique(); - mScaler_compton->load(scaler_compton); -} - -Bool_t GenTPCLoopers::generateEvent() -{ - // Clear the vector of pairs - mGenPairs.clear(); - // Clear the vector of compton electrons - mGenElectrons.clear(); - if (mFlatGas) { - unsigned int nLoopers, nLoopersPairs, nLoopersCompton; - LOG(debug) << "mCurrentEvent is " << mCurrentEvent; - LOG(debug) << "Current event time: " << ((mCurrentEvent < mInteractionTimeRecords.size() - 1) ? std::to_string(mInteractionTimeRecords[mCurrentEvent + 1].bc2ns() - mInteractionTimeRecords[mCurrentEvent].bc2ns()) : std::to_string(mTimeEnd - mInteractionTimeRecords[mCurrentEvent].bc2ns())) << " ns"; - LOG(debug) << "Current time offset wrt BC: " << mInteractionTimeRecords[mCurrentEvent].getTimeOffsetWrtBC() << " ns"; - mTimeLimit = (mCurrentEvent < mInteractionTimeRecords.size() - 1) ? mInteractionTimeRecords[mCurrentEvent + 1].bc2ns() - mInteractionTimeRecords[mCurrentEvent].bc2ns() : mTimeEnd - mInteractionTimeRecords[mCurrentEvent].bc2ns(); - // With flat gas the number of loopers are adapted based on time interval widths - // The denominator is either the LHC orbit (if mFlatGasOrbit is true) or the mean interaction time record interval - nLoopers = mFlatGasOrbit ? (mFlatGasNumber * (mTimeLimit / o2::constants::lhc::LHCOrbitNS)) : (mFlatGasNumber * (mTimeLimit / mIntTimeRecMean)); - nLoopersPairs = static_cast(std::round(nLoopers * mLoopsFractionPairs)); - nLoopersCompton = nLoopers - nLoopersPairs; - SetNLoopers(nLoopersPairs, nLoopersCompton); - LOG(info) << "Flat gas loopers: " << nLoopers << " (pairs: " << nLoopersPairs << ", compton: " << nLoopersCompton << ")"; - generateEvent(mTimeLimit); - mCurrentEvent++; - } else { - // Set number of loopers if poissonian params are available - if (mPoissonSet) { - mNLoopersPairs = static_cast(std::round(mMultiplier[0] * PoissonPairs())); - LOG(debug) << "Generated loopers pairs (Poisson): " << mNLoopersPairs; - } - if (mGaussSet) { - mNLoopersCompton = static_cast(std::round(mMultiplier[1] * GaussianElectrons())); - LOG(debug) << "Generated compton electrons (Gauss): " << mNLoopersCompton; - } - // Generate pairs - for (int i = 0; i < mNLoopersPairs; ++i) { - std::vector pair = mONNX_pair->generate_sample(); - // Apply the inverse transformation using the scaler - std::vector transformed_pair = mScaler_pair->inverse_transform(pair); - mGenPairs.push_back(transformed_pair); - } - // Generate compton electrons - for (int i = 0; i < mNLoopersCompton; ++i) { - std::vector electron = mONNX_compton->generate_sample(); - // Apply the inverse transformation using the scaler - std::vector transformed_electron = mScaler_compton->inverse_transform(electron); - mGenElectrons.push_back(transformed_electron); - } - } - return true; -} - -Bool_t GenTPCLoopers::generateEvent(double time_limit) -{ - LOG(info) << "Time constraint for loopers: " << time_limit << " ns"; - // Generate pairs - for (int i = 0; i < mNLoopersPairs; ++i) { - std::vector pair = mONNX_pair->generate_sample(); - // Apply the inverse transformation using the scaler - std::vector transformed_pair = mScaler_pair->inverse_transform(pair); - transformed_pair[9] = gRandom->Uniform(0., time_limit); // Regenerate time, scaling is not needed because time_limit is already in nanoseconds - mGenPairs.push_back(transformed_pair); - } - // Generate compton electrons - for (int i = 0; i < mNLoopersCompton; ++i) { - std::vector electron = mONNX_compton->generate_sample(); - // Apply the inverse transformation using the scaler - std::vector transformed_electron = mScaler_compton->inverse_transform(electron); - transformed_electron[6] = gRandom->Uniform(0., time_limit); // Regenerate time, scaling is not needed because time_limit is already in nanoseconds - mGenElectrons.push_back(transformed_electron); - } - LOG(info) << "Generated Particles with time limit"; - return true; -} - -std::vector GenTPCLoopers::importParticles() -{ - std::vector particles; - const double mass_e = TDatabasePDG::Instance()->GetParticle(11)->Mass(); - const double mass_p = TDatabasePDG::Instance()->GetParticle(-11)->Mass(); - // Get looper pairs from the event - for (auto& pair : mGenPairs) { - double px_e, py_e, pz_e, px_p, py_p, pz_p; - double vx, vy, vz, time; - double e_etot, p_etot; - px_e = pair[0]; - py_e = pair[1]; - pz_e = pair[2]; - px_p = pair[3]; - py_p = pair[4]; - pz_p = pair[5]; - vx = pair[6]; - vy = pair[7]; - vz = pair[8]; - time = pair[9]; - e_etot = TMath::Sqrt(px_e * px_e + py_e * py_e + pz_e * pz_e + mass_e * mass_e); - p_etot = TMath::Sqrt(px_p * px_p + py_p * py_p + pz_p * pz_p + mass_p * mass_p); - // Push the electron - TParticle electron(11, 1, -1, -1, -1, -1, px_e, py_e, pz_e, e_etot, vx, vy, vz, time / 1e9); - electron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(electron.GetStatusCode(), 0).fullEncoding); - electron.SetBit(ParticleStatus::kToBeDone, // - o2::mcgenstatus::getHepMCStatusCode(electron.GetStatusCode()) == 1); - particles.push_back(electron); - // Push the positron - TParticle positron(-11, 1, -1, -1, -1, -1, px_p, py_p, pz_p, p_etot, vx, vy, vz, time / 1e9); - positron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(positron.GetStatusCode(), 0).fullEncoding); - positron.SetBit(ParticleStatus::kToBeDone, // - o2::mcgenstatus::getHepMCStatusCode(positron.GetStatusCode()) == 1); - particles.push_back(positron); - } - // Get compton electrons from the event - for (auto& compton : mGenElectrons) { - double px, py, pz; - double vx, vy, vz, time; - double etot; - px = compton[0]; - py = compton[1]; - pz = compton[2]; - vx = compton[3]; - vy = compton[4]; - vz = compton[5]; - time = compton[6]; - etot = TMath::Sqrt(px * px + py * py + pz * pz + mass_e * mass_e); - // Push the electron - TParticle electron(11, 1, -1, -1, -1, -1, px, py, pz, etot, vx, vy, vz, time / 1e9); - electron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(electron.GetStatusCode(), 0).fullEncoding); - electron.SetBit(ParticleStatus::kToBeDone, // - o2::mcgenstatus::getHepMCStatusCode(electron.GetStatusCode()) == 1); - particles.push_back(electron); - } - - return particles; -} - -unsigned int GenTPCLoopers::PoissonPairs() -{ - unsigned int poissonValue; - do { - // Generate a Poisson-distributed random number with mean mPoisson[0] - poissonValue = mRandGen.Poisson(mPoisson[0]); - } while (poissonValue < mPoisson[1] || poissonValue > mPoisson[2]); // Regenerate if out of range - - return poissonValue; -} - -unsigned int GenTPCLoopers::GaussianElectrons() -{ - unsigned int gaussValue; - do { - // Generate a Normal-distributed random number with mean mGass[0] and stddev mGauss[1] - gaussValue = mRandGen.Gaus(mGauss[0], mGauss[1]); - } while (gaussValue < mGauss[2] || gaussValue > mGauss[3]); // Regenerate if out of range - - return gaussValue; -} - -void GenTPCLoopers::SetNLoopers(unsigned int nsig_pair, unsigned int nsig_compton) -{ - if (mFlatGas) { - mNLoopersPairs = nsig_pair; - mNLoopersCompton = nsig_compton; - } else { - if (mPoissonSet) { - LOG(info) << "Poissonian parameters correctly loaded."; - } else { - mNLoopersPairs = nsig_pair; - } - if (mGaussSet) { - LOG(info) << "Gaussian parameters correctly loaded."; - } else { - mNLoopersCompton = nsig_compton; - } - } -} - -void GenTPCLoopers::SetMultiplier(const std::array& mult) -{ - // Multipliers will work only if the poissonian and gaussian parameters are set - // otherwise they will be ignored - if (mult[0] < 0 || mult[1] < 0) { - LOG(fatal) << "Error: Multiplier values must be non-negative!"; - exit(1); - } else { - LOG(info) << "Multiplier values set to: Pair = " << mult[0] << ", Compton = " << mult[1]; - mMultiplier[0] = mult[0]; - mMultiplier[1] = mult[1]; - } -} - -void GenTPCLoopers::setFlatGas(Bool_t flat, Int_t number, Int_t nloopers_orbit) -{ - mFlatGas = flat; - if (mFlatGas) { - if (nloopers_orbit > 0) { - mFlatGasOrbit = true; - mFlatGasNumber = nloopers_orbit; - LOG(info) << "Flat gas loopers will be generated using orbit reference."; - } else { - mFlatGasOrbit = false; - if (number < 0) { - LOG(warn) << "Warning: Number of loopers per event must be non-negative! Switching option off."; - mFlatGas = false; - mFlatGasNumber = -1; - } else { - mFlatGasNumber = number; - } - } - if (mFlatGas) { - mContextFile = std::filesystem::exists("collisioncontext.root") ? TFile::Open("collisioncontext.root") : nullptr; - mCollisionContext = mContextFile ? (o2::steer::DigitizationContext*)mContextFile->Get("DigitizationContext") : nullptr; - mInteractionTimeRecords = mCollisionContext ? mCollisionContext->getEventRecords() : std::vector{}; - if (mInteractionTimeRecords.empty()) { - LOG(error) << "Error: No interaction time records found in the collision context!"; - exit(1); - } else { - LOG(info) << "Interaction Time records has " << mInteractionTimeRecords.size() << " entries."; - mCollisionContext->printCollisionSummary(); - } - for (int c = 0; c < mInteractionTimeRecords.size() - 1; c++) { - mIntTimeRecMean += mInteractionTimeRecords[c + 1].bc2ns() - mInteractionTimeRecords[c].bc2ns(); - } - mIntTimeRecMean /= (mInteractionTimeRecords.size() - 1); // Average interaction time record used as reference - const auto& hbfUtils = o2::raw::HBFUtils::Instance(); - // Get the start time of the second orbit after the last interaction record - const auto& lastIR = mInteractionTimeRecords.back(); - o2::InteractionRecord finalOrbitIR(0, lastIR.orbit + 2); // Final orbit, BC = 0 - mTimeEnd = finalOrbitIR.bc2ns(); - LOG(debug) << "Final orbit start time: " << mTimeEnd << " ns while last interaction record time is " << mInteractionTimeRecords.back().bc2ns() << " ns"; - } - } else { - mFlatGasNumber = -1; - } - LOG(info) << "Flat gas loopers: " << (mFlatGas ? "ON" : "OFF") << ", Reference loopers number per " << (mFlatGasOrbit ? "orbit " : "event ") << mFlatGasNumber; -} - -void GenTPCLoopers::setFractionPairs(float fractionPairs) -{ - if (fractionPairs < 0 || fractionPairs > 1) { - LOG(fatal) << "Error: Loops fraction for pairs must be in the range [0, 1]."; - exit(1); - } - mLoopsFractionPairs = fractionPairs; - LOG(info) << "Pairs fraction set to: " << mLoopsFractionPairs; -} - -void GenTPCLoopers::SetRate(const std::string& rateFile, bool isPbPb = true, int intRate) -{ - // Checking if the rate file exists and is not empty - TFile rate_file(rateFile.c_str(), "READ"); - if (!rate_file.IsOpen() || rate_file.IsZombie()) { - LOG(fatal) << "Error: Rate file is empty or does not exist!"; - exit(1); - } - const char* fitName = isPbPb ? "fitPbPb" : "fitpp"; - auto fit = (TF1*)rate_file.Get(fitName); - if (!fit) { - LOG(fatal) << "Error: Could not find fit function '" << fitName << "' in rate file!"; - exit(1); - } - mInteractionRate = intRate; - if (mInteractionRate < 0) { - mContextFile = std::filesystem::exists("collisioncontext.root") ? TFile::Open("collisioncontext.root") : nullptr; - if (!mContextFile || mContextFile->IsZombie()) { - LOG(fatal) << "Error: Interaction rate not provided and collision context file not found!"; - exit(1); - } - mCollisionContext = (o2::steer::DigitizationContext*)mContextFile->Get("DigitizationContext"); - mInteractionRate = std::floor(mCollisionContext->getDigitizerInteractionRate()); - LOG(info) << "Interaction rate retrieved from collision context: " << mInteractionRate << " Hz"; - if (mInteractionRate < 0) { - LOG(fatal) << "Error: Invalid interaction rate retrieved from collision context!"; - exit(1); - } - } - auto ref = static_cast(std::floor(fit->Eval(mInteractionRate / 1000.))); // fit expects rate in kHz - rate_file.Close(); - if (ref <= 0) { - LOG(fatal) << "Computed flat gas number reference per orbit is <=0"; - exit(1); - } else { - LOG(info) << "Set flat gas number to " << ref << " loopers per orbit using " << fitName << " from " << mInteractionRate << " Hz interaction rate."; - auto flat = true; - setFlatGas(flat, -1, ref); - } -} - -void GenTPCLoopers::SetAdjust(float adjust) -{ - if (mFlatGas && mFlatGasOrbit && adjust >= -1.f && adjust != 0.f) { - LOG(info) << "Adjusting flat gas number per orbit by " << adjust * 100.f << "%"; - mFlatGasNumber = static_cast(std::round(mFlatGasNumber * (1.f + adjust))); - LOG(info) << "New flat gas number per orbit: " << mFlatGasNumber; - } -} - -} // namespace eventgen -} // namespace o2 \ No newline at end of file diff --git a/Generators/src/TPCLoopersParam.cxx b/Generators/src/TPCLoopersParam.cxx deleted file mode 100644 index 0202a8ced0535..0000000000000 --- a/Generators/src/TPCLoopersParam.cxx +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2024-2025 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \author M+Giacalone - September 2025 - -#include "Generators/TPCLoopersParam.h" -O2ParamImpl(o2::eventgen::GenTPCLoopersParam);