103 std::vector<std::string> tokens = o2::RangeTokenizer::tokenize<std::string>(specifier);
106 std::pair<int, float> synconto(-1, 1);
109 std::string
name = tokens[0];
112 int collisionsasked = -1;
113 int collisionsavail = -1;
114 bool randomizeorder =
false;
115 if (tokens.size() > 2) {
116 auto mctoken = tokens[2];
117 std::regex re(
"([0-9]*):(r?)([0-9]*)$", std::regex_constants::extended);
120 if (std::regex_match(mctoken.c_str(),
m, re)) {
121 collisionsasked = std::atoi(
m[1].
str().c_str());
123 randomizeorder =
true;
125 collisionsavail = std::atoi(
m[3].
str().c_str());
127 LOG(error) <<
"Could not parse " << mctoken <<
" as MCNUMBERSTRING";
132 if (adjustEventCount) {
136 if (collisionsavail > 0) {
137 collisionsavail = std::min((
size_t)collisionsavail, (
size_t)mcreader.
getNEvents(0));
142 LOG(info) <<
"Collisions avail for " <<
name <<
" " << collisionsavail;
145 auto& interactionToken = tokens[1];
146 if (interactionToken[0] ==
'@' || interactionToken[0] ==
'r') {
149 std::regex re(
"[@r]([0-9]*):([ed])([0-9]*[.]?[0-9]?)$", std::regex_constants::extended);
152 if (std::regex_match(interactionToken.c_str(),
m, re)) {
153 auto crossindex = std::atoi(
m[1].
str().c_str());
154 auto mode =
m[2].str();
155 auto modevalue = std::atof(
m[3].
str().c_str());
157 if (crossindex > existingPatterns.size()) {
158 LOG(error) <<
"Reference to non-existent interaction spec";
161 synconto = std::pair<int, float>(crossindex, modevalue);
164 if (
mode.compare(
"e") == 0) {
167 if (
mode.compare(
"d") == 0) {
170 return InteractionSpec{
name,
rate, synconto, lockMode, interactionToken[0], collisionsasked, collisionsavail, randomizeorder};
172 LOG(error) <<
"Could not parse " << interactionToken <<
" as INTERACTIONSTRING";
175 }
catch (std::regex_error e) {
176 LOG(error) <<
"Exception during regular expression match " << e.what();
180 rate = std::atof(interactionToken.c_str());
188 bpo::options_description options(
189 "A utility to create and manipulate digitization contexts (MC collision structure within a timeframe).\n\n"
192 options.add_options()(
193 "interactions,i", bpo::value<std::vector<std::string>>(&optvalues.
interactionRates)->multitoken(),
"name,IRate|LockSpecifier")(
194 "QEDinteraction", bpo::value<std::string>(&optvalues.
qedInteraction)->default_value(
""),
"Interaction specifier for QED contribution (name,IRATE,maxeventnumber)")(
195 "outfile,o", bpo::value<std::string>(&optvalues.
outfilename)->default_value(
"collisioncontext.root"),
"Outfile of collision context")(
196 "orbits", bpo::value<int>(&optvalues.
orbits)->default_value(-1),
197 "Number of orbits to generate maximally (if given, can be used to determine the number of timeframes). "
198 "Otherwise, the context will be generated by using collision numbers from the interaction specification.")(
199 "seed", bpo::value<long>(&optvalues.
seed)->default_value(0L),
"Seed for random number generator (for time sampling etc). Default 0: Random")(
200 "show-context",
"Print generated collision context to terminal.")(
201 "bcPatternFile", bpo::value<std::string>(&optvalues.
bcpatternfile)->default_value(
""),
"Interacting BC pattern file (e.g. from CreateBCPattern.C); Use \"ccdb\" when fetching from CCDB.")(
202 "orbitsPerTF", bpo::value<int>(&optvalues.
orbitsPerTF)->default_value(256),
"Orbits per timeframes")(
203 "orbitsEarly", bpo::value<double>(&optvalues.
orbitsEarly)->default_value(0.),
"Number of orbits with extra collisions prefixed to each timeframe")(
204 "use-existing-kine",
"Read existing kinematics to adjust event counts")(
205 "timeframeID", bpo::value<int>(&optvalues.
tfid)->default_value(0),
"Timeframe id of the first timeframe int this context. Allows to generate contexts for different start orbits")(
206 "first-orbit", bpo::value<double>(&optvalues.
firstFractionalOrbit)->default_value(0),
"First (fractional) orbit in the run (HBFUtils.firstOrbit + BC from decimal)")(
207 "maxCollsPerTF", bpo::value<int>(&optvalues.
maxCollsPerTF)->default_value(-1),
"Maximal number of MC collisions to put into one timeframe. By default no constraint.")(
208 "noEmptyTF", bpo::bool_switch(&optvalues.
noEmptyTF),
"Enforce to have at least one collision")(
209 "configKeyValues", bpo::value<std::string>(&optvalues.
configKeyValues)->default_value(
""),
"Semicolon separated key=value strings (e.g.: 'TPC.gasDensity=1;...')")(
210 "with-vertices", bpo::value<std::string>(&optvalues.
vertexModeString)->default_value(
"kNoVertex"),
"Assign vertices to collisions. Argument is the vertex mode. Defaults to no vertexing applied")(
211 "timestamp", bpo::value<long>(&optvalues.
timestamp)->default_value(-1L),
"Timestamp for CCDB queries / anchoring")(
213 "Extract individual timeframe contexts. Format required: time_frame_prefix[:comma_separated_list_of_signals_to_offset]");
215 options.add_options()(
"help,h",
"Produce help message.");
217 bpo::variables_map vm;
219 bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm);
223 if (vm.count(
"help")) {
224 std::cout << options << std::endl;
227 if (vm.count(
"show-context")) {
230 if (vm.count(
"use-existing-kine")) {
241 LOG(info) <<
"First BC " << optvalues.
firstBC;
243 }
catch (
const bpo::error& e) {
244 std::cerr << e.what() <<
"\n\n";
245 std::cerr <<
"Error parsing options; Available options:\n";
246 std::cerr << options << std::endl;
252int main(
int argc,
char* argv[])
263 gRandom->SetSeed(options.
seed);
265 std::vector<InteractionSpec> ispecs;
272 std::vector<std::pair<o2::InteractionTimeRecord, std::vector<o2::steer::EventPart>>> collisions;
273 std::vector<o2::BunchFilling> bunchFillings;
276 bool usetimeframelength = options.
orbits > 0;
278 auto setBCFillingHelper = [&options](
auto&
sampler,
auto& bcPatternString) {
279 if (bcPatternString ==
"ccdb") {
280 LOG(info) <<
"Fetch bcPattern information from CCDB";
283 ccdb.setCaching(
false);
284 ccdb.setLocalObjectValidityChecking(
true);
287 sampler.setBunchFilling(grpLHC->getBunchFilling());
289 sampler.setBunchFilling(bcPatternString);
296 auto orbits_total = options.
orbits;
302 for (
int id = 0;
id < ispecs.size(); ++
id) {
303 auto mode = ispecs[
id].syncmode;
315 record =
sampler.generateCollisionTime();
316 }
while (options.
noEmptyTF && usetimeframelength && record.
orbit >= orbitstart + orbits_total);
319 if (usetimeframelength && record.
orbit >= orbitstart + orbits_total) {
322 std::vector<o2::steer::EventPart> parts;
323 parts.emplace_back(
id,
count);
325 std::pair<o2::InteractionTimeRecord, std::vector<o2::steer::EventPart>> insertvalue(record, parts);
326 auto iter = std::lower_bound(collisions.begin(), collisions.end(), insertvalue, [](std::pair<
o2::InteractionTimeRecord, std::vector<o2::steer::EventPart>>
const&
a, std::pair<
o2::InteractionTimeRecord, std::vector<o2::steer::EventPart>>
const&
b) { return a.first < b.first; });
327 collisions.insert(iter, insertvalue);
328 record =
sampler.generateCollisionTime();
330 }
while ((ispecs[
id].mcnumberasked > 0 &&
count < ispecs[
id].mcnumberasked));
334 auto random_shuffle = [](
auto first,
auto last) {
336 for (
auto i =
n - 1;
i > 0; --
i) {
341 std::vector<int> eventindices(
count);
342 std::iota(eventindices.begin(), eventindices.end(), 0);
344 if (ispecs[
id].randomizeorder) {
345 random_shuffle(eventindices.begin(), eventindices.end());
347 if (ispecs[
id].mcnumberavail > 0) {
349 for (
auto& e : eventindices) {
350 e = e % ispecs[
id].mcnumberavail;
354 for (
auto&
col : collisions) {
355 for (
auto& part :
col.second) {
356 if (part.sourceID ==
id) {
357 part.entryID = eventindices[part.entryID];
363 bunchFillings.push_back(
sampler.getBunchFilling());
368 double lastcoltime = -1.;
369 auto distanceval = ispecs[
id].synconto.second;
370 auto lockonto = ispecs[
id].synconto.first;
373 for (
int colid = 0; colid < collisions.size(); ++colid) {
374 auto&
col = collisions[colid];
375 auto coltime =
col.first.getTimeNS();
377 bool rightinteraction =
false;
380 for (
auto& eventPart :
col.second) {
381 if (eventPart.sourceID == lockonto) {
382 rightinteraction =
true;
386 if (!rightinteraction) {
403 if (ispecs[
id].syncmodeop ==
'r') {
404 LOG(
debug) <<
"Replacing/overwriting another event ";
409 auto iter = std::find_if(
col.second.begin(),
col.second.end(), [lockonto](
auto val) { return lockonto == val.sourceID; });
410 if (iter !=
col.second.end()) {
411 col.second.erase(iter);
413 LOG(error) <<
"Expected to replace another event part but did not find one for source " << lockonto <<
" and collision " << colid;
417 if (ispecs[
id].mcnumberavail >= 0) {
418 col.second.emplace_back(
id,
eventcount % ispecs[
id].mcnumberavail);
424 lastcoltime = coltime;
438 for (
auto& p : collisions) {
439 records.push_back(p.first);
440 parts.push_back(p.second);
441 maxParts = std::max(p.second.size(), maxParts);
446 for (
int i = 1;
i < bunchFillings.size(); ++
i) {
447 bunchFillings[0].mergeWith(bunchFillings[
i]);
450 std::vector<std::string> prefixes;
451 for (
auto& p : ispecs) {
452 prefixes.push_back(p.name);
457 LOG(info) <<
"<<------ DENSE CONTEXT ---------";
461 LOG(info) <<
"-------- DENSE CONTEXT ------->>";
468 LOG(info) <<
"<<------ FILTERED CONTEXT ---------";
472 LOG(info) <<
"-------- FILTERED CONTEXT ------->>";
474 auto numTimeFrames = timeframeindices.size();
482 LOG(info) <<
"Applying vertexing using CCDB mean vertex " << *meanv;
485 LOG(fatal) <<
"No vertex available";
493 o2::dataformats::MeanVertexObject meanv(dparam.position[0], dparam.position[1], dparam.position[2], dparam.width[0], dparam.width[1], dparam.width[2], dparam.slopeX, dparam.slopeY);
494 LOG(info) <<
"Applying vertexing using DiamondParam mean vertex " << meanv;
499 LOG(error) <<
"Unknown vertex mode ... Not generating vertices";
508 std::cout <<
"### IRATE " << qedSpec.interactionRate <<
"\n";
509 digicontext.
fillQED(qedSpec.name, qedSpec.mcnumberasked, qedSpec.interactionRate);
521 LOG(info) <<
"Extracting individual timeframe collision contexts";
524 auto check_and_extract_tokens = [](
const std::string& input, std::vector<std::string>& tokens) {
526 const std::regex
pattern(R
"(^([a-zA-Z0-9]+)(:([a-zA-Z0-9]+(,[a-zA-Z0-9]+)*))?$)");
530 if (std::regex_match(input, matches,
pattern)) {
535 tokens.push_back(matches[1].
str());
537 std::string
b = matches[2].str();
538 std::regex token_pattern(R
"([a-zA-Z0-9]+)");
539 auto tokens_begin = std::sregex_iterator(
b.begin(),
b.end(), token_pattern);
540 auto tokens_end = std::sregex_iterator();
543 for (std::sregex_iterator
i = tokens_begin;
i != tokens_end; ++
i) {
544 tokens.push_back((*i).str());
548 LOG(error) <<
"Argument for --extract-per-timeframe does not match specification";
552 std::vector<std::string> tokens;
554 auto path_prefix = tokens[0];
555 std::vector<int> sources_to_offset{};
557 LOG(info) <<
"PREFIX is " << path_prefix;
559 for (
int i = 1;
i < tokens.size(); ++
i) {
560 LOG(info) <<
"Offsetting " << tokens[
i];
561 sources_to_offset.push_back(digicontext.
findSimPrefix(tokens[
i]));
564 auto first_timeframe = options.
orbitsEarly > 0. ? 1 : 0;
566 int tf_output_counter = 1;
567 for (
int tf_id = first_timeframe; tf_id < numTimeFrames; ++tf_id) {
574 copy.fillQED(qedSpec.name, qedSpec.mcnumberasked, qedSpec.interactionRate);
577 std::stringstream
str;
578 str << path_prefix << tf_output_counter++ <<
"/collisioncontext.root";
579 copy.saveToFile(
str.str());
581 copy.printCollisionSummary();
DigitizationContext extractSingleTimeframe(int timeframeid, std::vector< std::tuple< int, int, int > > const &timeframeindices, std::vector< int > const &sources_to_offset)
void fillQED(std::string_view QEDprefix, int max_events, double qedrate)
add QED contributions to context, giving prefix; maximal event number and qed interaction rate
void printCollisionSummary(bool withQED=false, int truncateOutputTo=-1) const
void applyMaxCollisionFilter(std::vector< std::tuple< int, int, int > > &timeframeindices, long startOrbit, long orbitsPerTF, int maxColl, double orbitsEarly=0.)
std::vector< o2::InteractionTimeRecord > & getEventRecords(bool withQED=false)
void sampleInteractionVertices(o2::dataformats::MeanVertexObject const &v)
std::vector< std::vector< o2::steer::EventPart > > & getEventParts(bool withQED=false)
std::vector< std::tuple< int, int, int > > calcTimeframeIndices(long startOrbit, long orbitsPerTF, double orbitsEarly=0.) const
get timeframe structure --> index markers where timeframe starts/ends/is_influenced_by