Project
Loading...
Searching...
No Matches
CollisionContextTool.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#include <boost/program_options.hpp>
13#include <string>
14#include <iostream>
16#include <regex>
22#include <cmath>
23#include <TRandom.h>
24#include <numeric>
25#include <fairlogger/Logger.h>
30#include "SimConfig/SimConfig.h"
31
32//
33// Created by Sandro Wenzel on 13.07.21.
34//
35
36// A utility to create/engineer (later modify/display) collision contexts
37
38// options struct filled from command line
39struct Options {
40 std::vector<std::string> interactionRates;
41 std::string qedInteraction; // specification for QED contribution
42 std::string outfilename; //
43 int orbits; // number of orbits to generate (can be a multiple of orbitsPerTF --> determine fraction or multiple of timeframes)
44 long seed; //
45 bool printContext = false;
46 std::string bcpatternfile;
47 int tfid = 0; // tfid -> used to calculate start orbit for collisions
48 double orbitsEarly = 0.; // how many orbits from a prev timeframe should still be kept in the current timeframe
49 double firstFractionalOrbit; // capture orbit and bunch crossing via decimal number
50 uint32_t firstOrbit = 0; // first orbit in run (orbit offset)
51 uint32_t firstBC = 0; // first bunch crossing (relative to firstOrbit) of the first interaction;
52 int orbitsPerTF = 256; // number of orbits per timeframe --> used to calculate start orbit for collisions
54 bool noEmptyTF = false; // prevent empty timeframes; the first interaction will be shifted backwards to fall within the range given by Options.orbits
55 int maxCollsPerTF = -1; // the maximal number of hadronic collisions per TF (can be used to constrain number of collisions per timeframe to some maximal value)
56 std::string configKeyValues = ""; // string to init config key values
57 long timestamp = -1; // timestamp for CCDB queries
58 std::string individualTFextraction = ""; // triggers extraction of individuel timeframe components when non-null
59 // format is path prefix
60 std::string vertexModeString{"kNoVertex"}; // Vertex Mode; vertices will be assigned to collisions of mode != kNoVertex
62};
63
65 NOLOCK,
66 EVERYN,
68};
69
71 std::string name; // name (prefix for transport simulation); may also serve as unique identifier
73 std::pair<int, float> synconto; // if this interaction locks on another interaction; takes precedence over interactionRate
75 char syncmodeop = 0; // syncmode operation ("@" --> embedd; "r" --> replace)
76 int mcnumberasked = -1; // number of MC events asked (but can be left -1) in which case it will be determined from timeframelength
77 int mcnumberavail = -1; // number of MC events avail (but can be left -1); if avail < asked there will be reuse of events
78 bool randomizeorder = false; // whether order of events will be randomized
79};
80
81InteractionSpec parseInteractionSpec(std::string const& specifier, std::vector<InteractionSpec> const& existingPatterns, bool adjustEventCount)
82{
83 // An interaction specification is a command-separated string
84 // of the following form:
85 // SPEC=NAMESTRING,INTERACTIONSTRING[,MCNUMBERSTRING]
86 //
87 // where
88 //
89 // NAMESTRING : a simple named specifier for the interaction; matching to a simulation prefix used by o2-sim
90 //
91 // INTERACTIONSTRING: irate | @ID:[ed]FLOATVALUE
92 // - either: a simple number irate specifying the interaction rate in kHz
93 // - or: a string such as @0:e5, saying that this interaction should match/sync
94 // with collisions of the 0-th interaction, but inject only every 5 collisions.
95 // Alternatively @0:d10000 means to inject but leaving a timedistance of at least 10000ns between signals
96 // - or: a string r0:e5, saying that this interaction should sync with collisions of the 0-th interaction but
97 // **overwrite** every 5-th interaction with a collision from this interaction name
98 // MCNUMBERSTRING: NUMBER1:r?NUMBER2 can specify how many collisions NUMBER1 to produce, taking from a sample of NUMBER2 available collisions
99 // - this option is only supported on the first interaction which is supposed to be the background interaction
100 // - if the 'r' character is present we randomize the order of the MC events
101
102 // tokens are separated by comma
103 std::vector<std::string> tokens = o2::RangeTokenizer::tokenize<std::string>(specifier);
104
105 float rate = -1.;
106 std::pair<int, float> synconto(-1, 1);
107
108 // extract (kinematics prefix) name
109 std::string name = tokens[0];
110
111 // extract the MC number spec if given
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);
118
119 std::cmatch m;
120 if (std::regex_match(mctoken.c_str(), m, re)) {
121 collisionsasked = std::atoi(m[1].str().c_str());
122 if (m[2].str().compare("r") == 0) {
123 randomizeorder = true;
124 }
125 collisionsavail = std::atoi(m[3].str().c_str());
126 } else {
127 LOG(error) << "Could not parse " << mctoken << " as MCNUMBERSTRING";
128 exit(1);
129 }
130 }
131
132 if (adjustEventCount) {
133 // if the number of collisionsavail has not been specified, we should
134 // try to extract it from the kinematics directly
136 if (collisionsavail > 0) {
137 collisionsavail = std::min((size_t)collisionsavail, (size_t)mcreader.getNEvents(0));
138 } else {
139 collisionsavail = mcreader.getNEvents(0);
140 }
141 }
142 LOG(info) << "Collisions avail for " << name << " " << collisionsavail;
143
144 // extract interaction rate ... or locking
145 auto& interactionToken = tokens[1];
146 if (interactionToken[0] == '@' || interactionToken[0] == 'r') {
147 try {
148 // locking onto some other interaction
149 std::regex re("[@r]([0-9]*):([ed])([0-9]*[.]?[0-9]?)$", std::regex_constants::extended);
150
151 std::cmatch m;
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());
156
157 if (crossindex > existingPatterns.size()) {
158 LOG(error) << "Reference to non-existent interaction spec";
159 exit(1);
160 }
161 synconto = std::pair<int, float>(crossindex, modevalue);
162
163 InteractionLockMode lockMode;
164 if (mode.compare("e") == 0) {
166 }
167 if (mode.compare("d") == 0) {
169 }
170 return InteractionSpec{name, rate, synconto, lockMode, interactionToken[0], collisionsasked, collisionsavail, randomizeorder};
171 } else {
172 LOG(error) << "Could not parse " << interactionToken << " as INTERACTIONSTRING";
173 exit(1);
174 }
175 } catch (std::regex_error e) {
176 LOG(error) << "Exception during regular expression match " << e.what();
177 exit(1);
178 }
179 } else {
180 rate = std::atof(interactionToken.c_str());
181 return InteractionSpec{name, rate, synconto, InteractionLockMode::NOLOCK, 0, collisionsasked, collisionsavail, randomizeorder};
182 }
183}
184
185bool parseOptions(int argc, char* argv[], Options& optvalues)
186{
187 namespace bpo = boost::program_options;
188 bpo::options_description options(
189 "A utility to create and manipulate digitization contexts (MC collision structure within a timeframe).\n\n"
190 "Allowed options");
191
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")(
212 "extract-per-timeframe", bpo::value<std::string>(&optvalues.individualTFextraction)->default_value(""),
213 "Extract individual timeframe contexts. Format required: time_frame_prefix[:comma_separated_list_of_signals_to_offset]");
214
215 options.add_options()("help,h", "Produce help message.");
216
217 bpo::variables_map vm;
218 try {
219 bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm);
220 bpo::notify(vm);
221
222 // help
223 if (vm.count("help")) {
224 std::cout << options << std::endl;
225 return false;
226 }
227 if (vm.count("show-context")) {
228 optvalues.printContext = true;
229 }
230 if (vm.count("use-existing-kine")) {
231 optvalues.useexistingkinematics = true;
232 }
233
235
236 // fix the first orbit and bunch crossing
237 // auto orbitbcpair = parseOrbitAndBC(optvalues.firstIRString);
238 optvalues.firstOrbit = (uint32_t)optvalues.firstFractionalOrbit;
239 optvalues.firstBC = (uint32_t)((optvalues.firstFractionalOrbit - 1. * optvalues.firstOrbit) * o2::constants::lhc::LHCMaxBunches);
240 LOG(info) << "First orbit " << optvalues.firstOrbit;
241 LOG(info) << "First BC " << optvalues.firstBC;
242
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;
247 return false;
248 }
249 return true;
250}
251
252int main(int argc, char* argv[])
253{
254 Options options;
255 if (!parseOptions(argc, argv, options)) {
256 exit(1);
257 }
258
259 // init params
261
262 // init random generator
263 gRandom->SetSeed(options.seed);
264
265 std::vector<InteractionSpec> ispecs;
266 // building the interaction spec
267 for (auto& i : options.interactionRates) {
268 // this is created as output from
269 ispecs.push_back(parseInteractionSpec(i, ispecs, options.useexistingkinematics));
270 }
271
272 std::vector<std::pair<o2::InteractionTimeRecord, std::vector<o2::steer::EventPart>>> collisions;
273 std::vector<o2::BunchFilling> bunchFillings; // vector of bunch filling objects; generated by interaction samplers
274
275 // now we generate the collision structure (interaction type by interaction type)
276 bool usetimeframelength = options.orbits > 0;
277
278 auto setBCFillingHelper = [&options](auto& sampler, auto& bcPatternString) {
279 if (bcPatternString == "ccdb") {
280 LOG(info) << "Fetch bcPattern information from CCDB";
281 // fetch the GRP Object
283 ccdb.setCaching(false);
284 ccdb.setLocalObjectValidityChecking(true);
285 auto grpLHC = ccdb.getForTimeStamp<o2::parameters::GRPLHCIFData>("GLO/Config/GRPLHCIF", options.timestamp);
286 LOG(info) << "Fetched injection scheme " << grpLHC->getInjectionScheme() << " from CCDB";
287 sampler.setBunchFilling(grpLHC->getBunchFilling());
288 } else {
289 sampler.setBunchFilling(bcPatternString);
290 }
291 };
292
293 // this is the starting orbit from which on we construct interactions (it is possibly shifted by one tf to the left
294 // in order to generate eventual "earlyOrbits"
295 auto orbitstart = options.firstOrbit + options.tfid * options.orbitsPerTF;
296 auto orbits_total = options.orbits;
297 if (options.orbitsEarly > 0.) {
298 orbitstart -= options.orbitsPerTF;
299 orbits_total += options.orbitsPerTF;
300 }
301
302 for (int id = 0; id < ispecs.size(); ++id) {
303 auto mode = ispecs[id].syncmode;
306 sampler.setInteractionRate(ispecs[id].interactionRate);
307 if (!options.bcpatternfile.empty()) {
308 setBCFillingHelper(sampler, options.bcpatternfile);
309 }
311 // this loop makes sure that the first collision is within the range of orbits asked (if noEmptyTF is enabled)
312 do {
313 sampler.setFirstIR(o2::InteractionRecord(options.firstBC, orbitstart));
314 sampler.init();
315 record = sampler.generateCollisionTime();
316 } while (options.noEmptyTF && usetimeframelength && record.orbit >= orbitstart + orbits_total);
317 int count = 0;
318 do {
319 if (usetimeframelength && record.orbit >= orbitstart + orbits_total) {
320 break;
321 }
322 std::vector<o2::steer::EventPart> parts;
323 parts.emplace_back(id, count);
324
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();
329 count++;
330 } while ((ispecs[id].mcnumberasked > 0 && count < ispecs[id].mcnumberasked)); // TODO: this loop should probably be replaced by a condition with usetimeframelength and number of orbits
331
332 // we support randomization etc on non-injected/embedded interactions
333 // and we can apply them here
334 auto random_shuffle = [](auto first, auto last) {
335 auto n = last - first;
336 for (auto i = n - 1; i > 0; --i) {
337 using std::swap;
338 swap(first[i], first[(int)(gRandom->Rndm() * n)]);
339 }
340 };
341 std::vector<int> eventindices(count);
342 std::iota(eventindices.begin(), eventindices.end(), 0);
343 // apply randomization of order if any
344 if (ispecs[id].randomizeorder) {
345 random_shuffle(eventindices.begin(), eventindices.end());
346 }
347 if (ispecs[id].mcnumberavail > 0) {
348 // apply cutting to number of available entries
349 for (auto& e : eventindices) {
350 e = e % ispecs[id].mcnumberavail;
351 }
352 }
353 // make these transformations final:
354 for (auto& col : collisions) {
355 for (auto& part : col.second) {
356 if (part.sourceID == id) {
357 part.entryID = eventindices[part.entryID];
358 }
359 }
360 }
361
362 // keep bunch filling information produced by these samplers
363 bunchFillings.push_back(sampler.getBunchFilling());
364
365 } else {
366 // we are in some lock/sync mode and modify existing collisions
367 int lastcol = -1;
368 double lastcoltime = -1.;
369 auto distanceval = ispecs[id].synconto.second;
370 auto lockonto = ispecs[id].synconto.first;
371 int eventcount = 0;
372
373 for (int colid = 0; colid < collisions.size(); ++colid) {
374 auto& col = collisions[colid];
375 auto coltime = col.first.getTimeNS();
376
377 bool rightinteraction = false;
378 // we are locking only on collisions which have the referenced interaction present
379 // --> there must be an EventPart with the right sourceID
380 for (auto& eventPart : col.second) {
381 if (eventPart.sourceID == lockonto) {
382 rightinteraction = true;
383 break;
384 }
385 }
386 if (!rightinteraction) {
387 continue;
388 }
389
390 bool inject = false;
391 // we always start with first one
392 if (lastcol == -1) {
393 inject = true;
394 }
395 if (mode == InteractionLockMode::EVERYN && (colid - lastcol) >= distanceval) {
396 inject = true;
397 }
398 if (mode == InteractionLockMode::MINTIMEDISTANCE && (coltime - lastcoltime) >= distanceval) {
399 inject = true;
400 }
401
402 if (inject) {
403 if (ispecs[id].syncmodeop == 'r') {
404 LOG(debug) << "Replacing/overwriting another event ";
405 // Syncing is replacing; which means we need to take out the original
406 // event that we locked onto.
407 // We take out this event part immediately (and complain if there is a problem).
408 int index = 0;
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);
412 } else {
413 LOG(error) << "Expected to replace another event part but did not find one for source " << lockonto << " and collision " << colid;
414 }
415 }
416
417 if (ispecs[id].mcnumberavail >= 0) {
418 col.second.emplace_back(id, eventcount % ispecs[id].mcnumberavail);
419 } else {
420 col.second.emplace_back(id, eventcount);
421 }
422 eventcount++;
423 lastcol = colid;
424 lastcoltime = coltime;
425 }
426 }
427 }
428 }
429
430 // create DigitizationContext
432 // we can fill this container
433 auto& parts = digicontext.getEventParts();
434 // we can fill this container
435 auto& records = digicontext.getEventRecords();
436 // copy over information
437 size_t maxParts = 0;
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);
442 }
443 digicontext.setNCollisions(collisions.size());
444 digicontext.setMaxNumberParts(maxParts);
445 // merge bunch filling info
446 for (int i = 1; i < bunchFillings.size(); ++i) {
447 bunchFillings[0].mergeWith(bunchFillings[i]);
448 }
449 digicontext.setBunchFilling(bunchFillings[0]);
450 std::vector<std::string> prefixes;
451 for (auto& p : ispecs) {
452 prefixes.push_back(p.name);
453 }
454 digicontext.setSimPrefixes(prefixes);
455
456 // <---- at this moment we have a dense collision context (not representing the final output we want)
457 LOG(info) << "<<------ DENSE CONTEXT ---------";
458 if (options.printContext) {
459 digicontext.printCollisionSummary();
460 }
461 LOG(info) << "-------- DENSE CONTEXT ------->>";
462
463 auto timeframeindices = digicontext.calcTimeframeIndices(orbitstart, options.orbitsPerTF, options.orbitsEarly);
464 // apply max collision per timeframe filters + reindexing of event id (linearisation and compactification)
465 digicontext.applyMaxCollisionFilter(timeframeindices, orbitstart, options.orbitsPerTF, options.maxCollsPerTF, options.orbitsEarly);
466
467 // <---- at this moment we have a dense collision context (not representing the final output we want)
468 LOG(info) << "<<------ FILTERED CONTEXT ---------";
469 if (options.printContext) {
470 digicontext.printCollisionSummary();
471 }
472 LOG(info) << "-------- FILTERED CONTEXT ------->>";
473
474 auto numTimeFrames = timeframeindices.size(); // digicontext.finalizeTimeframeStructure(orbitstart, options.orbitsPerTF, options.orbitsEarly);
475
477 switch (options.vertexMode) {
479 // fetch mean vertex from CCDB
481 if (meanv) {
482 LOG(info) << "Applying vertexing using CCDB mean vertex " << *meanv;
483 digicontext.sampleInteractionVertices(*meanv);
484 } else {
485 LOG(fatal) << "No vertex available";
486 }
487 break;
488 }
489
491 // init this vertex from CCDB or InteractionDiamond parameter
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;
495 digicontext.sampleInteractionVertices(meanv);
496 break;
497 }
498 default: {
499 LOG(error) << "Unknown vertex mode ... Not generating vertices";
500 }
501 }
502 }
503
504 // we fill QED contributions to the context
505 if (options.qedInteraction.size() > 0) {
506 // TODO: use bcFilling information
507 auto qedSpec = parseInteractionSpec(options.qedInteraction, ispecs, options.useexistingkinematics);
508 std::cout << "### IRATE " << qedSpec.interactionRate << "\n";
509 digicontext.fillQED(qedSpec.name, qedSpec.mcnumberasked, qedSpec.interactionRate);
510 }
511
512 if (options.printContext) {
513 digicontext.printCollisionSummary();
514 }
515 digicontext.saveToFile(options.outfilename);
516
517 // extract individual timeframes
518 if (options.individualTFextraction.size() > 0) {
519 // we are asked to extract individual timeframe components
520
521 LOG(info) << "Extracting individual timeframe collision contexts";
522 // extract prefix path to store these collision contexts
523 // Function to check the pattern and extract tokens from b
524 auto check_and_extract_tokens = [](const std::string& input, std::vector<std::string>& tokens) {
525 // the regular expression pattern for expected input format
526 const std::regex pattern(R"(^([a-zA-Z0-9]+)(:([a-zA-Z0-9]+(,[a-zA-Z0-9]+)*))?$)");
527 std::smatch matches;
528
529 // Check if the input matches the pattern
530 if (std::regex_match(input, matches, pattern)) {
531 // Clear any existing tokens in the vector
532 tokens.clear();
533
534 // matches[1] contains the part before the colon which we save first
535 tokens.push_back(matches[1].str());
536 // matches[2] contains the comma-separated list
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();
541
542 // Iterate over the tokens and add them to the vector
543 for (std::sregex_iterator i = tokens_begin; i != tokens_end; ++i) {
544 tokens.push_back((*i).str());
545 }
546 return true;
547 }
548 LOG(error) << "Argument for --extract-per-timeframe does not match specification";
549 return false;
550 };
551
552 std::vector<std::string> tokens;
553 if (check_and_extract_tokens(options.individualTFextraction, tokens)) {
554 auto path_prefix = tokens[0];
555 std::vector<int> sources_to_offset{};
556
557 LOG(info) << "PREFIX is " << path_prefix;
558
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]));
562 }
563
564 auto first_timeframe = options.orbitsEarly > 0. ? 1 : 0;
565 // now we are ready to loop over all timeframes
566 int tf_output_counter = 1;
567 for (int tf_id = first_timeframe; tf_id < numTimeFrames; ++tf_id) {
568 auto copy = digicontext.extractSingleTimeframe(tf_id, timeframeindices, sources_to_offset);
569
570 // each individual case gets QED interactions injected
571 // This should probably be done inside the extraction itself
572 if (digicontext.isQEDProvided()) {
573 auto qedSpec = parseInteractionSpec(options.qedInteraction, ispecs, options.useexistingkinematics);
574 copy.fillQED(qedSpec.name, qedSpec.mcnumberasked, qedSpec.interactionRate);
575 }
576
577 std::stringstream str;
578 str << path_prefix << tf_output_counter++ << "/collisioncontext.root";
579 copy.saveToFile(str.str());
580 LOG(info) << "----";
581 copy.printCollisionSummary();
582 }
583 }
584 }
585
586 return 0;
587}
bool parseOptions(int argc, char *argv[], Options &optvalues)
InteractionSpec parseInteractionSpec(std::string const &specifier, std::vector< InteractionSpec > const &existingPatterns, bool adjustEventCount)
int32_t i
container for the LHC InterFace data
Helper function to tokenize sequences and ranges of integral numbers.
uint32_t eventcount
Definition RawData.h:1
uint32_t col
Definition RawData.h:4
std::ostringstream debug
static BasicCCDBManager & instance()
T * getForTimeStamp(std::string const &path, long timestamp)
retrieve an object of type T from CCDB as stored under path and timestamp
static void updateFromString(std::string const &)
static bool parseVertexModeString(std::string const &vertexstring, o2::conf::VertexMode &mode)
const std::string & getInjectionScheme() const
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
int findSimPrefix(std::string const &prefix) const
void applyMaxCollisionFilter(std::vector< std::tuple< int, int, int > > &timeframeindices, long startOrbit, long orbitsPerTF, int maxColl, double orbitsEarly=0.)
void setSimPrefixes(std::vector< std::string > const &p)
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)
void saveToFile(std::string_view filename) const
void setBunchFilling(o2::BunchFilling const &bf)
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
void setInteractionRate(float rateHz)
size_t getNEvents(int source) const
Get number of events.
GLdouble n
Definition glcorearb.h:1982
const GLfloat * m
Definition glcorearb.h:4066
GLenum mode
Definition glcorearb.h:266
GLint GLsizei count
Definition glcorearb.h:399
GLuint GLenum * rate
Definition glcorearb.h:5735
GLuint sampler
Definition glcorearb.h:1630
GLuint index
Definition glcorearb.h:781
GLuint const GLchar * name
Definition glcorearb.h:781
GLint first
Definition glcorearb.h:399
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLuint GLfloat * val
Definition glcorearb.h:1582
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLuint id
Definition glcorearb.h:650
constexpr int LHCMaxBunches
InteractionLockMode syncmode
std::pair< int, float > synconto
std::string vertexModeString
std::string configKeyValues
Definition GRPTool.cxx:66
o2::conf::VertexMode vertexMode
std::string individualTFextraction
std::string bcpatternfile
std::vector< std::string > interactionRates
uint64_t timestamp
Definition GRPTool.cxx:67
std::string outfilename
double firstFractionalOrbit
int orbitsPerTF
Definition GRPTool.cxx:51
std::string qedInteraction
uint32_t orbit
LHC orbit.
void compare(std::string_view s1, std::string_view s2)
#define main
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::array< uint16_t, 5 > pattern
const std::string str