Skip to content

Commit 9757ce2

Browse files
committed
Added external fraction parametrisation and other improvements
1 parent e83c6dd commit 9757ce2

2 files changed

Lines changed: 123 additions & 31 deletions

File tree

MC/bin/o2dpg_sim_workflow.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@
157157
parser.add_argument('--fwdmatching-cut-4-param', action='store_true', help='apply selection cuts on position and angular parameters')
158158
# TPC loopers with external WGAN generator
159159
parser.add_argument('--disable-loopers', action='store_true', help='disables fast simulated TPC loopers')
160+
parser.add_argument('-confKeyLoopers',help='Config key parameters influencing the number of loopers in the simulation', default='')
160161

161162
# Matching training for machine learning
162163
parser.add_argument('--fwdmatching-save-trainingdata', action='store_true', help='enables saving parameters at plane for matching training with machine learning')
@@ -863,17 +864,17 @@ def getDPL_global_options(bigshm=False, ccdbbackend=True):
863864

864865
# Include fast simulated TPC loopers
865866
if isActive('TPC') and not args.disable_loopers:
866-
LOOPStask = createTask(name='sgngenloops_' + str(tf), needs=signalneeds, tf=tf, cwd='tf' + str(tf), lab=["GEN"], cpu=1, mem=1000)
867-
LOOPScfgbase = "GeneratorFromO2Kine.randomize=true"
868-
LOOPSinicfg = " --configFile $O2DPG_MC_CONFIG_ROOT/MC/config/common/ini/GeneratorLoopersInjector.ini"
869-
LOOPSCONFKEY = constructConfigKeyArg(create_geant_config(args, LOOPScfgbase))
870-
LOOPStask['cmd'] = '${O2_ROOT}/bin/o2-sim --noGeant --field ccdb -j 1 --vertexMode kNoVertex' \
871-
+ ' --run ' + str(args.run) + ' ' + str(LOOPSCONFKEY) + ' -g external' \
872-
+ ' -n ' + str(NSIGEVENTS) + ' --seed ' + str(TFSEED) + ' -o loops ' \
873-
+ embeddinto + ' --fromCollContext collisioncontext.root:' + signalprefix + LOOPSinicfg
874-
kineFileName = 'loops_Kine.root' # Kine file now has injected loopers
875-
signalneeds = signalneeds + [LOOPStask['name']]
876-
workflow['stages'].append(LOOPStask)
867+
LOOPERStask = createTask(name='sgngenloopers_' + str(tf), needs=signalneeds, tf=tf, cwd='tf' + str(tf), lab=["GEN"], cpu=1, mem=1000)
868+
LOOPERScfgbase = "GeneratorFromO2Kine.randomize=false" + (";GeneratorExternal.config=" + str(args.confKeyLoopers)) if args.confKeyLoopers != '' else ""
869+
LOOPERSinicfg = " --configFile $O2DPG_MC_CONFIG_ROOT/MC/config/common/ini/GeneratorLoopersInjector.ini"
870+
LOOPERSCONFKEY = constructConfigKeyArg(create_geant_config(args, LOOPERScfgbase))
871+
LOOPERStask['cmd'] = '${O2_ROOT}/bin/o2-sim --noGeant --field ccdb -j 1 --vertexMode kNoVertex' \
872+
+ ' --run ' + str(args.run) + ' ' + str(LOOPERSCONFKEY) + ' -g external' \
873+
+ ' -n ' + str(NSIGEVENTS) + ' --seed ' + str(TFSEED) + ' -o loopers ' \
874+
+ embeddinto + ' --fromCollContext collisioncontext.root:' + signalprefix + LOOPERSinicfg
875+
kineFileName = 'loopers_Kine.root' # Kine file now has injected loopers
876+
signalneeds = signalneeds + [LOOPERStask['name']]
877+
workflow['stages'].append(LOOPERStask)
877878

878879
sgnmem = 6000 if COLTYPE == 'PbPb' else 4000
879880
SGNtask=createTask(name='sgnsim_'+str(tf), needs=signalneeds, tf=tf, cwd='tf'+str(tf), lab=["GEANT"],

MC/config/common/external/generator/TPCLoopers.C

Lines changed: 111 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -419,33 +419,92 @@ class GenLoopersInjector : public Generator
419419
return true;
420420
}
421421

