Skip to content

Commit 9855980

Browse files
committed
Integrate non-uniform InteractionSampler into CollisionContextTool
Possibility to inject non-uniform MU(BC) distributions into the collision context creation. Distributions can come from ROOT file or CCDB and follow a format from EventSelectionQA (histogram hBcTVX). Example: ``` --nontrivial-mu-distribution ccdb://http://ccdb-test.cern.ch:8080/GLO/CALIB/EVSELQA/HBCTVX' ```
1 parent 07e63da commit 9855980

File tree

2 files changed

+79
-3
lines changed

2 files changed

+79
-3
lines changed

DataFormats/simulation/src/InteractionSampler.cxx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@ bool NonUniformMuInteractionSampler::setBCIntensityScales(const TH1F& hist)
202202

203203
std::vector<float> NonUniformMuInteractionSampler::determineBCIntensityScalesFromHistogram(const TH1F& hist)
204204
{
205+
if (mInteractingBCs.size() == 0) {
206+
LOG(error) << " Initialize bunch crossing scheme before assigning scales";
207+
}
205208
std::vector<float> scales;
206209
// we go through the BCs and query the count from histogram
207210
for (auto bc : mInteractingBCs) {

Steer/src/CollisionContextTool.cxx

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
#include "DataFormatsParameters/GRPLHCIFData.h"
3030
#include "SimConfig/SimConfig.h"
3131
#include <filesystem>
32+
#include <sstream>
33+
#include <vector>
34+
#include <numeric>
3235

3336
//
3437
// Created by Sandro Wenzel on 13.07.21.
@@ -64,6 +67,8 @@ struct Options {
6467
// This is useful when someone else is creating the contexts (MC-data embedding) and we
6568
// merely want to pass these through. If this is given, we simply take the timeframe ID, number of orbits
6669
// and copy the right amount of timeframes into the destination folder (implies individualTFextraction)
70+
std::string nontrivial_mu_distribution = ""; // path to fetch a non-uniform MC(BC) distribution for the interaction sampler
71+
// can be: (a) ccdb, (b) a ROOT file with the histogram included
6772
};
6873

6974
enum class InteractionLockMode {
@@ -72,6 +77,28 @@ enum class InteractionLockMode {
7277
MINTIMEDISTANCE
7378
};
7479

80+
struct CcdbUrl {
81+
std::string server; // may include http:// or https://
82+
std::string port; // empty if none
83+
std::string fullPath; // everything after server[:port]/
84+
};
85+
86+
std::optional<CcdbUrl> parseCcdbRegex(const std::string& url)
87+
{
88+
static const std::regex re(
89+
R"(^(?:ccdb://)(https?://[^/:]+|[^/:]+)(?::(\d+))?/(.+)$)");
90+
std::smatch m;
91+
if (!std::regex_match(url, m, re)) {
92+
return std::nullopt;
93+
}
94+
95+
CcdbUrl out;
96+
out.server = m[1].str(); // server (may include http:// or https://)
97+
out.port = m[2].str(); // optional port
98+
out.fullPath = m[3].str(); // remainder
99+
return out;
100+
}
101+
75102
struct InteractionSpec {
76103
std::string name; // name (prefix for transport simulation); may also serve as unique identifier
77104
float interactionRate;
@@ -216,8 +243,8 @@ bool parseOptions(int argc, char* argv[], Options& optvalues)
216243
"timestamp", bpo::value<long>(&optvalues.timestamp)->default_value(-1L), "Timestamp for CCDB queries / anchoring")(
217244
"extract-per-timeframe", bpo::value<std::string>(&optvalues.individualTFextraction)->default_value(""),
218245
"Extract individual timeframe contexts. Format required: time_frame_prefix[:comma_separated_list_of_signals_to_offset]")(
219-
"import-external", bpo::value<std::string>(&optvalues.external_path)->default_value(""),
220-
"Take collision contexts (per timeframe) from external files for instance for data-anchoring use-case. Needs timeframeID and number of orbits to be given as well.");
246+
"import-external", bpo::value<std::string>(&optvalues.external_path)->default_value(""), "Take collision contexts (per timeframe) from external files for instance for data-anchoring use-case. Needs timeframeID and number of orbits to be given as well.")(
247+
"nontrivial-mu-distribution", bpo::value<std::string>(&optvalues.nontrivial_mu_distribution)->default_value(""), "Distribution for MU(BC)");
221248

222249
options.add_options()("help,h", "Produce help message.");
223250

@@ -397,6 +424,46 @@ int main(int argc, char* argv[])
397424
auto mode = ispecs[id].syncmode;
398425
if (mode == InteractionLockMode::NOLOCK) {
399426
auto sampler = std::make_unique<o2::steer::InteractionSampler>();
427+
TH1F* mu_hist = nullptr;
428+
429+
// we check if there is a realistic bunch crossing distribution available
430+
const auto& mu_distr_source = options.nontrivial_mu_distribution;
431+
if (mu_distr_source.size() > 0) {
432+
if (mu_distr_source.find("ccdb") == 0) {
433+
auto ccdb_info_wrapper = parseCcdbRegex(mu_distr_source);
434+
if (!ccdb_info_wrapper.has_value()) {
435+
LOG(error) << "Could not parse CCDB path for mu(bc) distribution";
436+
} else {
437+
auto& ccdb_info = ccdb_info_wrapper.value();
438+
439+
// for now construct a specific CCDBManager for this query
440+
o2::ccdb::CCDBManagerInstance ccdb_inst(ccdb_info.server + std::string(":") + ccdb_info.port);
441+
ccdb_inst.setFatalWhenNull(false);
442+
auto local_hist = ccdb_inst.getForTimeStamp<TH1F>(ccdb_info.fullPath, options.timestamp);
443+
if (local_hist) {
444+
mu_hist = (TH1F*)(local_hist->Clone("h2")); // we need to clone since ownership of local_hist is with TFile
445+
} else {
446+
LOG(warn) << "No mu(bc) distribution found on CCDB. Using uniform one";
447+
}
448+
}
449+
} else {
450+
// we interpret the file as a ROOT file and open it to extract the wanted histogram
451+
auto mudistr_file = TFile::Open(mu_distr_source.c_str(), "OPEN");
452+
if (mudistr_file && !mudistr_file->IsZombie()) {
453+
auto local_hist = mudistr_file->Get<TH1F>("hBcTVX");
454+
mu_hist = (TH1F*)(local_hist->Clone("h2")); // we need to clone since ownership of local_hist is with TFile
455+
mudistr_file->Close();
456+
}
457+
}
458+
if (mu_hist) {
459+
LOG(info) << "Found an external mu distribution with mean BC value " << mu_hist->GetMean();
460+
461+
// do some checks
462+
463+
// reset to correct interaction Sampler type
464+
sampler.reset(new o2::steer::NonUniformMuInteractionSampler());
465+
}
466+
}
400467

401468
// for debug purposes: allows to instantiate trivial sampler
402469
if (const char* env = getenv("ALICEO2_ENFORCE_TRIVIAL_BC_SAMPLER")) {
@@ -418,11 +485,17 @@ int main(int argc, char* argv[])
418485
if (!options.bcpatternfile.empty()) {
419486
setBCFillingHelper(*sampler, options.bcpatternfile);
420487
}
488+
sampler->init();
489+
if (auto sampler_cast = dynamic_cast<o2::steer::NonUniformMuInteractionSampler*>(sampler.get())) {
490+
if (mu_hist) {
491+
sampler_cast->setBCIntensityScales(*mu_hist);
492+
}
493+
}
494+
421495
o2::InteractionTimeRecord record;
422496
// this loop makes sure that the first collision is within the range of orbits asked (if noEmptyTF is enabled)
423497
do {
424498
sampler->setFirstIR(o2::InteractionRecord(options.firstBC, orbitstart));
425-
sampler->init();
426499
record = sampler->generateCollisionTime();
427500
} while (options.noEmptyTF && usetimeframelength && record.orbit >= orbitstart + orbits_total);
428501
int count = 0;

0 commit comments

Comments
 (0)