From 9789874a2e0ae7387ddb6f368138668ffefa5d84 Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Fri, 17 Jan 2025 16:00:12 +0100 Subject: [PATCH 1/3] Trigger implementation in hybrid generator --- Generators/include/Generators/Generator.h | 2 +- .../include/Generators/GeneratorHybrid.h | 5 + Generators/src/GeneratorFactory.cxx | 77 ++++++------- Generators/src/GeneratorHybrid.cxx | 103 +++++++++++++++++- 4 files changed, 146 insertions(+), 41 deletions(-) diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index 6da1a0e837cc8..7181bcbc6682d 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -74,6 +74,7 @@ class Generator : public FairGenerator 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) virtual void updateHeader(o2::dataformats::MCEventHeader* eventHeader) {}; + Bool_t triggerEvent(); /** setters **/ void setMomentumUnit(double val) { mMomentumUnit = val; }; @@ -106,7 +107,6 @@ class Generator : public FairGenerator /** internal methods **/ Bool_t addTracks(FairPrimaryGenerator* primGen); Bool_t boostEvent(); - Bool_t triggerEvent(); /** to handle cocktail constituents **/ void addSubGenerator(int subGeneratorId, std::string const& subGeneratorDescription); diff --git a/Generators/include/Generators/GeneratorHybrid.h b/Generators/include/Generators/GeneratorHybrid.h index b0993c4fd82e2..1f651b4464753 100644 --- a/Generators/include/Generators/GeneratorHybrid.h +++ b/Generators/include/Generators/GeneratorHybrid.h @@ -103,6 +103,11 @@ class GeneratorHybrid : public Generator bool mCocktailMode = false; std::vector> mGroups; + // Trigger configuration + std::vector mTriggerModes; // trigger mode for each generator + std::vector> mTriggerMacros; // trigger macros for each generator (multiple triggers for each generator possible) + std::vector> mTriggerFuncs; // trigger functions for each generator (multiple triggers for each generator possible) + // Create a task arena with a specified number of threads std::thread mTBBTaskPoolRunner; tbb::concurrent_bounded_queue mInputTaskQueue; diff --git a/Generators/src/GeneratorFactory.cxx b/Generators/src/GeneratorFactory.cxx index dc2f4f2159b4d..1bd1f58254ec2 100644 --- a/Generators/src/GeneratorFactory.cxx +++ b/Generators/src/GeneratorFactory.cxx @@ -293,48 +293,51 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair } /** triggers **/ + // to be set via GeneratorFactory only if generator is not hybrid + // external settings via JSON are supported in the latter Trigger trigger = nullptr; DeepTrigger deeptrigger = nullptr; - - auto trgconfig = conf.getTrigger(); - if (trgconfig.empty()) { - return; - } else if (trgconfig.compare("particle") == 0) { - trigger = TriggerParticle(TriggerParticleParam::Instance()); - } else if (trgconfig.compare("external") == 0) { - // external trigger via configuration macro - auto& params = TriggerExternalParam::Instance(); - LOG(info) << "Setting up external trigger with following parameters"; - LOG(info) << params; - auto external_trigger_filename = params.fileName; - auto external_trigger_func = params.funcName; - trigger = o2::conf::GetFromMacro(external_trigger_filename, external_trigger_func, "o2::eventgen::Trigger", "trigger"); - if (!trigger) { - LOG(info) << "Trying to retrieve a \'o2::eventgen::DeepTrigger\' type" << std::endl; - deeptrigger = o2::conf::GetFromMacro(external_trigger_filename, external_trigger_func, "o2::eventgen::DeepTrigger", "deeptrigger"); - } - if (!trigger && !deeptrigger) { - LOG(fatal) << "Failed to retrieve \'external trigger\': problem with configuration "; - } - } else { - LOG(fatal) << "Invalid trigger"; - } - - /** add trigger to generators **/ - auto generators = primGen->GetListOfGenerators(); - for (int igen = 0; igen < generators->GetEntries(); ++igen) { - auto generator = dynamic_cast(generators->At(igen)); - if (!generator) { - LOG(fatal) << "request to add a trigger to an unsupported generator"; + if(!genconfig.compare("hybrid") == 0){ + auto trgconfig = conf.getTrigger(); + if (trgconfig.empty()) { return; + } else if (trgconfig.compare("particle") == 0) { + trigger = TriggerParticle(TriggerParticleParam::Instance()); + } else if (trgconfig.compare("external") == 0) { + // external trigger via configuration macro + auto& params = TriggerExternalParam::Instance(); + LOG(info) << "Setting up external trigger with following parameters"; + LOG(info) << params; + auto external_trigger_filename = params.fileName; + auto external_trigger_func = params.funcName; + trigger = o2::conf::GetFromMacro(external_trigger_filename, external_trigger_func, "o2::eventgen::Trigger", "trigger"); + if (!trigger) { + LOG(info) << "Trying to retrieve a \'o2::eventgen::DeepTrigger\' type" << std::endl; + deeptrigger = o2::conf::GetFromMacro(external_trigger_filename, external_trigger_func, "o2::eventgen::DeepTrigger", "deeptrigger"); + } + if (!trigger && !deeptrigger) { + LOG(fatal) << "Failed to retrieve \'external trigger\': problem with configuration "; + } + } else { + LOG(fatal) << "Invalid trigger"; } - generator->setTriggerMode(o2::eventgen::Generator::kTriggerOR); - if (trigger) { - generator->addTrigger(trigger); - } - if (deeptrigger) { - generator->addDeepTrigger(deeptrigger); + + /** add trigger to generators **/ + auto generators = primGen->GetListOfGenerators(); + for (int igen = 0; igen < generators->GetEntries(); ++igen) { + auto generator = dynamic_cast(generators->At(igen)); + if (!generator) { + LOG(fatal) << "request to add a trigger to an unsupported generator"; + return; + } + generator->setTriggerMode(o2::eventgen::Generator::kTriggerOR); + if (trigger) { + generator->addTrigger(trigger); + } + if (deeptrigger) { + generator->addDeepTrigger(deeptrigger); + } } } } diff --git a/Generators/src/GeneratorHybrid.cxx b/Generators/src/GeneratorHybrid.cxx index af6f2bea03052..43d8c861e07e6 100644 --- a/Generators/src/GeneratorHybrid.cxx +++ b/Generators/src/GeneratorHybrid.cxx @@ -183,6 +183,37 @@ Bool_t GeneratorHybrid::Init() } gens[count]->Init(); // TODO: move this to multi-threaded addSubGenerator(count, gen); + if (mTriggerModes[count] != o2::eventgen::Generator::kTriggerOFF) { + gens[count]->setTriggerMode(mTriggerModes[count]); + LOG(info) << "Setting Trigger mode of generator " << gen << " to: " << mTriggerModes[count]; + o2::eventgen::Trigger trigger = nullptr; + o2::eventgen::DeepTrigger deeptrigger = nullptr; + for (int trg = 0; trg < mTriggerMacros[count].size(); trg++) { + if (mTriggerMacros[count][trg].empty() || mTriggerFuncs[count][trg].empty()) { + continue; + } + LOG(info) << "Setting trigger " << trg << " of generator " << gen << " with following parameters"; + LOG(info) << "Macro filename: " << mTriggerMacros[count][trg]; + LOG(info) << "Function name: " << mTriggerFuncs[count][trg]; + trigger = o2::conf::GetFromMacro(mTriggerMacros[count][trg], mTriggerFuncs[count][trg], "o2::eventgen::Trigger", "trigger"); + if (!trigger) { + LOG(info) << "Trying to retrieve a \'o2::eventgen::DeepTrigger\' type"; + deeptrigger = o2::conf::GetFromMacro(mTriggerMacros[count][trg], mTriggerFuncs[count][trg], "o2::eventgen::DeepTrigger", "deeptrigger"); + } + if (!trigger && !deeptrigger) { + LOG(warn) << "Failed to retrieve \'external trigger\': problem with configuration"; + LOG(warn) << "Trigger " << trg << " of generator " << gen << " will not be included"; + continue; + } else { + LOG(info) << "Trigger " << trg << " of generator " << gen << " successfully set"; + } + if (trigger) { + gens[count]->addTrigger(trigger); + } else { + gens[count]->addDeepTrigger(deeptrigger); + } + } + } count++; } if (mRandomize) { @@ -240,9 +271,13 @@ Bool_t GeneratorHybrid::Init() // mGenIsInitialized[task] = true; // } } - generator->clearParticles(); - generator->generateEvent(); - generator->importParticles(); + bool isTriggered = false; + while(!isTriggered) { + generator->clearParticles(); + generator->generateEvent(); + generator->importParticles(); + isTriggered = generator->triggerEvent(); + } LOG(debug) << "eventgen finished for task " << task; if (!mStopFlag) { if (mGenerationMode == GenMode::kParallel) { @@ -450,6 +485,68 @@ Bool_t GeneratorHybrid::confSetter(const auto& gen) mConfigs.push_back(""); } } + if (gen.HasMember("triggers")) { + const auto& trigger = gen["triggers"]; + auto trigger_specs = [this, &trigger]() { + mTriggerMacros.push_back({}); + mTriggerFuncs.push_back({}); + if(trigger.HasMember("specs")) { + for(auto& spec : trigger["specs"].GetArray()) { + if(spec.HasMember("macro")){ + const auto& macro = spec["macro"].GetString(); + if (!strcmp(macro, "") == 0) { + mTriggerMacros.back().push_back(macro); + } else { + mTriggerMacros.back().push_back(""); + } + } else { + mTriggerMacros.back().push_back(""); + } + if (spec.HasMember("function")) { + const auto& function = spec["function"].GetString(); + if (!strcmp(function, "") == 0) { + mTriggerFuncs.back().push_back(function); + } else { + mTriggerFuncs.back().push_back(""); + } + } else { + mTriggerFuncs.back().push_back(""); + } + } + } else { + mTriggerMacros.back().push_back(""); + mTriggerFuncs.back().push_back(""); + } + }; + if (trigger.HasMember("mode")) { + const auto& trmode = trigger["mode"].GetString(); + if (strcmp(trmode, "or") == 0) { + mTriggerModes.push_back(o2::eventgen::Generator::kTriggerOR); + trigger_specs(); + } else if (strcmp(trmode, "and") == 0) { + mTriggerModes.push_back(o2::eventgen::Generator::kTriggerAND); + trigger_specs(); + } else if (strcmp(trmode, "off") == 0) { + mTriggerModes.push_back(o2::eventgen::Generator::kTriggerOFF); + mTriggerMacros.push_back({""}); + mTriggerFuncs.push_back({""}); + } else { + LOG(warn) << "Wrong trigger mode provided for generator " << name << ", keeping trigger OFF"; + mTriggerModes.push_back(o2::eventgen::Generator::kTriggerOFF); + mTriggerMacros.push_back({""}); + mTriggerFuncs.push_back({""}); + } + } else { + LOG(warn) << "No trigger mode provided for generator " << name << ", turning trigger OFF"; + mTriggerModes.push_back(o2::eventgen::Generator::kTriggerOFF); + mTriggerMacros.push_back({""}); + mTriggerFuncs.push_back({""}); + } + } else { + mTriggerModes.push_back(o2::eventgen::Generator::kTriggerOFF); + mTriggerMacros.push_back({""}); + mTriggerFuncs.push_back({""}); + } return true; } From ecf25ab2062b5c46c3e6569c348a2f3a06187edb Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Fri, 17 Jan 2025 15:01:32 +0000 Subject: [PATCH 2/3] Please consider the following formatting changes --- Generators/include/Generators/GeneratorHybrid.h | 4 ++-- Generators/src/GeneratorFactory.cxx | 2 +- Generators/src/GeneratorHybrid.cxx | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Generators/include/Generators/GeneratorHybrid.h b/Generators/include/Generators/GeneratorHybrid.h index 1f651b4464753..21f669776d944 100644 --- a/Generators/include/Generators/GeneratorHybrid.h +++ b/Generators/include/Generators/GeneratorHybrid.h @@ -104,9 +104,9 @@ class GeneratorHybrid : public Generator std::vector> mGroups; // Trigger configuration - std::vector mTriggerModes; // trigger mode for each generator + std::vector mTriggerModes; // trigger mode for each generator std::vector> mTriggerMacros; // trigger macros for each generator (multiple triggers for each generator possible) - std::vector> mTriggerFuncs; // trigger functions for each generator (multiple triggers for each generator possible) + std::vector> mTriggerFuncs; // trigger functions for each generator (multiple triggers for each generator possible) // Create a task arena with a specified number of threads std::thread mTBBTaskPoolRunner; diff --git a/Generators/src/GeneratorFactory.cxx b/Generators/src/GeneratorFactory.cxx index 1bd1f58254ec2..16aded9f5c4ac 100644 --- a/Generators/src/GeneratorFactory.cxx +++ b/Generators/src/GeneratorFactory.cxx @@ -298,7 +298,7 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair Trigger trigger = nullptr; DeepTrigger deeptrigger = nullptr; - if(!genconfig.compare("hybrid") == 0){ + if (!genconfig.compare("hybrid") == 0) { auto trgconfig = conf.getTrigger(); if (trgconfig.empty()) { return; diff --git a/Generators/src/GeneratorHybrid.cxx b/Generators/src/GeneratorHybrid.cxx index 43d8c861e07e6..69caf3449703b 100644 --- a/Generators/src/GeneratorHybrid.cxx +++ b/Generators/src/GeneratorHybrid.cxx @@ -272,7 +272,7 @@ Bool_t GeneratorHybrid::Init() // } } bool isTriggered = false; - while(!isTriggered) { + while (!isTriggered) { generator->clearParticles(); generator->generateEvent(); generator->importParticles(); @@ -490,9 +490,9 @@ Bool_t GeneratorHybrid::confSetter(const auto& gen) auto trigger_specs = [this, &trigger]() { mTriggerMacros.push_back({}); mTriggerFuncs.push_back({}); - if(trigger.HasMember("specs")) { - for(auto& spec : trigger["specs"].GetArray()) { - if(spec.HasMember("macro")){ + if (trigger.HasMember("specs")) { + for (auto& spec : trigger["specs"].GetArray()) { + if (spec.HasMember("macro")) { const auto& macro = spec["macro"].GetString(); if (!strcmp(macro, "") == 0) { mTriggerMacros.back().push_back(macro); From d3879010bc1b49520e05c6d3a44c4ae5bd7939e0 Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Fri, 17 Jan 2025 17:42:44 +0100 Subject: [PATCH 3/3] Added hybrid trigger example --- Generators/src/GeneratorFactory.cxx | 2 +- Generators/src/GeneratorHybrid.cxx | 4 +- run/SimExamples/Hybrid_trigger/README.md | 16 +++++ .../Hybrid_trigger/hybridconfig.json | 32 ++++++++++ run/SimExamples/Hybrid_trigger/runo2sim.sh | 60 +++++++++++++++++++ run/SimExamples/Hybrid_trigger/trigger.macro | 45 ++++++++++++++ 6 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 run/SimExamples/Hybrid_trigger/README.md create mode 100644 run/SimExamples/Hybrid_trigger/hybridconfig.json create mode 100755 run/SimExamples/Hybrid_trigger/runo2sim.sh create mode 100644 run/SimExamples/Hybrid_trigger/trigger.macro diff --git a/Generators/src/GeneratorFactory.cxx b/Generators/src/GeneratorFactory.cxx index 16aded9f5c4ac..5db1354a12908 100644 --- a/Generators/src/GeneratorFactory.cxx +++ b/Generators/src/GeneratorFactory.cxx @@ -298,7 +298,7 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair Trigger trigger = nullptr; DeepTrigger deeptrigger = nullptr; - if (!genconfig.compare("hybrid") == 0) { + if (!(genconfig.compare("hybrid") == 0)) { auto trgconfig = conf.getTrigger(); if (trgconfig.empty()) { return; diff --git a/Generators/src/GeneratorHybrid.cxx b/Generators/src/GeneratorHybrid.cxx index 69caf3449703b..03a78eb852eb6 100644 --- a/Generators/src/GeneratorHybrid.cxx +++ b/Generators/src/GeneratorHybrid.cxx @@ -494,7 +494,7 @@ Bool_t GeneratorHybrid::confSetter(const auto& gen) for (auto& spec : trigger["specs"].GetArray()) { if (spec.HasMember("macro")) { const auto& macro = spec["macro"].GetString(); - if (!strcmp(macro, "") == 0) { + if (!(strcmp(macro, "") == 0)) { mTriggerMacros.back().push_back(macro); } else { mTriggerMacros.back().push_back(""); @@ -504,7 +504,7 @@ Bool_t GeneratorHybrid::confSetter(const auto& gen) } if (spec.HasMember("function")) { const auto& function = spec["function"].GetString(); - if (!strcmp(function, "") == 0) { + if (!(strcmp(function, "") == 0)) { mTriggerFuncs.back().push_back(function); } else { mTriggerFuncs.back().push_back(""); diff --git a/run/SimExamples/Hybrid_trigger/README.md b/run/SimExamples/Hybrid_trigger/README.md new file mode 100644 index 0000000000000..21ccde29dece5 --- /dev/null +++ b/run/SimExamples/Hybrid_trigger/README.md @@ -0,0 +1,16 @@ + + +The usage of the Hybrid generator with the o2-sim is presented in this short manual. +All the other generators are implemented as sub-generators and they can be called thanks to a +JSON file, fed to o2-sim via the GeneratorHybrid.configFile parameter. The O2sim package needs to be loaded in order to use this example. + +The example can be run automatically using the runo2sim.sh script, which contains most of the +available generators in O2. The JSON template can be generated using the ${O2DPG_ROOT}/MC/bin/o2_hybrid_gen.py script. To use this example the user can simply copy the entire Hybrid example folder and execute the script after giving it execution permissions (`chmod +x runo2sim.sh`). + +# Files description + +- **runo2sim.sh** → allows to use the hybrid generator example +- **hybridconfig.json** → example JSON file for the hybrid generator configuration +- **example.optns** → options file to be used in EPOS4 implemented as subgenerator in this example (the .optns must be available in the current working directory) \ No newline at end of file diff --git a/run/SimExamples/Hybrid_trigger/hybridconfig.json b/run/SimExamples/Hybrid_trigger/hybridconfig.json new file mode 100644 index 0000000000000..cc565ecec0256 --- /dev/null +++ b/run/SimExamples/Hybrid_trigger/hybridconfig.json @@ -0,0 +1,32 @@ +{ + "generators": [ + { + "cocktail": [ + { + "name": "pythia8hi", + "triggers": { + "mode": "or", + "specs": [ + { + "macro": "${PWD}/trigger.macro", + "function": "trigger_impactb_pythia8(0.,5.)" + } + ] + }, + "config": "" + }, + { + "name": "external", + "config": { + "fileName": "${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGDQ/external/generator/GeneratorPromptCharmonia.C", + "funcName": "GeneratorParamPromptJpsiToElectronEvtGen_pp13TeV()", + "iniFile": "" + } + } + ] + } + ], + "fractions": [ + 1 + ] +} \ No newline at end of file diff --git a/run/SimExamples/Hybrid_trigger/runo2sim.sh b/run/SimExamples/Hybrid_trigger/runo2sim.sh new file mode 100755 index 0000000000000..75880a396e8e5 --- /dev/null +++ b/run/SimExamples/Hybrid_trigger/runo2sim.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# +# Hybrid generator simulation example with triggers and cocktail: +# the simulation is configured using a JSON file (hybridconfig.json in this folder), whose +# template can be generated using the script ${O2DPG_ROOT}/MC/bin/o2_hybrid_gen.py. +# Trigger is taken from the trigger.macro and it's a simple impact parameter selection for +# heavy ion collisions +set -x +if [ ! "${O2DPG_ROOT}" ]; then + echo "This needs O2DPG loaded; alienv enter ..." + exit 1 +fi + +[ ! "${O2_ROOT}" ] && echo "Error: This needs O2 loaded" && exit 2 + +NEV=1 +more="" +JOBS=2 + +usage() +{ + cat </dev/stderr + exit 3 + ;; + esac + shift +done + +# Starting simulation with Hybrid generator +${O2_ROOT}/bin/o2-sim --noGeant -j $JOBS --field ccdb --vertexMode kCCDB --run 300000 --configKeyValues "MFTBase.buildAlignment=true;GeneratorHybrid.configFile=$PWD/hybridconfig.json;GeneratorHybrid.randomize=false;${more}" -g hybrid -o genevents --timestamp 1546300800000 --seed 836302859 -n $NEV \ No newline at end of file diff --git a/run/SimExamples/Hybrid_trigger/trigger.macro b/run/SimExamples/Hybrid_trigger/trigger.macro new file mode 100644 index 0000000000000..ad187dcdc7e45 --- /dev/null +++ b/run/SimExamples/Hybrid_trigger/trigger.macro @@ -0,0 +1,45 @@ +#include "Generators/Trigger.h" +#include "TParticle.h" +#include + +// a very simple trigger example, examining generated particles +o2::eventgen::Trigger trigger() +{ + // + return [](const std::vector& particles) -> bool { + std::cout << "Running trigger on event with size " << particles.size() << "\n"; + if (particles.size() > 10000) { + return true; + } + return false; + }; +} + +#include "Pythia8/Pythia.h" +#include "Pythia8/HIInfo.h" +#include +// a deep trigger example, looking into the internal generator state +o2::eventgen::DeepTrigger + trigger_impactb_pythia8(double bmin = 5., double bmax = 10.) +{ + return [bmin, bmax](void* interface, std::string name) -> bool { + if (!name.compare("pythia8")) { + auto py8 = reinterpret_cast(interface); +#if PYTHIA_VERSION_INTEGER < 8300 + auto hiinfo = py8->info.hiinfo; +#else + auto hiinfo = py8->info.hiInfo; +#endif + if (!hiinfo) { + LOG(fatal) << "Cannot define impact parameter: is \'pythia8\' running in heavy-ion mode?"; + } + auto b = hiinfo->b(); + auto selected = (b > bmin && b < bmax); + LOG(info) << "Impact parameter = " << b << " fm: " << (selected ? "selected" : "rejected"); + return selected; + } else { + LOG(fatal) << "Cannot define impact parameter for generator interface \'" << name << "\'"; + } + return false; + }; +}