Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Generators/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ o2_add_library(Generators
src/GeneratorTParticleParam.cxx
src/GeneratorService.cxx
src/FlowMapper.cxx
src/TPCLoopers.cxx
src/TPCLoopersParam.cxx
$<$<BOOL:${pythia_FOUND}>:src/GeneratorPythia8.cxx>
$<$<BOOL:${pythia_FOUND}>:src/DecayerPythia8.cxx>
$<$<BOOL:${pythia_FOUND}>:src/GeneratorPythia8Param.cxx>
Expand All @@ -53,6 +55,7 @@ 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)
Expand All @@ -63,6 +66,8 @@ 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
Expand All @@ -88,6 +93,10 @@ 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
Expand Down Expand Up @@ -158,4 +167,5 @@ 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)
13 changes: 13 additions & 0 deletions Generators/include/Generators/Generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
#include "FairGenerator.h"
#include "TParticle.h"
#include "Generators/Trigger.h"
#ifdef GENERATORS_WITH_TPCLOOPERS
#include "Generators/TPCLoopers.h"
#include "Generators/TPCLoopersParam.h"
#endif
#include <functional>
#include <vector>
#include <unordered_map>
Expand Down Expand Up @@ -73,6 +77,7 @@ 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();

Expand Down Expand Up @@ -154,6 +159,8 @@ 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<int, std::string> mSubGeneratorsIdToDesc;
// the current ID of the sub-generator used in the current event (if applicable)
Expand All @@ -162,6 +169,12 @@ 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<o2::eventgen::GenTPCLoopers> mTPCLoopersGen = nullptr;
bool initTPCLoopersGen();
#endif

ClassDefOverride(Generator, 2);

}; /** class Generator **/
Expand Down
148 changes: 148 additions & 0 deletions Generators/include/Generators/TPCLoopers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// 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 <onnxruntime_cxx_api.h>
#endif
#include <vector>
#include <rapidjson/document.h>
#include "TRandom3.h"
#include <SimulationDataFormat/DigitizationContext.h>
#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<double> normal_min;
std::vector<double> normal_max;
std::vector<double> outlier_center;
std::vector<double> outlier_scale;

void load(const std::string& filename);

std::vector<double> inverse_transform(const std::vector<double>& input);

private:
std::vector<double> 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<double> 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a small doxygen style class description would be good

{
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<TParticle> importParticles();

unsigned int PoissonPairs();

unsigned int GaussianElectrons();

void SetNLoopers(unsigned int nsig_pair, unsigned int nsig_compton);

void SetMultiplier(const std::array<float, 2>& 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<ONNXGenerator> mONNX_pair = nullptr;
std::unique_ptr<ONNXGenerator> mONNX_compton = nullptr;
std::unique_ptr<Scaler> mScaler_pair = nullptr;
std::unique_ptr<Scaler> 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<std::vector<double>> mGenPairs;
std::vector<std::vector<double>> mGenElectrons;
unsigned int mNLoopersPairs = -1;
unsigned int mNLoopersCompton = -1;
std::array<float, 2> 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<o2::InteractionTimeRecord> 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_
54 changes: 54 additions & 0 deletions Generators/include/Generators/TPCLoopersParam.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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<GenTPCLoopersParam> {
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_
79 changes: 79 additions & 0 deletions Generators/share/TPCLoopers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# 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*
28 changes: 28 additions & 0 deletions Generators/share/TPCLoopers/ScalerComptonParams.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"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
]
}
}
Loading