Skip to content

Commit 9fa6915

Browse files
committed
Orbit-early treatment in CollisionContext tool
Developments to allow treatment/inclusion of additional orbits before each timeframe start: - A new option `--earlyOrbits x` will prepend x orbits with collisions before the firstOrbit asked - It will also do the same in each individual timeframe collision context extracted from the global context - Collisions falling within the 'earlyOrbit' range are always kept and not filtered out based on a maximal count filter Some cleanup. Some restructuring/simplification of DigitizationContext: - less internal state - timeframe boundary indices are generalized from (start, end) --> (start, end, previous) where previous is the index from which on this timeframe can still be influenced with an earlyOrbit criterion
1 parent 6b8ca30 commit 9fa6915

File tree

3 files changed

+174
-43
lines changed

3 files changed

+174
-43
lines changed

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: 131 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -380,32 +380,126 @@ std::vector<std::pair<int, int>> getTimeFrameBoundaries(std::vector<o2::Interact
380380
result.emplace_back(std::pair<int, int>(left, right - 1));
381381
return result;
382382
}
383+
384+
// a common helper for timeframe structure - includes indices for orbits-early (orbits from last timeframe still affecting current one)
385+
std::vector<std::tuple<int, int, int>> getTimeFrameBoundaries(std::vector<o2::InteractionTimeRecord> const& irecords,
386+
long startOrbit,
387+
long orbitsPerTF,
388+
float orbitsEarly)
389+
{
390+
// we could actually use the other method first ... then do another pass to fix the early-index ... or impact index
391+
auto true_indices = getTimeFrameBoundaries(irecords, startOrbit, orbitsPerTF);
392+
393+
std::vector<std::tuple<int, int, int>> indices_with_early{};
394+
for (int ti = 0; ti < true_indices.size(); ++ti) {
395+
// for each timeframe we copy the true indices
396+
auto& tf_range = true_indices[ti];
397+
398+
// init new index without fixing the early index yet
399+
indices_with_early.push_back(std::make_tuple(tf_range.first, tf_range.second, -1));
400+
401+
// from the second timeframe on we can determine the index in the previous timeframe
402+
// which matches our criterion
403+
if (orbitsEarly > 0. && ti > 0) {
404+
auto& prev_tf_range = true_indices[ti - 1];
405+
// in this range search the smallest index which precedes
406+
// timeframe ti by not more than "orbitsEarly" orbits
407+
// (could probably use binary search, in case optimization becomes necessary)
408+
int earlyOrbitIndex = prev_tf_range.second;
409+
410+
// this is the orbit of the ti-th timeframe start
411+
auto orbit_timeframe_start = startOrbit + ti * orbitsPerTF;
412+
413+
auto orbit_timeframe_early_fractional = orbit_timeframe_start - orbitsEarly;
414+
auto orbit_timeframe_early_integral = (uint32_t)(orbit_timeframe_early_fractional);
415+
416+
auto bc_early = (uint32_t)((orbit_timeframe_early_fractional - orbit_timeframe_early_integral) * o2::constants::lhc::LHCMaxBunches);
417+
418+
// this is the interaction record of the ti-th timeframe start
419+
o2::InteractionRecord timeframe_start_record(0, orbit_timeframe_early_integral);
420+
// this is the interaction record in some previous timeframe after which interactions could still
421+
// influence the ti-th timeframe according to orbitsEarly
422+
o2::InteractionRecord timeframe_early_record(bc_early, orbit_timeframe_early_integral);
423+
424+
auto differenceInBCNS_max = timeframe_start_record.differenceInBCNS(timeframe_early_record);
425+
426+
for (int j = prev_tf_range.second; j >= prev_tf_range.first; --j) {
427+
// determine difference in timing in NS; compare that with the limit given by orbitsEarly
428+
auto timediff_NS = timeframe_start_record.differenceInBCNS(irecords[j]);
429+
if (timediff_NS < differenceInBCNS_max) {
430+
earlyOrbitIndex = j;
431+
} else {
432+
break;
433+
}
434+
}
435+
std::get<2>(indices_with_early.back()) = earlyOrbitIndex;
436+
}
437+
}
438+
return indices_with_early;
439+
}
440+
383441
} // namespace
384442

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

390448
std::vector<std::vector<o2::steer::EventPart>> newparts;
391449
std::vector<o2::InteractionTimeRecord> newrecords;
392450

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

399454
if (maxColl == -1) {
400455
maxColl = mEventRecords.size();
401456
}
402457

