Skip to content

Commit 5c29d41

Browse files
authored
Merge 42a6068 into sapling-pr-archive-ktf
2 parents 816b8e5 + 42a6068 commit 5c29d41

File tree

61 files changed

+1078
-931
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1078
-931
lines changed

CCDB/include/CCDB/CcdbObjectInfo.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,16 @@ class CcdbObjectInfo
9393
[[nodiscard]] long getEndValidityTimestamp() const { return mEnd; }
9494
void setEndValidityTimestamp(long end) { mEnd = end; }
9595

96+
bool operator<(const CcdbObjectInfo& other) const
97+
{
98+
return mStart < other.mStart;
99+
}
100+
101+
bool operator>(const CcdbObjectInfo& other) const
102+
{
103+
return mStart > other.mStart;
104+
}
105+
96106
private:
97107
std::string mObjType{}; // object type (e.g. class)
98108
std::string mFileName{}; // file name in the CCDB
@@ -107,4 +117,17 @@ class CcdbObjectInfo
107117

108118
} // namespace o2::ccdb
109119

120+
namespace std
121+
{
122+
// defining std::hash for InteractionRecord to be used with std containers
123+
template <>
124+
struct hash<o2::ccdb::CcdbObjectInfo> {
125+
public:
126+
size_t operator()(const o2::ccdb::CcdbObjectInfo& info) const
127+
{
128+
return info.getStartValidityTimestamp();
129+
}
130+
};
131+
} // namespace std
132+
110133
#endif // O2_CCDB_CCDBOBJECTINFO_H_

DataFormats/simulation/include/SimulationDataFormat/DigitizationContext.h

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ class DigitizationContext
115115

116116
/// retrieves collision context for a single timeframe-id (which may be needed by simulation)
117117
/// (Only copies collision context without QED information. This can be added to the result with the fillQED method
118-
/// in a second step. As a pre-condition, one should have called finalizeTimeframeStructure)
119-
DigitizationContext extractSingleTimeframe(int timeframeid, std::vector<int> const& sources_to_offset);
118+
/// in a second step. Takes as input a timeframe indices collection)
119+
DigitizationContext extractSingleTimeframe(int timeframeid, std::vector<std::tuple<int, int, int>> const& timeframeindices, std::vector<int> const& sources_to_offset);
120120

121121
/// function reading the hits from a chain (previously initialized with initSimChains
122122
/// The hits pointer will be initialized (what to we do about ownership??)
@@ -130,12 +130,12 @@ class DigitizationContext
130130
/// returns the GRP object associated to this context
131131
o2::parameters::GRPObject const& getGRP() const;
132132

133-
// apply collision number cuts and potential relabeling of eventID
134-
void applyMaxCollisionFilter(long startOrbit, long orbitsPerTF, int maxColl);
133+
// apply collision number cuts and potential relabeling of eventID, (keeps collisions which fall into the orbitsEarly range for the next timeframe)
134+
// needs a timeframe index structure (determined by calcTimeframeIndices), which is adjusted during the process to reflect the filtering
135+
void applyMaxCollisionFilter(std::vector<std::tuple<int, int, int>>& timeframeindices, long startOrbit, long orbitsPerTF, int maxColl, double orbitsEarly = 0.);
135136

136-
/// finalize timeframe structure (fixes the indices in mTimeFrameStartIndex)
137-
// returns the number of timeframes
138-
int finalizeTimeframeStructure(long startOrbit, long orbitsPerTF);
137+
/// get timeframe structure --> index markers where timeframe starts/ends/is_influenced_by
138+
std::vector<std::tuple<int, int, int>> calcTimeframeIndices(long startOrbit, long orbitsPerTF, double orbitsEarly = 0.) const;
139139

140140
// Sample and fix interaction vertices (according to some distribution). Makes sure that same event ids
141141
// have to have same vertex, as well as event ids associated to same collision.
@@ -176,17 +176,13 @@ class DigitizationContext
176176
// for each collision we record the constituents (which shall not exceed mMaxPartNumber)
177177
std::vector<std::vector<o2::steer::EventPart>> mEventParts;
178178

