28 std::cout <<
"Summary of DigitizationContext --\n";
29 std::cout <<
"Maximal parts per collision " << mMaxPartNumber <<
"\n";
30 std::cout <<
"Collision parts taken from simulations specified by prefix:\n";
31 for (
int p = 0; p < mSimPrefixes.size(); ++p) {
32 std::cout <<
"Part " << p <<
" : " << mSimPrefixes[p] <<
"\n";
34 std::cout <<
"QED information included " <<
isQEDProvided() <<
"\n";
36 std::cout <<
"Number of Collisions " << mEventRecords.size() <<
"\n";
37 std::cout <<
"Number of QED events " << mEventRecordsWithQED.size() - mEventRecords.size() <<
"\n";
39 for (
int i = 0;
i < mEventRecordsWithQED.size(); ++
i) {
40 if (truncateOutputTo >= 0 &&
i > truncateOutputTo) {
41 std::cout <<
"--- Output truncated to " << truncateOutputTo <<
" ---\n";
44 std::cout <<
"Record " <<
i <<
" TIME " << mEventRecordsWithQED[
i];
45 for (
auto& e : mEventPartsWithQED[
i]) {
46 std::cout <<
" (" << e.sourceID <<
" , " << e.entryID <<
")";
51 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";
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();
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();
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";
73 for (
int i = 0;
i < mEventRecords.size(); ++
i) {
74 if (truncateOutputTo >= 0 &&
i > truncateOutputTo) {
75 std::cout <<
"--- Output truncated to " << truncateOutputTo <<
" ---\n";
78 std::cout <<
"Collision " <<
i <<
" TIME " << mEventRecords[
i];
79 for (
auto& e : mEventParts[
i]) {
80 std::cout <<
" (" << e.sourceID <<
" , " << e.entryID <<
")";
82 if (
i < mInteractionVertices.size()) {
83 std::cout <<
" sampled vertex : " << mInteractionVertices[
i];
92 mSimPrefixes = prefixes;
97 if (!(simchains.size() == 0)) {
105 LOG(info) <<
"Not hit file present for " << detid.
getName() <<
" (exiting SimChain setup)";
110 simchains.emplace_back(
new TChain(
"o2sim"));
115 simchains.emplace_back(
new TChain(
"o2sim"));
121 if (mEventRecordsWithQED.size() > 0) {
122 if (mSimPrefixes.size() >= QEDSOURCEID) {
123 LOG(fatal) <<
"Too many signal chains; crashes with QED source ID";
127 simchains.resize(QEDSOURCEID + 1,
nullptr);
128 simchains[QEDSOURCEID] =
new TChain(
"o2sim");
140 if (!(simkinematicschains.size() == 0)) {
145 simkinematicschains.emplace_back(
new TChain(
"o2sim"));
150 simkinematicschains.emplace_back(
new TChain(
"o2sim"));
159 if (mMaxPartNumber == 1) {
164 return (
p2 -
p1).Mag2() < 1E-6;
167 std::vector<TChain*> kinematicschain;
168 std::vector<TBranch*> headerbranches;
169 std::vector<o2::dataformats::MCEventHeader*> headers;
170 std::vector<math_utils::Point3D<double>> vertices;
172 bool consistent =
true;
173 if (kinematicschain.size() > 0) {
174 headerbranches.resize(kinematicschain.size(),
nullptr);
175 headers.resize(kinematicschain.size(),
nullptr);
181 for (
auto& part : collision) {
182 const auto source = part.sourceID;
183 const auto entry = part.entryID;
185 if (!headerbranches[
source]) {
186 headerbranches[
source] =
chain->GetBranch(
"MCEventHeader.");
191 auto header = headers[
source];
192 vertices.emplace_back(header->GetX(), header->GetY(), header->GetZ());
195 bool thiscollision =
true;
196 const auto&
p1 = vertices[0];
197 for (
int j = 1;
j < vertices.size(); ++
j) {
198 const auto&
p2 = vertices[
j];
199 bool thischeck = checkVertexPair(
p1,
p2);
200 thiscollision &= thischeck;
202 if (verbose && !thiscollision) {
203 std::stringstream text;
204 text <<
"Found inconsistent vertices for digit collision ";
205 text << collisionID <<
" : ";
206 for (
auto& p : vertices) {
209 LOG(error) << text.str();
211 consistent &= thiscollision;
230 auto ensure_path_exists = [](std::string_view
filename) {
233 std::filesystem::path file_path(
filename);
234 std::filesystem::path dir_path = file_path.parent_path();
237 if (dir_path.empty()) {
243 if (!std::filesystem::exists(dir_path)) {
244 if (std::filesystem::create_directories(dir_path)) {
248 std::cerr <<
"Failed to create directories: " << dir_path.string() << std::endl;
253 }
catch (
const std::filesystem::filesystem_error& ex) {
254 std::cerr <<
"Filesystem error: " << ex.what() << std::endl;
256 }
catch (
const std::exception& ex) {
257 std::cerr <<
"General error: " << ex.what() << std::endl;
262 if (!ensure_path_exists(
filename)) {
263 LOG(error) <<
"Filename contains path component which could not be created";
269 auto cl = TClass::GetClass(
typeid(*
this));
270 file.WriteObjectAny(
this, cl,
"DigitizationContext");
273 LOG(error) <<
"Could not write to file " <<
filename.data();
286 file.GetObject(
"DigitizationContext", incontext);
292 if (mEventRecords.size() <= 1) {
303 auto first = mEventRecords.front();
304 auto last = mEventRecords.back();
307 LOG(info) <<
"QED RATE " << qedrate;
310 qedInteractionSampler.
init();
311 qedInteractionSampler.
print();
312 std::vector<o2::InteractionTimeRecord> qedinteractionrecords;
314 LOG(info) <<
"GENERATING COL TIMES";
317 qedinteractionrecords.push_back(t);
319 LOG(info) <<
"DONE GENERATING COL TIMES";
320 fillQED(QEDprefix, qedinteractionrecords, max_events,
false);
323void DigitizationContext::fillQED(std::string_view QEDprefix, std::vector<o2::InteractionTimeRecord>
const& irecord,
int max_events,
bool fromKinematics)
325 mQEDSimPrefix = QEDprefix;
327 std::vector<std::vector<o2::steer::EventPart>> qedEventParts;
329 int numberQEDevents = max_events;
330 if (fromKinematics) {
334 TFile
f(qedKinematicsName.c_str(),
"OPEN");
335 auto t = (TTree*)
f.Get(
"o2sim");
337 LOG(error) <<
"No QED kinematics found";
338 throw std::runtime_error(
"No QED kinematics found");
340 numberQEDevents = t->GetEntries();
344 for (
auto& tmp : irecord) {
345 std::vector<EventPart> qedpart;
346 qedpart.emplace_back(QEDSOURCEID, eventID++);
347 qedEventParts.push_back(qedpart);
348 if (eventID == numberQEDevents) {
356 auto combinedrecords = mEventRecords;
357 combinedrecords.insert(combinedrecords.end(), irecord.begin(), irecord.end());
358 auto combinedparts = mEventParts;
359 combinedparts.insert(combinedparts.end(), qedEventParts.begin(), qedEventParts.end());
362 std::vector<size_t> idx(combinedrecords.size());
363 std::iota(idx.begin(), idx.end(), 0);
365 std::stable_sort(idx.begin(), idx.end(),
366 [&combinedrecords](
size_t i1,
size_t i2) { return combinedrecords[i1] < combinedrecords[i2]; });
368 mEventRecordsWithQED.clear();
369 mEventPartsWithQED.clear();
370 for (
int i = 0;
i < idx.size(); ++
i) {
371 mEventRecordsWithQED.push_back(combinedrecords[idx[
i]]);
372 mEventPartsWithQED.push_back(combinedparts[idx[
i]]);
379std::vector<std::pair<int, int>> getTimeFrameBoundaries(std::vector<o2::InteractionTimeRecord>
const& irecords,
long startOrbit,
long orbitsPerTF)
381 std::vector<std::pair<int, int>>
result;
385 if (irecords.size() == 0) {
390 if (irecords.back().orbit < startOrbit) {
391 LOG(error) <<
"start orbit larger than last collision entry";
397 while (
left < irecords.size() && irecords[
left].orbit < startOrbit) {
403 int timeframe_count = 1;
404 while (
right < irecords.size()) {
405 if (irecords[
right].
orbit >= startOrbit + timeframe_count * orbitsPerTF) {
419std::vector<std::tuple<int, int, int>> getTimeFrameBoundaries(std::vector<o2::InteractionTimeRecord>
const& irecords,
425 auto true_indices = getTimeFrameBoundaries(irecords, startOrbit, orbitsPerTF);
427 std::vector<std::tuple<int, int, int>> indices_with_early{};
428 for (
int ti = 0; ti < true_indices.size(); ++ti) {
430 auto& tf_range = true_indices[ti];
433 indices_with_early.push_back(std::make_tuple(tf_range.first, tf_range.second, -1));
437 if (orbitsEarly > 0. && ti > 0) {
438 auto& prev_tf_range = true_indices[ti - 1];
442 int earlyOrbitIndex = prev_tf_range.second;
445 auto orbit_timeframe_start = startOrbit + ti * orbitsPerTF;
447 auto orbit_timeframe_early_fractional = orbit_timeframe_start - orbitsEarly;
448 auto orbit_timeframe_early_integral = (uint32_t)(orbit_timeframe_early_fractional);
458 auto differenceInBCNS_max = timeframe_start_record.differenceInBCNS(timeframe_early_record);
460 for (
int j = prev_tf_range.second;
j >= prev_tf_range.first; --
j) {
462 auto timediff_NS = timeframe_start_record.differenceInBCNS(irecords[
j]);
463 if (timediff_NS < differenceInBCNS_max) {
469 std::get<2>(indices_with_early.back()) = earlyOrbitIndex;
472 return indices_with_early;
482 std::vector<std::vector<o2::steer::EventPart>> newparts;
483 std::vector<o2::InteractionTimeRecord> newrecords;
485 std::unordered_map<int, int> currMaxId;
486 std::unordered_map<int, std::unordered_map<int, int>> reIndexMap;
489 maxColl = mEventRecords.size();
493 int first_timeframe = orbitsEarly > 0. ? 1 : 0;
496 std::unordered_map<size_t, size_t> indices_old_to_new;
499 for (
int tf_id = first_timeframe; tf_id < timeframeindices.size(); ++tf_id) {
500 auto& tf_indices = timeframeindices[tf_id];
502 auto firstindex = std::get<0>(tf_indices);
503 auto lastindex = std::get<1>(tf_indices);
504 auto previndex = std::get<2>(tf_indices);
506 LOG(info) <<
"timeframe indices " << previndex <<
" : " << firstindex <<
" : " << lastindex;
510 for (
int index = previndex >= 0 ? previndex : firstindex;
index <= lastindex; ++
index) {
511 if (collCount >= maxColl) {
517 if (indices_old_to_new.find(
index) != indices_old_to_new.end()) {
522 bool keep =
index < firstindex || collCount < maxColl;
528 if (
index >= firstindex) {
536 indices_old_to_new[
index] = newrecords.size();
537 newrecords.push_back(mEventRecords[
index]);
538 newparts.push_back(mEventParts[
index]);
541 for (
auto& part : newparts.back()) {
542 auto source = part.sourceID;
543 auto entry = part.entryID;
545 if (reIndexMap.find(
source) != reIndexMap.end() && reIndexMap[
source].find(
entry) != reIndexMap[
source].end()) {
549 if (currMaxId.find(
source) == currMaxId.end()) {
552 part.entryID = currMaxId[
source];
561 if (indices_old_to_new.find(firstindex) != indices_old_to_new.end()) {
562 std::get<0>(tf_indices) = indices_old_to_new[firstindex];
564 if (indices_old_to_new.find(lastindex) != indices_old_to_new.end()) {
565 std::get<1>(tf_indices) = indices_old_to_new[lastindex];
567 std::get<1>(tf_indices) = newrecords.size();
569 if (indices_old_to_new.find(previndex) != indices_old_to_new.end()) {
570 std::get<2>(tf_indices) = indices_old_to_new[previndex];
574 mEventRecords = newrecords;
575 mEventParts = newparts;
580 auto timeframeindices = getTimeFrameBoundaries(mEventRecords, startOrbit, orbitsPerTF, orbitsEarly);
581 LOG(info) <<
"Fixed " << timeframeindices.size() <<
" timeframes ";
582 for (
auto p : timeframeindices) {
583 LOG(info) << std::get<0>(p) <<
" " << std::get<1>(p) <<
" " << std::get<2>(p);
586 return timeframeindices;
593 std::unordered_map<int, int>
result;
595 for (
int collindex = 0; collindex < parts.size(); ++collindex) {
596 for (
auto& eventpart : parts[collindex]) {
597 if (eventpart.sourceID ==
source) {
598 result[eventpart.entryID] = collindex;
607 auto iter = std::find(mSimPrefixes.begin(), mSimPrefixes.end(), prefix);
608 if (iter != mSimPrefixes.end()) {
609 return std::distance(mSimPrefixes.begin(), iter);
617 template <
class T1,
class T2>
618 std::size_t operator()(
const std::pair<T1, T2>& pair)
const
620 return std::hash<T1>()(pair.first) ^ std::hash<T2>()(pair.second);
628 std::unordered_map<std::pair<int, int>,
int, pair_hash> vertex_cache;
630 mInteractionVertices.clear();
633 std::unordered_set<int> vset;
634 for (
auto& coll : mEventParts) {
639 for (
auto& part : coll) {
640 auto source = part.sourceID;
641 auto event = part.entryID;
642 auto cached_iter = vertex_cache.find(std::pair<int, int>(
source,
event));
644 if (cached_iter != vertex_cache.end()) {
645 vset.emplace(cached_iter->second);
650 if (vset.size() > 1) {
651 LOG(fatal) <<
"Impossible conflict during interaction vertex sampling";
655 if (vset.size() == 1) {
657 cacheindex = *(vset.begin());
658 mInteractionVertices.push_back(mInteractionVertices[cacheindex]);
661 mInteractionVertices.emplace_back(meanv.
sample());
662 cacheindex = mInteractionVertices.size() - 1;
665 for (
auto& part : coll) {
666 auto source = part.sourceID;
667 auto event = part.entryID;
668 vertex_cache[std::pair<int, int>(
source,
event)] = cacheindex;
676 if (timeframeindices.size() == 0) {
677 LOG(error) <<
"Timeframe index structure empty; Returning empty object.";
680 r.mSimPrefixes = mSimPrefixes;
683 auto tf_ranges = timeframeindices.at(timeframeid);
685 auto startindex = std::get<0>(tf_ranges);
686 auto endindex = std::get<1>(tf_ranges);
687 auto earlyindex = std::get<2>(tf_ranges);
689 if (earlyindex >= 0) {
690 startindex = earlyindex;
692 std::copy(mEventRecords.begin() + startindex, mEventRecords.begin() + endindex, std::back_inserter(
r.mEventRecords));
693 std::copy(mEventParts.begin() + startindex, mEventParts.begin() + endindex, std::back_inserter(
r.mEventParts));
694 if (mInteractionVertices.size() > endindex) {
695 std::copy(mInteractionVertices.begin() + startindex, mInteractionVertices.begin() + endindex, std::back_inserter(
r.mInteractionVertices));
701 auto perform_offsetting = [&
r](
int source_id) {
702 auto indices_for_source =
r.getCollisionIndicesForSource(source_id);
703 int minvalue = std::numeric_limits<int>::max();
704 for (
auto& p : indices_for_source) {
705 if (p.first < minvalue) {
710 for (
auto& p : indices_for_source) {
711 auto index_into_mEventParts = p.second;
712 for (
auto& part :
r.mEventParts[index_into_mEventParts]) {
713 if (part.sourceID == source_id) {
714 part.entryID -= minvalue;
719 for (
auto source_id : sources_to_offset) {
720 perform_offsetting(source_id);
723 }
catch (std::exception) {
724 LOG(warn) <<
"No such timeframe id in collision context. Returing empty object";
727 r.setNCollisions(
r.mEventRecords.size());
Definition of the Names Generator class.
constexpr int p1()
constexpr to accelerate the coordinates changing
static std::string getHitsFileName(DId d, const std::string_view prefix=STANDARDSIMPREFIX)
static std::string getMCKinematicsFileName(const std::string_view prefix=STANDARDSIMPREFIX)
static std::string getCollisionContextFileName(const std::string_view prefix="")
Static class with identifiers, bitmasks and names for ALICE detectors.
static constexpr const char * getName(ID id)
names of defined detectors
static GRPObject * loadFrom(const std::string &grpFileName="")
DigitizationContext extractSingleTimeframe(int timeframeid, std::vector< std::tuple< int, int, int > > const &timeframeindices, std::vector< int > const &sources_to_offset)
bool checkVertexCompatibility(bool verbose=false) const
Check collision parts for vertex consistency.
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
bool initSimChains(o2::detectors::DetID detid, std::vector< TChain * > &simchains) const
std::unordered_map< int, int > getCollisionIndicesForSource(int source) const
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)
bool initSimKinematicsChains(std::vector< TChain * > &simkinematicschains) const
o2::parameters::GRPObject const & getGRP() const
returns the GRP object associated to this context
bool isQEDProvided() const
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
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
static DigitizationContext * loadFromFile(std::string_view filename="")
void setFirstIR(const o2::InteractionRecord &ir)
const o2::InteractionTimeRecord & generateCollisionTime()
void setBunchFilling(const BunchFilling &bc)
void setInteractionRate(float rateHz)
GLsizei GLsizei GLchar * source
constexpr int LHCMaxBunches
std::vector< o2::ctf::BufferType > vec
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"