458+
// the actual first actual timeframe
459+
int first_timeframe = orbitsEarly > 0. ? 1 : 0;
460+
461+
// mapping of old to new indices
462+
std::unordered_map<size_t, size_t> indices_old_to_new;
463+
403464
// 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;
465+
for (int tf_id = first_timeframe; tf_id < timeframeindices.size(); ++tf_id) {
466+
auto& tf_indices = timeframeindices[tf_id];
467+
468+
auto firstindex = std::get<0>(tf_indices); // .first;
469+
auto lastindex = std::get<1>(tf_indices); // .second;
470+
auto previndex = std::get<2>(tf_indices);
471+
472+
LOG(info) << "timeframe indices " << previndex << " : " << firstindex << " : " << lastindex;
473+
474+
int collCount = 0; // counting collisions within timeframe
407475
// copy to new structure
408-
for (int index = firstindex; index <= std::min(lastindex, firstindex + maxColl - 1); ++index) {
476+
for (int index = previndex >= 0 ? previndex : firstindex; index <= lastindex; ++index) {
477+
if (collCount >= maxColl) {
478+
continue;
479+
}
480+
481+
// look if this index was already done?
482+
// avoid duplicate entries in transformed records
483+
if (indices_old_to_new.find(index) != indices_old_to_new.end()) {
484+
continue;
485+
}
486+
487+
// we put these events under a certain condition
488+
bool keep = index < firstindex || collCount < maxColl;
489+
490+
if (!keep) {
491+
continue;
492+
}
493+
494+
if (index >= firstindex) {
495+
collCount++;
496+
}
497+
498+
// we must also make sure that we don't duplicate the records
499+
// moreover some records are merely put as precoll of tf2 ---> so they shouldn't be part of tf1 in the final
500+
// extraction, ouch !
501+
// maybe we should combine the filter and individual tf extraction in one step !!
502+
indices_old_to_new[index] = newrecords.size();
409503
newrecords.push_back(mEventRecords[index]);
410504
newparts.push_back(mEventParts[index]);
411505

@@ -427,22 +521,35 @@ void DigitizationContext::applyMaxCollisionFilter(long startOrbit, long orbitsPe
427521
currMaxId[source] += 1;
428522
}
429523
}
524+
} // ends one timeframe
525+
526+
// correct the timeframe indices
527+
if (indices_old_to_new.find(firstindex) != indices_old_to_new.end()) {
528+
std::get<0>(tf_indices) = indices_old_to_new[firstindex]; // start
529+
}
530+
if (indices_old_to_new.find(lastindex) != indices_old_to_new.end()) {
531+
std::get<1>(tf_indices) = indices_old_to_new[lastindex]; // end;
532+
} else {
533+
std::get<1>(tf_indices) = newrecords.size(); // end;
534+
}
535+
if (indices_old_to_new.find(previndex) != indices_old_to_new.end()) {
536+
std::get<2>(tf_indices) = indices_old_to_new[previndex]; // previous or "early" index
430537
}
431538
}
432539
// reassignment
433540
mEventRecords = newrecords;
434541
mEventParts = newparts;
435542
}
436543

437-
int DigitizationContext::finalizeTimeframeStructure(long startOrbit, long orbitsPerTF)
544+
std::vector<std::tuple<int, int, int>> DigitizationContext::calcTimeframeIndices(long startOrbit, long orbitsPerTF, double orbitsEarly) const
438545
{
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;
546+
auto timeframeindices = getTimeFrameBoundaries(mEventRecords, startOrbit, orbitsPerTF, orbitsEarly);
547+
LOG(info) << "Fixed " << timeframeindices.size() << " timeframes ";
548+
for (auto p : timeframeindices) {
549+
LOG(info) << std::get<0>(p) << " " << std::get<1>(p) << " " << std::get<2>(p);
443550
}
444551

445-
return mTimeFrameStartIndex.size();
552+
return timeframeindices;
446553
}
447554

448555
std::unordered_map<int, int> DigitizationContext::getCollisionIndicesForSource(int source) const
@@ -529,21 +636,25 @@ void DigitizationContext::sampleInteractionVertices(o2::dataformats::MeanVertexO
529636
}
530637
}
531638

532-
DigitizationContext DigitizationContext::extractSingleTimeframe(int timeframeid, std::vector<int> const& sources_to_offset)
639+
DigitizationContext DigitizationContext::extractSingleTimeframe(int timeframeid, std::vector<std::tuple<int, int, int>> const& timeframeindices, std::vector<int> const& sources_to_offset)
533640
{
534641
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";
642+
if (timeframeindices.size() == 0) {
643+
LOG(error) << "Timeframe index structure empty; Returning empty object.";
537644
return r;
538645
}
539646
r.mSimPrefixes = mSimPrefixes;
540647
r.mMuBC = mMuBC;
541648
try {
542-
auto startend = mTimeFrameStartIndex.at(timeframeid);
649+
auto tf_ranges = timeframeindices.at(timeframeid);
543650

544-
auto startindex = startend.first;
545-
auto endindex = startend.second;
651+
auto startindex = std::get<0>(tf_ranges);
652+
auto endindex = std::get<1>(tf_ranges);
653+
auto earlyindex = std::get<2>(tf_ranges);
546654

655+
if (earlyindex >= 0) {
656+
startindex = earlyindex;
657+
}
547658
std::copy(mEventRecords.begin() + startindex, mEventRecords.begin() + endindex, std::back_inserter(r.mEventRecords));
548659
std::copy(mEventParts.begin() + startindex, mEventParts.begin() + endindex, std::back_inserter(r.mEventParts));
549660
if (mInteractionVertices.size() > endindex) {

0 commit comments

Comments
 (0)