179-
// for each collision we may record/fix the interaction vertex (to be used in event generation)
179+
// for each collisionstd::vector<std::tuple<int,int,int>> &timeframeindice we may record/fix the interaction vertex (to be used in event generation)
180180
std::vector<math_utils::Point3D<float>> mInteractionVertices;
181181

182182
// the collision records **with** QED interleaved;
183183
std::vector<o2::InteractionTimeRecord> mEventRecordsWithQED;
184184
std::vector<std::vector<o2::steer::EventPart>> mEventPartsWithQED;
185185

186-
// timeframe structure
187-
std::vector<std::pair<int, int>> mTimeFrameStartIndex; // for each timeframe, the pair of start-index and end-index into mEventParts, mEventRecords
188-
std::vector<std::pair<int, int>> mTimeFrameStartIndexQED; // for each timeframe, the pair of start-index and end-index into mEventParts, mEventRecords (QED version)
189-
190186
o2::BunchFilling mBCFilling; // pattern of active BCs
191187

192188
std::vector<std::string> mSimPrefixes; // identifiers to the hit sim products; the key corresponds to the source ID of event record

DataFormats/simulation/src/DigitizationContext.cxx

Lines changed: 152 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,27 @@ void DigitizationContext::printCollisionSummary(bool withQED, int truncateOutput
4949
}
5050
} else {
5151
std::cout << "Number of Collisions " << mEventRecords.size() << "\n";
52+
if (mEventPartsWithQED.size() > 0) {
53+
auto num_qed_events = mEventPartsWithQED.size() - mEventRecords.size();
54+
if (num_qed_events > 0) {
55+
std::cout << "Number of QED events (but not shown) " << num_qed_events << "\n";
56+
// find first and last QED collision so that we can give the range in orbits where these
57+
// things are included
58+
auto firstQEDcoll_iter = std::find_if(mEventPartsWithQED.begin(), mEventPartsWithQED.end(),
59+
[](const std::vector<EventPart>& vec) {
60+
return std::find_if(vec.begin(), vec.end(), [](EventPart const& p) { return p.sourceID == 99; }) != vec.end();
61+
});
62+
63+
auto lastColl_iter = std::find_if(mEventPartsWithQED.rbegin(), mEventPartsWithQED.rend(),
64+
[](const std::vector<EventPart>& vec) {
65+
return std::find_if(vec.begin(), vec.end(), [](EventPart const& p) { return p.sourceID == 99; }) != vec.end();
66+
});
67+
68+
auto firstindex = std::distance(mEventPartsWithQED.begin(), firstQEDcoll_iter);
69+
auto lastindex = std::distance(mEventPartsWithQED.begin(), lastColl_iter.base()) - 1;
70+
std::cout << "QED from: " << mEventRecordsWithQED[firstindex] << " ---> " << mEventRecordsWithQED[lastindex] << "\n";
71+
}
72+
}
5273
for (int i = 0; i < mEventRecords.size(); ++i) {
5374
if (truncateOutputTo >= 0 && i > truncateOutputTo) {
5475
std::cout << "--- Output truncated to " << truncateOutputTo << " ---\n";
@@ -380,32 +401,126 @@ std::vector<std::pair<int, int>> getTimeFrameBoundaries(std::vector<o2::Interact
380401
result.emplace_back(std::pair<int, int>(left, right - 1));
381402
return result;
382403
}
404+
405+
// a common helper for timeframe structure - includes indices for orbits-early (orbits from last timeframe still affecting current one)
406+
std::vector<std::tuple<int, int, int>> getTimeFrameBoundaries(std::vector<o2::InteractionTimeRecord> const& irecords,
407+
long startOrbit,
408+
long orbitsPerTF,
409+
float orbitsEarly)
410+
{
411+
// we could actually use the other method first ... then do another pass to fix the early-index ... or impact index
412+
auto true_indices = getTimeFrameBoundaries(irecords, startOrbit, orbitsPerTF);
413+
414+
std::vector<std::tuple<int, int, int>> indices_with_early{};
415+
for (int ti = 0; ti < true_indices.size(); ++ti) {
416+
// for each timeframe we copy the true indices
417+
auto& tf_range = true_indices[ti];
418+
419+
// init new index without fixing the early index yet
420+
indices_with_early.push_back(std::make_tuple(tf_range.first, tf_range.second, -1));
421+
422+
// from the second timeframe on we can determine the index in the previous timeframe
423+
// which matches our criterion
424+
if (orbitsEarly > 0. && ti > 0) {
425+
auto& prev_tf_range = true_indices[ti - 1];
426+
// in this range search the smallest index which precedes
427+
// timeframe ti by not more than "orbitsEarly" orbits
428+
// (could probably use binary search, in case optimization becomes necessary)
429+
int earlyOrbitIndex = prev_tf_range.second;
430+
431+
// this is the orbit of the ti-th timeframe start
432+
auto orbit_timeframe_start = startOrbit + ti * orbitsPerTF;
433+
434+
auto orbit_timeframe_early_fractional = orbit_timeframe_start - orbitsEarly;
435+
auto orbit_timeframe_early_integral = (uint32_t)(orbit_timeframe_early_fractional);
436+
437+
auto bc_early = (uint32_t)((orbit_timeframe_early_fractional - orbit_timeframe_early_integral) * o2::constants::lhc::LHCMaxBunches);
438+
439+
// this is the interaction record of the ti-th timeframe start
440+
o2::InteractionRecord timeframe_start_record(0, orbit_timeframe_early_integral);
441+
// this is the interaction record in some previous timeframe after which interactions could still
442+
// influence the ti-th timeframe according to orbitsEarly
443+
o2::InteractionRecord timeframe_early_record(bc_early, orbit_timeframe_early_integral);
444+
445+
auto differenceInBCNS_max = timeframe_start_record.differenceInBCNS(timeframe_early_record);
446+
447+
for (int j = prev_tf_range.second; j >= prev_tf_range.first; --j) {
448+
// determine difference in timing in NS; compare that with the limit given by orbitsEarly
449+
auto timediff_NS = timeframe_start_record.differenceInBCNS(irecords[j]);
450+
if (timediff_NS < differenceInBCNS_max) {
451+
earlyOrbitIndex = j;
452+
} else {
453+
break;
454+
}
455+
}
456+
std::get<2>(indices_with_early.back()) = earlyOrbitIndex;
457+
}
458+
}
459+
return indices_with_early;
460+
}
461+
383462
} // namespace
384463

385-
void DigitizationContext::applyMaxCollisionFilter(long startOrbit, long orbitsPerTF, int maxColl)
464+
void DigitizationContext::applyMaxCollisionFilter(std::vector<std::tuple<int, int, int>>& timeframeindices, long startOrbit, long orbitsPerTF, int maxColl, double orbitsEarly)
386465
{
387466
// the idea is to go through each timeframe and throw away collisions beyond a certain count
388467
// then the indices should be condensed
389468

390469
std::vector<std::vector<o2::steer::EventPart>> newparts;
391470
std::vector<o2::InteractionTimeRecord> newrecords;
392471

393-
// get a timeframe boundary indexing
394-
auto timeframeindices = getTimeFrameBoundaries(mEventRecords, startOrbit, orbitsPerTF);
395-
396472
std::unordered_map<int, int> currMaxId; // the max id encountered for a source
397473
std::unordered_map<int, std::unordered_map<int, int>> reIndexMap; // for each source, a map of old to new index for the event parts
398474

399475
if (maxColl == -1) {
400476
maxColl = mEventRecords.size();
401477
}
402478

479+
// the actual first actual timeframe
480+
int first_timeframe = orbitsEarly > 0. ? 1 : 0;
481+
482+
// mapping of old to new indices
483+
std::unordered_map<size_t, size_t> indices_old_to_new;
484+
403485
// now we can go through the structure timeframe by timeframe
404-
for (auto timeframe : timeframeindices) {
405-
auto firstindex = timeframe.first;
406-
auto lastindex = timeframe.second;
486+
for (int tf_id = first_timeframe; tf_id < timeframeindices.size(); ++tf_id) {
487+
auto& tf_indices = timeframeindices[tf_id];
488+
489+
auto firstindex = std::get<0>(tf_indices); // .first;
490+
auto lastindex = std::get<1>(tf_indices); // .second;
491+
auto previndex = std::get<2>(tf_indices);
492+
493+
LOG(info) << "timeframe indices " << previndex << " : " << firstindex << " : " << lastindex;
494+
495+
int collCount = 0; // counting collisions within timeframe
407496
// copy to new structure
408-
for (int index = firstindex; index <= std::min(lastindex, firstindex + maxColl - 1); ++index) {
497+
for (int index = previndex >= 0 ? previndex : firstindex; index <= lastindex; ++index) {
498+
if (collCount >= maxColl) {
499+
continue;
500+
}
501+
502+
// look if this index was already done?
503+
// avoid duplicate entries in transformed records
504+
if (indices_old_to_new.find(index) != indices_old_to_new.end()) {
505+
continue;
506+
}
507+
508+
// we put these events under a certain condition
509+
bool keep = index < firstindex || collCount < maxColl;
510+
511+
if (!keep) {
512+
continue;
513+
}
514+
515+
if (index >= firstindex) {
516+
collCount++;
517+
}
518+
519+
// we must also make sure that we don't duplicate the records
520+
// moreover some records are merely put as precoll of tf2 ---> so they shouldn't be part of tf1 in the final
521+
// extraction, ouch !
522+
// maybe we should combine the filter and individual tf extraction in one step !!
523+
indices_old_to_new[index] = newrecords.size();
409524
newrecords.push_back(mEventRecords[index]);
410525
newparts.push_back(mEventParts[index]);
411526

@@ -427,22 +542,35 @@ void DigitizationContext::applyMaxCollisionFilter(long startOrbit, long orbitsPe
427542
currMaxId[source] += 1;
428543
}
429544
}
545+
} // ends one timeframe
546+
547+
// correct the timeframe indices
548+
if (indices_old_to_new.find(firstindex) != indices_old_to_new.end()) {
549+
std::get<0>(tf_indices) = indices_old_to_new[firstindex]; // start
550+
}
551+
if (indices_old_to_new.find(lastindex) != indices_old_to_new.end()) {
552+
std::get<1>(tf_indices) = indices_old_to_new[lastindex]; // end;
553+
} else {
554+
std::get<1>(tf_indices) = newrecords.size(); // end;
555+
}
556+
if (indices_old_to_new.find(previndex) != indices_old_to_new.end()) {
557+
std::get<2>(tf_indices) = indices_old_to_new[previndex]; // previous or "early" index
430558
}
431559
}
432560
// reassignment
433561
mEventRecords = newrecords;
434562
mEventParts = newparts;
435563
}
436564

437-
int DigitizationContext::finalizeTimeframeStructure(long startOrbit, long orbitsPerTF)
565+
std::vector<std::tuple<int, int, int>> DigitizationContext::calcTimeframeIndices(long startOrbit, long orbitsPerTF, double orbitsEarly) const
438566
{
439-
mTimeFrameStartIndex = getTimeFrameBoundaries(mEventRecords, startOrbit, orbitsPerTF);
440-
LOG(info) << "Fixed " << mTimeFrameStartIndex.size() << " timeframes ";
441-
for (auto p : mTimeFrameStartIndex) {
442-
LOG(info) << p.first << " " << p.second;
567+
auto timeframeindices = getTimeFrameBoundaries(mEventRecords, startOrbit, orbitsPerTF, orbitsEarly);
568+
LOG(info) << "Fixed " << timeframeindices.size() << " timeframes ";
569+
for (auto p : timeframeindices) {
570+
LOG(info) << std::get<0>(p) << " " << std::get<1>(p) << " " << std::get<2>(p);
443571
}
444572

445-
return mTimeFrameStartIndex.size();
573+
return timeframeindices;
446574
}
447575

448576
std::unordered_map<int, int> DigitizationContext::getCollisionIndicesForSource(int source) const
@@ -529,21 +657,25 @@ void DigitizationContext::sampleInteractionVertices(o2::dataformats::MeanVertexO
529657
}
530658
}
531659

532-
DigitizationContext DigitizationContext::extractSingleTimeframe(int timeframeid, std::vector<int> const& sources_to_offset)
660+
DigitizationContext DigitizationContext::extractSingleTimeframe(int timeframeid, std::vector<std::tuple<int, int, int>> const& timeframeindices, std::vector<int> const& sources_to_offset)
533661
{
534662
DigitizationContext r; // make a return object
535-
if (mTimeFrameStartIndex.size() == 0) {
536-
LOG(error) << "No timeframe structure determined; Returning empty object. Please call ::finalizeTimeframeStructure before calling this function";
663+
if (timeframeindices.size() == 0) {
664+
LOG(error) << "Timeframe index structure empty; Returning empty object.";
537665
return r;
538666
}
539667
r.mSimPrefixes = mSimPrefixes;
540668
r.mMuBC = mMuBC;
541669
try {
542-
auto startend = mTimeFrameStartIndex.at(timeframeid);
670+
auto tf_ranges = timeframeindices.at(timeframeid);
543671

544-
auto startindex = startend.first;
545-
auto endindex = startend.second;
672+
auto startindex = std::get<0>(tf_ranges);
673+
auto endindex = std::get<1>(tf_ranges);
674+
auto earlyindex = std::get<2>(tf_ranges);
546675

676+
if (earlyindex >= 0) {
677+
startindex = earlyindex;
678+
}
547679
std::copy(mEventRecords.begin() + startindex, mEventRecords.begin() + endindex, std::back_inserter(r.mEventRecords));
548680
std::copy(mEventParts.begin() + startindex, mEventParts.begin() + endindex, std::back_inserter(r.mEventParts));
549681
if (mInteractionVertices.size() > endindex) {

Detectors/CTF/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ comma-separated list of detectors to skip
100100
```
101101
max CTFs to process (<= 0 : infinite)
102102
103+
```
104+
--max-tf-per-file arg (=-1)
105+
```
106+
max TFs to process from every CTF file (<= 0 : infinite)
107+
103108
```
104109
--loop arg (=0)
105110
```

Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ struct CTFReaderInp {
4040
int64_t delay_us = 0;
4141
int maxLoops = 0;
4242
int maxTFs = -1;
43+
int maxTFsPerFile = -1;
4344
unsigned int subspec = 0;
4445
unsigned int decSSpecEMC = 0;
4546
int tfRateLimit = -999;

Detectors/CTF/workflow/src/CTFReaderSpec.cxx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ void CTFReaderSpec::init(InitContext& ic)
148148
mUseLocalTFCounter = ic.options().get<bool>("local-tf-counter");
149149
mImposeRunStartMS = ic.options().get<int64_t>("impose-run-start-timstamp");
150150
mInput.checkTFLimitBeforeReading = ic.options().get<bool>("limit-tf-before-reading");
151+
mInput.maxTFs = ic.options().get<int>("max-tf");
152+
mInput.maxTFs = mInput.maxTFs > 0 ? mInput.maxTFs : 0x7fffffff;
153+
mInput.maxTFsPerFile = ic.options().get<int>("max-tf-per-file");
154+
mInput.maxTFsPerFile = mInput.maxTFsPerFile > 0 ? mInput.maxTFsPerFile : 0x7fffffff;
151155
mRunning = true;
152156
mFileFetcher = std::make_unique<o2::utils::FileFetcher>(mInput.inpdata, mInput.tffileRegex, mInput.remoteRegex, mInput.copyCmd);
153157
mFileFetcher->setMaxFilesInQueue(mInput.maxFileCache);
@@ -360,7 +364,7 @@ bool CTFReaderSpec::processTF(ProcessingContext& pc)
360364
void CTFReaderSpec::checkTreeEntries()
361365
{
362366
// check if the tree has entries left, if needed, close current tree/file
363-
if (++mCurrTreeEntry >= mCTFTree->GetEntries()) { // this file is done, check if there are other files
367+
if (++mCurrTreeEntry >= mCTFTree->GetEntries() || (mInput.maxTFsPerFile > 0 && mCurrTreeEntry >= mInput.maxTFsPerFile)) { // this file is done, check if there are other files
364368
mCTFTree.reset();
365369
mCTFFile->Close();
366370
mCTFFile.reset();
@@ -474,6 +478,9 @@ DataProcessorSpec getCTFReaderSpec(const CTFReaderInp& inp)
474478
options.emplace_back(ConfigParamSpec{"local-tf-counter", VariantType::Bool, false, {"reassign header.tfCounter from local TF counter"}});
475479
options.emplace_back(ConfigParamSpec{"fetch-failure-threshold", VariantType::Float, 0.f, {"Fail if too many failures( >0: fraction, <0: abs number, 0: no threshold)"}});
476480
options.emplace_back(ConfigParamSpec{"limit-tf-before-reading", VariantType::Bool, false, {"Check TF limiting before reading new TF, otherwhise before injecting it"}});
481+
options.emplace_back(ConfigParamSpec{"max-tf", VariantType::Int, -1, {"max CTFs to process (<= 0 : infinite)"}});
482+
options.emplace_back(ConfigParamSpec{"max-tf-per-file", VariantType::Int, -1, {"max TFs to process per ctf file (<= 0 : infinite)"}});
483+
477484
if (!inp.metricChannel.empty()) {
478485
options.emplace_back(ConfigParamSpec{"channel-config", VariantType::String, inp.metricChannel, {"Out-of-band channel config for TF throttling"}});
479486
}

Detectors/CTF/workflow/src/ctf-reader-workflow.cxx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions)
5454
options.push_back(ConfigParamSpec{"ctf-input", VariantType::String, "none", {"comma-separated list CTF input files"}});
5555
options.push_back(ConfigParamSpec{"onlyDet", VariantType::String, std::string{DetID::ALL}, {"comma-separated list of detectors to accept. Overrides skipDet"}});
5656
options.push_back(ConfigParamSpec{"skipDet", VariantType::String, std::string{DetID::NONE}, {"comma-separate list of detectors to skip"}});
57-
options.push_back(ConfigParamSpec{"max-tf", VariantType::Int, -1, {"max CTFs to process (<= 0 : infinite)"}});
5857
options.push_back(ConfigParamSpec{"loop", VariantType::Int, 0, {"loop N times (infinite for N<0)"}});
5958
options.push_back(ConfigParamSpec{"delay", VariantType::Float, 0.f, {"delay in seconds between consecutive TFs sending"}});
6059
options.push_back(ConfigParamSpec{"copy-cmd", VariantType::String, "alien_cp ?src file://?dst", {"copy command for remote files or no-copy to avoid copying"}}); // Use "XrdSecPROTOCOL=sss,unix xrdcp -N root://eosaliceo2.cern.ch/?src ?dst" for direct EOS access
@@ -116,8 +115,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext)
116115
if (ctfInput.delay_us < 0) {
117116
ctfInput.delay_us = 0;
118117
}
119-
int n = configcontext.options().get<int>("max-tf");
120-
ctfInput.maxTFs = n > 0 ? n : 0x7fffffff;
121118

122119
ctfInput.maxFileCache = std::max(1, configcontext.options().get<int>("max-cached-files"));
123120

0 commit comments

Comments
 (0)