422+
std::vector<TParticle> genProcessor(Generator* gen)
423+
{
424+
auto unit_transformer = [](auto &p, auto pos_unit, auto time_unit, auto en_unit, auto mom_unit)
425+
{
426+
p.SetMomentum(p.Px() * mom_unit, p.Py() * mom_unit, p.Pz() * mom_unit, p.Energy() * en_unit);
427+
p.SetProductionVertex(p.Vx() * pos_unit, p.Vy() * pos_unit, p.Vz() * pos_unit, p.T() * time_unit);
428+
};
429+
430+
auto index_transformer = [](auto &p, int offset)
431+
{
432+
for (int i = 0; i < 2; ++i)
433+
{
434+
if (p.GetMother(i) != -1)
435+
{
436+
const auto newindex = p.GetMother(i) + offset;
437+
p.SetMother(i, newindex);
438+
}
439+
}
440+
if (p.GetNDaughters() > 0)
441+
{
442+
for (int i = 0; i < 2; ++i)
443+
{
444+
const auto newindex = p.GetDaughter(i) + offset;
445+
p.SetDaughter(i, newindex);
446+
}
447+
}
448+
};
449+
auto parts = gen->getParticles();
450+
auto time_unit = gen->getTimeUnit();
451+
auto pos_unit = gen->getPositionUnit();
452+
auto mom_unit = gen->getMomentumUnit();
453+
auto energy_unit = gen->getEnergyUnit();
454+
for (auto &p : parts)
455+
{
456+
// apply the mother-daugher index transformation
457+
index_transformer(p, mParticles.size());
458+
// apply unit transformation of sub-generator
459+
unit_transformer(p, pos_unit, time_unit, energy_unit, mom_unit);
460+
}
461+
return parts;
462+
}
463+
422464
Bool_t importParticles() override
423465
{
424466
mParticles.clear(); // Clear the particles stack before importing new ones
425467
// Combination of import particles from GeneratorFromO2Kine and GenTPCLoopers
426468
mKineGen->clearParticles(); // Clear particles from O2 Kinematics generator
427469
mGenTPCLoopers->clearParticles(); // Clear particles from GenTPCLoopers
428470
auto stat1 = mKineGen->importParticles();
429-
// Check size of mParticles stack and set loopers accordingly if mAdaptiveLoopers is true
430-
if (mAdaptiveLoopers)
471+
if (stat1)
431472
{
432-
int nParticles = mParticles.size();
433-
if (nParticles > 0)
473+
// Include particles from O2 Kinematics generator
474+
auto kineparts = genProcessor(mKineGen.get());
475+
LOG(info) << "Size of kineparts: " << kineparts.size();
476+
mParticles.insert(mParticles.end(), kineparts.begin(), kineparts.end());
477+
LOG(info) << "Size mParticles at kine stage " << mParticles.size();
478+
// Check size of mParticles stack and set loopers accordingly if mAdaptiveLoopers is true
479+
if (mAdaptiveLoopers)
434480
{
435-
// Calculate the number of loopers to inject adaptively
436-
short int nLoopers = static_cast<short int>(std::round((nParticles * mLoopsFraction) / (1 - mLoopsFractionPairs)));
437-
short int nLoopersPairs = static_cast<short int>(std::round(nLoopers * mLoopsFractionPairs));
438-
short int nLoopersCompton = nLoopers - nLoopersPairs;
439-
mGenTPCLoopers->SetNLoopers(nLoopersPairs, nLoopersCompton);
440-
mGenTPCLoopers->generateEvent();
481+
int nParticles = mParticles.size();
482+
if (nParticles > 0)
483+
{
484+
// Calculate the number of loopers to inject adaptively
485+
short int nLoopers = static_cast<short int>(std::round((nParticles * mLoopsFraction) / (1 - mLoopsFractionPairs)));
486+
short int nLoopersPairs = static_cast<short int>(std::round(nLoopers * mLoopsFractionPairs));
487+
short int nLoopersCompton = nLoopers - nLoopersPairs;
488+
mGenTPCLoopers->SetNLoopers(nLoopersPairs, nLoopersCompton);
489+
LOG(info) << "Adaptive loopers: " << nLoopers << " (pairs: " << nLoopersPairs << ", compton: " << nLoopersCompton << ")";
490+
} else {
491+
LOG(info) << "No particles found in O2 Kinematics, no loopers will be generated";
492+
return false;
493+
}
441494
}
442-
}
443-
auto stat2 = mGenTPCLoopers->importParticles();
444-
if (stat1 && stat2)
445-
{
446-
// Merge particles from both generators
447-
mParticles.insert(mParticles.end(), mKineGen->getParticles().begin(), mKineGen->getParticles().end());
448-
mParticles.insert(mParticles.end(), mGenTPCLoopers->getParticles().begin(), mGenTPCLoopers->getParticles().end());
495+
// Generate loopers using GenTPCLoopers
496+
// this is valid also when number of loopers is fixed
497+
mGenTPCLoopers->generateEvent();
498+
auto stat2 = mGenTPCLoopers->importParticles();
499+
if (!stat2) {
500+
LOG(error) << "Failed to import particles from GenTPCLoopers";
501+
return false;
502+
}
503+
// Include particles from GenTPCLoopers
504+
auto loopers = genProcessor(mGenTPCLoopers.get());
505+
LOG(info) << "Size of loopers: " << loopers.size();
506+
mParticles.insert(mParticles.end(), loopers.begin(), loopers.end());
507+
LOG(info) << "Size mParticles at loopers stage " << mParticles.size();
449508
} else {
450509
LOG(error) << "Failed to import particles from O2 Kinematics or TPCLoopers";
451510
return false;
@@ -457,7 +516,7 @@ class GenLoopersInjector : public Generator
457516
std::unique_ptr<GeneratorFromO2Kine> mKineGen = nullptr; // Instance of GeneratorFromO2Kine to read particles from O2 kinematics file
458517
std::unique_ptr<GenTPCLoopers> mGenTPCLoopers = nullptr; // Instance of GenTPCLoopers to generate loopers
459518
Bool_t mAdaptiveLoopers = true; // Flag to indicate if adaptive loopers are used
460-
float mLoopsFraction = 0.1; // Fraction of loopers to be injected adaptively
519+
float mLoopsFraction = 0.05; // Fraction of loopers to be injected adaptively
461520
float mLoopsFractionPairs = 0.08; // Fraction of loopers from Pairs
462521
};
463522

@@ -541,7 +600,7 @@ FairGenerator *
541600
// Loopers are considered adaptive by default, meaning that the number of loopers is determined by the number of particles in the kinematics file per event
542601
FairGenerator *
543602
GeneratorLoopersInjector(std::string kineFileName = "genevents_Kine.root", std::string model_pairs = "tpcloopmodel.onnx", std::string model_compton = "tpcloopmodelcompton.onnx",
544-
std::string scaler_pair = "scaler_pair.json", std::string scaler_compton = "scaler_compton.json", float loopers_fraction = 0.1, float fraction_pairs = 0.08)
603+
std::string scaler_pair = "scaler_pair.json", std::string scaler_compton = "scaler_compton.json", float loopers_fraction = 0.05, float fraction_pairs = 0.08)
545604
{
546605
// Expand all environment paths
547606
model_pairs = gSystem->ExpandPathName(model_pairs.c_str());
@@ -602,6 +661,38 @@ GeneratorLoopersInjector(std::string kineFileName = "genevents_Kine.root", std::
602661
model_pairs = isAlien[0] || isCCDB[0] ? local_names[0] : model_pairs;
603662
model_compton = isAlien[1] || isCCDB[1] ? local_names[1] : model_compton;
604663
auto generator = new o2::eventgen::GenLoopersInjector(kineFileName, model_pairs, model_compton, scaler_pair, scaler_compton);
605-
generator->setLoopsFractions(loopers_fraction, fraction_pairs);
664+
auto& extParams = o2::eventgen::GeneratorExternalParam::Instance();
665+
auto config = extParams.config;
666+
// Parse external configuration for loopers fractions if provided
667+
if (!config.empty()) {
668+
LOG(info) << "Using external configuration for loopers fractions: " << extParams.config;
669+
// Try to parse as "<loopers_fraction>-<fraction_pairs>" or single value
670+
size_t dash = config.find('-');
671+
try {
672+
if (dash == std::string::npos) {
673+
float frac = std::stof(config);
674+
if (frac >= 0 && frac < 1) {
675+
generator->setLoopsFractions(frac, fraction_pairs);
676+
} else {
677+
throw std::invalid_argument("Out of range");
678+
}
679+
} else {
680+
float frac1 = std::stof(config.substr(0, dash));
681+
float frac2 = std::stof(config.substr(dash + 1));
682+
if (frac1 >= 0 && frac1 < 1 && frac2 >= 0 && frac2 <= 1) {
683+
generator->setLoopsFractions(frac1, frac2);
684+
} else {
685+
throw std::invalid_argument("Out of range");
686+
}
687+
}
688+
} catch (...) {
689+
LOG(warn) << "Invalid external configuration for loopers fractions: " << extParams.config;
690+
LOG(warn) << "Expected format: <loopers_fraction>-<fraction_pairs> or a single value between [0,1).";
691+
LOG(warn) << "Using default values instead.";
692+
generator->setLoopsFractions(loopers_fraction, fraction_pairs);
693+
}
694+
} else {
695+
generator->setLoopsFractions(loopers_fraction, fraction_pairs);
696+
}
606697
return generator;
607698
}

0 commit comments

Comments
 (0)