120 class TMessageWrapper :
public TMessage
124 ~TMessageWrapper()
override =
default;
132 mInitialOutputDir = std::filesystem::current_path().string();
133 mCurrentOutputDir = mInitialOutputDir;
139 FairSystemInfo sysinfo;
140 LOG(info) <<
"TIME-STAMP " << mTimer.RealTime() <<
"\t";
142 LOG(info) <<
"MEM-STAMP " << sysinfo.GetCurrentMemory() / (1024. * 1024) <<
" "
143 << sysinfo.GetMaxMemory() <<
" MB\n";
148 void InitTask() final
150 LOG(info) <<
"INIT HIT MERGER";
151 ROOT::EnableThreadSafety();
153 std::string outfilename(
"o2sim_merged_hits.root");
160 LOG(fatal) <<
"No configuration received. Aborting";
166 mOutFileName = outfilename.c_str();
168 mOutFile =
new TFile(outfilename.c_str(),
"RECREATE");
169 mOutTree =
new TTree(
"o2sim",
"o2sim");
170 mOutTree->SetDirectory(mOutFile);
173 mMCHeaderTree =
new TTree(
"o2sim",
"o2sim");
174 mMCHeaderTree->SetDirectory(mMCHeaderOnlyOutFile);
177 if (mDetectorInstances.size() == 0) {
185 auto pipeenv = getenv(
"ALICE_O2SIMMERGERTODRIVER_PIPE");
187 mPipeToDriver = atoi(pipeenv);
188 LOG(info) <<
"ASSIGNED PIPE HANDLE " << mPipeToDriver;
190 LOG(warning) <<
"DID NOT FIND ENVIRONMENT VARIABLE TO INIT PIPE";
194 if (mNExpectedEvents == 0) {
196 waitForControlInput();
198 LOG(info) <<
"NOT EXPECTING ANY DATA; SHUTTING DOWN";
204 bool setWorkingDirectory(std::string
const& dir)
206 namespace fs = std::filesystem;
216 fs::current_path(fs::path(mInitialOutputDir));
218 auto absolutePath = fs::absolute(fs::path(dir));
219 if (!fs::exists(absolutePath)) {
220 if (!fs::create_directory(absolutePath)) {
221 LOG(error) <<
"Could not create directory " << absolutePath.string();
226 fs::current_path(absolutePath.string().c_str());
227 mCurrentOutputDir = fs::current_path().string();
229 LOG(info) <<
"FINAL PATH " << mCurrentOutputDir;
230 }
catch (std::exception e) {
231 LOG(error) <<
" could not change path to " << dir;
242 if (!setWorkingDirectory(reconfig.
outputDir)) {
246 std::string outfilename(
"o2sim_merged_hits.root");
248 mNExpectedEvents = reconfig.
nEvents;
249 mOutFileName = outfilename.c_str();
251 mOutFile =
new TFile(outfilename.c_str(),
"RECREATE");
252 mOutTree =
new TTree(
"o2sim",
"o2sim");
253 mOutTree->SetDirectory(mOutFile);
256 mMCHeaderTree =
new TTree(
"o2sim",
"o2sim");
257 mMCHeaderTree->SetDirectory(mMCHeaderOnlyOutFile);
263 mPartsCheckSum.clear();
267 mMCTrackBuffer.clear();
268 mTrackRefBuffer.clear();
269 mSubEventInfoBuffer.clear();
270 mFlushableEvents.clear();
276 template <
typename T,
typename V>
277 V insertAdd(std::map<T, V>&
m, T
const&
key, V
value)
279 const auto iter =
m.find(
key);
281 if (iter !=
m.end()) {
282 iter->second +=
value;
283 accum = iter->second;
291 template <
typename T>
292 bool isDataComplete(T checksum, T nparts)
294 return checksum == nparts * (nparts + 1) / 2;
297 void consumeHits(
int eventID, fair::mq::Parts&
data,
int&
index)
299 auto detIDmessage = std::move(
data.At(
index++));
301 if (detIDmessage->GetSize() == 4) {
302 auto ptr = (
int*)detIDmessage->GetData();
304 LOG(debug2) <<
"I1 " <<
ptr[0] <<
" NAME " <<
id.getName() <<
" MB "
305 <<
data.At(
index)->GetSize() / 1024. / 1024.;
308 auto detector = mDetectorInstances[
id].get();
310 detector->collectHits(eventID,
data,
index);
315 template <
typename T,
typename BT>
316 void consumeData(
int eventID, fair::mq::Parts&
data,
int&
index, BT&
buffer)
318 auto decodeddata = o2::base::decodeTMessage<T*>(
data,
index);
320 buffer[eventID] =
typename BT::mapped_type();
322 buffer[eventID].push_back(decodeddata);
332 if (mSubEventInfoBuffer.find(
info.eventID) == mSubEventInfoBuffer.end()) {
333 mSubEventInfoBuffer[
info.eventID] = std::list<o2::data::SubEventInfo*>();
335 mSubEventInfoBuffer[
info.eventID].push_back(&info);
342 auto factory = fair::mq::TransportFactory::CreateTransportFactory(
"zeromq");
343 auto channel = fair::mq::Channel{
"o2sim-control",
"sub", factory};
344 auto controlsocketname = getenv(
"ALICE_O2SIMCONTROL");
345 LOG(info) <<
"SOCKETNAME " << controlsocketname;
346 channel.Connect(std::string(controlsocketname));
348 std::unique_ptr<fair::mq::Message> reply(channel.NewMessage());
350 LOG(info) <<
"WAITING FOR INPUT";
351 if (channel.Receive(reply) > 0) {
352 auto data = reply->GetData();
353 auto size = reply->GetSize();
355 std::string command(
reinterpret_cast<char const*
>(
data),
size);
356 LOG(info) <<
"message: " << command;
360 return ReInit(reconfig);
362 LOG(info) <<
"NOTHING RECEIVED";
367 bool ConditionalRun()
override
369 auto& channel = GetChannels().at(
"simdata").at(0);
370 fair::mq::Parts request;
371 auto bytes = channel.Receive(request);
373 LOG(error) <<
"Some error occurred on socket during receive on sim data";
378 auto more = handleSimData(request, 0);
379 LOG(info) <<
"HitMerger processing took " << timer.RealTime();
380 if (!more && mAsService) {
381 LOG(info) <<
" CONTROL ";
387 static bool initAcknowledged =
false;
388 if (!initAcknowledged) {
390 initAcknowledged =
true;
396 bool handleSimData(fair::mq::Parts&
data,
int )
398 bool expectmore =
true;
400 auto infoptr = o2::base::decodeTMessage<o2::data::SubEventInfo*>(
data,
index++);
402 auto accum = insertAdd<uint32_t, uint32_t>(mPartsCheckSum,
info.eventID, (uint32_t)
info.part);
404 LOG(info) <<
"SIMDATA channel got " <<
data.Size() <<
" parts for event " <<
info.eventID <<
" part " <<
info.part <<
" out of " <<
info.nparts;
406 fillSubEventInfoEntry(info);
407 consumeData<std::vector<o2::MCTrack>>(
info.eventID,
data,
index, mMCTrackBuffer);
408 consumeData<std::vector<o2::TrackReference>>(
info.eventID,
data,
index, mTrackRefBuffer);
413 if (isDataComplete<uint32_t>(accum,
info.nparts)) {
414 LOG(info) <<
"Event " <<
info.eventID <<
" complete. Marking as flushable";
415 mFlushableEvents[
info.eventID] =
true;
421 if (!mergingInProgress) {
422 if (mMergerIOThread.joinable()) {
423 mMergerIOThread.join();
426 mMergerIOThread = std::thread([info,
this]() { mergingInProgress =
true; mergeAndFlushData(); mergingInProgress =
false; });
429 mEventChecksum +=
info.eventID;
431 if (isDataComplete<uint32_t>(mEventChecksum,
info.maxEvents)) {
432 LOG(info) <<
"ALL EVENTS HERE; CHECKSUM " << mEventChecksum;
435 if (mMergerIOThread.joinable()) {
436 mMergerIOThread.join();
438 mMergerIOThread = std::thread([info,
this]() { mergingInProgress =
true; mergeAndFlushData(); mergingInProgress =
false; });
439 if (mMergerIOThread.joinable()) {
440 mMergerIOThread.join();
446 if (mPipeToDriver != -1) {
447 if (write(mPipeToDriver, &
info.eventID,
sizeof(
info.eventID)) == -1) {
448 LOG(error) <<
"FAILED WRITING TO PIPE";
455 void cleanEvent(
int eventID)
460 template <
typename T>
461 void backInsert(T
const& from, T& to)
463 std::copy(from.begin(), from.end(), std::back_inserter(to));
466 void reorderAndMergeMCTracks(
int eventID, TTree*
target,
const std::vector<int>& nprimaries,
const std::vector<int>& nsubevents, std::function<
void(std::vector<MCTrack>
const&)> tracks_analysis_hook,
o2::dataformats::MCEventHeader const* mceventheader)
469 std::vector<MCTrack>* mcTracksPerSubEvent =
nullptr;
470 auto targetdata = std::make_unique<std::vector<MCTrack>>();
472 auto& vectorOfSubEventMCTracks = mMCTrackBuffer[eventID];
473 const auto entries = vectorOfSubEventMCTracks.size();
482 nprimTot += nprimaries[
index];
484 for (
int i = 0;
i < nprimaries[
index];
i++) {
485 auto&
track = (*vectorOfSubEventMCTracks[
index])[
i];
486 if (
track.isTransported()) {
487 track.SetFirstDaughterTrackId(-1);
488 track.SetLastDaughterTrackId(-1);
490 targetdata->push_back(track);
496 Int_t idelta1 = nprimTot;
501 auto& subEventTracks = *(vectorOfSubEventMCTracks[
index]);
503 Int_t npart = (
int)(subEventTracks.size());
504 Int_t nprim = nprimaries[
index];
507 for (Int_t
i = nprim;
i < npart;
i++) {
508 auto&
track = subEventTracks[
i];
509 Int_t cId =
track.getMotherTrackId();
515 track.SetMotherTrackId(cId);
516 track.SetFirstDaughterTrackId(-1);
518 Int_t hwm = (
int)(targetdata->size());
519 auto& mother = (*targetdata)[cId];
520 if (mother.getFirstDaughterTrackId() == -1) {
521 mother.SetFirstDaughterTrackId(hwm);
523 mother.SetLastDaughterTrackId(hwm);
525 targetdata->push_back(track);
533 auto filladdr = (entries > 1) ? targetdata.get() : vectorOfSubEventMCTracks[0];
537 tracks_analysis_hook(*filladdr);
539 if (mWriteToDisc &&
target) {
541 targetbr->SetAddress(&filladdr);
543 targetbr->ResetAddress();
547 auto free_tmessage = [](
void*
data,
void* hint) {
delete static_cast<TMessage*
>(hint); };
548 auto& channel = GetChannels().at(
"kineforward").at(0);
550 tmsg->WriteObjectAny((
void*)filladdr, TClass::GetClass(
"std::vector<o2::MCTrack>"));
551 std::unique_ptr<fair::mq::Message> trackmessage(channel.NewMessage(tmsg->Buffer(), tmsg->BufferSize(), free_tmessage, tmsg));
553 tmsg->WriteObjectAny((
void*)mceventheader, TClass::GetClass(
"o2::dataformats::MCEventHeader"));
554 std::unique_ptr<fair::mq::Message> headermessage(channel.NewMessage(tmsg->Buffer(), tmsg->BufferSize(), free_tmessage, tmsg));
555 fair::mq::Parts reply;
556 reply.AddPart(std::move(headermessage));
557 reply.AddPart(std::move(trackmessage));
559 LOG(info) <<
"Forward publish MC tracks on channel";
563 for (
auto ptr : vectorOfSubEventMCTracks) {
568 template <
typename T,
typename M>
569 void remapTrackIdsAndMerge(std::string brname,
int eventID, TTree&
target,
570 const std::vector<int>& trackoffsets,
const std::vector<int>& nprimaries,
const std::vector<int>& subevOrdered, M& mapOfVectorOfTs)
577 T* incomingdata =
nullptr;
578 std::unique_ptr<T> targetdata(
nullptr);
579 auto& vectorOfT = mapOfVectorOfTs[eventID];
580 const auto entries = vectorOfT.size();
584 incomingdata = vectorOfT[0];
586 targetdata = std::make_unique<T>();
590 nprimTot += nprimaries[
entry];
593 Int_t idelta1 = nprimTot;
596 Int_t nprim = nprimaries[
index];
597 incomingdata = vectorOfT[
index];
599 for (
auto&
data : *incomingdata) {
600 updateTrackIdWithOffset(
data, nprim, idelta0, idelta1);
601 targetdata->push_back(
data);
604 idelta1 += trackoffsets[
index];
607 auto dataaddr = (entries == 1) ? incomingdata : targetdata.
get();
609 targetbr->SetAddress(&dataaddr);
611 targetbr->ResetAddress();
614 for (
auto ptr : vectorOfT) {
619 void updateTrackIdWithOffset(
MCTrack& track, Int_t nprim, Int_t idelta0, Int_t idelta1)
621 Int_t cId =
track.getMotherTrackId();
622 Int_t ioffset = (cId < nprim) ? idelta0 : idelta1;
624 track.SetMotherTrackId(cId + ioffset);
628 void updateTrackIdWithOffset(TrackReference&
ref, Int_t nprim, Int_t idelta0, Int_t idelta1)
630 Int_t cId =
ref.getTrackID();
631 Int_t ioffset = (cId < nprim) ? idelta0 : idelta1;
632 ref.setTrackID(cId + ioffset);
635 void initHitTreeAndOutFile(std::string prefix,
int detID)
638 if (mDetectorOutFiles.find(detID) != mDetectorOutFiles.end() && mDetectorOutFiles[detID]) {
639 LOG(warn) <<
"Hit outfile for detID " <<
DetID::getName(detID) <<
" already initialized --> Reopening";
640 mDetectorOutFiles[detID]->Close();
641 delete mDetectorOutFiles[detID];
645 mDetectorOutFiles[detID] =
new TFile(
name.c_str(),
"RECREATE");
646 mDetectorToTTreeMap[detID] =
new TTree(
"o2sim",
"o2sim");
647 mDetectorToTTreeMap[detID]->SetDirectory(mDetectorOutFiles[detID]);
649 mDetectorOutFiles[detID] =
nullptr;
650 mDetectorToTTreeMap[detID] =
nullptr;
657 bool mergeAndFlushData()
659 auto checkIfNextFlushable = [
this]() ->
bool {
661 return mFlushableEvents.find(mNextFlushID) != mFlushableEvents.end() && mFlushableEvents[mNextFlushID] ==
true;
664 LOG(info) <<
"Launching merge kernel ";
665 bool canflush = mFlushableEvents.find(mNextFlushID) != mFlushableEvents.end() && mFlushableEvents[mNextFlushID] ==
true;
669 while (canflush ==
true) {
670 auto flusheventID = mNextFlushID;
671 LOG(info) <<
"Merge and flush event " << flusheventID;
672 auto iter = mSubEventInfoBuffer.find(flusheventID);
673 if (iter == mSubEventInfoBuffer.end()) {
674 LOG(error) <<
"No info/data found for event " << flusheventID;
675 if (!checkIfNextFlushable()) {
680 auto& subEventInfoList = (*iter).second;
681 if (subEventInfoList.size() == 0 || mNExpectedEvents == 0) {
682 LOG(error) <<
"No data entries found for event " << flusheventID;
683 if (!checkIfNextFlushable()) {
695 std::vector<int> trackoffsets;
697 std::vector<int> nprimaries;
699 std::vector<int> nsubevents;
704 for (
auto info : subEventInfoList) {
705 assert(
info->npersistenttracks >= 0);
706 trackoffsets.emplace_back(
info->npersistenttracks);
707 nprimaries.emplace_back(
info->nprimarytracks);
708 nsubevents.emplace_back(
info->part);
709 if (eventheader ==
nullptr) {
710 eventheader = &
info->mMCEventHeader;
717 if (confref.isFilterOutNoHitEvents()) {
719 LOG(info) <<
" Taking out event " << flusheventID <<
" due to no hits ";
720 cleanEvent(flusheventID);
721 if (!checkIfNextFlushable()) {
733 const auto entries = subEventInfoList.size();
734 std::vector<int> subevOrdered((
int)(nsubevents.size()));
737 printf(
"HitMerger entry: %d nprimry: %5d trackoffset: %5d \n",
entry, nprimaries[
entry], trackoffsets[
entry]);
746 auto mcheaderhook = [eventheader](std::vector<MCTrack>
const&
tracks) {
747 int eta1Point2Counter = 0;
748 int eta1Point0Counter = 0;
749 int eta0Point8Counter = 0;
750 int eta1Point2CounterPi = 0;
751 int eta1Point0CounterPi = 0;
752 int eta0Point8CounterPi = 0;
755 if (tr.isPrimary()) {
757 const auto eta = tr.GetEta();
760 if (std::abs(tr.GetPdgCode()) == 211) {
761 eta1Point2CounterPi++;
766 if (std::abs(tr.GetPdgCode()) == 211) {
767 eta1Point0CounterPi++;
772 if (std::abs(tr.GetPdgCode()) == 211) {
773 eta0Point8CounterPi++;
782 eventheader->
putInfo(
"prims_eta_1.2", eta1Point2Counter);
783 eventheader->
putInfo(
"prims_eta_1.0", eta1Point0Counter);
784 eventheader->
putInfo(
"prims_eta_0.8", eta0Point8Counter);
785 eventheader->
putInfo(
"prims_eta_1.2_pi", eta1Point2CounterPi);
786 eventheader->
putInfo(
"prims_eta_1.0_pi", eta1Point0CounterPi);
787 eventheader->
putInfo(
"prims_eta_0.8_pi", eta0Point8CounterPi);
788 eventheader->
putInfo(
"prims_total", prims);
790 reorderAndMergeMCTracks(flusheventID, mOutTree, nprimaries, subevOrdered, mcheaderhook, eventheader);
794 remapTrackIdsAndMerge<std::vector<o2::TrackReference>>(
"TrackRefs", flusheventID, *mOutTree, trackoffsets, nprimaries, subevOrdered, mTrackRefBuffer);
799 headerbr->SetAddress(&eventheader);
801 headerbr->ResetAddress();
806 headerbr->SetAddress(&eventheader);
808 headerbr->ResetAddress();
815 for (
int id = 0;
id < mDetectorInstances.size(); ++
id) {
816 auto& det = mDetectorInstances[
id];
818 auto hittree = mDetectorToTTreeMap[
id];
820 det->mergeHitEntriesAndFlush(flusheventID, *hittree, trackoffsets, nprimaries, subevOrdered);
821 hittree->SetEntries(hittree->GetEntries() + 1);
822 LOG(info) <<
"flushing tree to file " << hittree->GetDirectory()->GetFile()->GetName();
829 mOutTree->SetEntries(mOutTree->GetEntries() + 1);
830 LOG(info) <<
"outtree has file " << mOutTree->GetDirectory()->GetFile()->GetName();
833 mMCHeaderTree->SetEntries(mMCHeaderTree->GetEntries() + 1);
834 LOG(info) <<
"mc header outtree has file " << mMCHeaderTree->GetDirectory()->GetFile()->GetName();
837 cleanEvent(flusheventID);
838 LOG(info) <<
"Merge/flush for event " << flusheventID <<
" took " << timer.RealTime();
839 if (!checkIfNextFlushable()) {
843 if (mWriteToDisc && mOutFile) {
844 LOG(info) <<
"Writing TTrees";
845 mOutFile->Write(
"", TObject::kOverwrite);
846 for (
int id = 0;
id < mDetectorInstances.size(); ++
id) {
847 auto& det = mDetectorInstances[
id];
848 if (det && mDetectorOutFiles[
id]) {
849 mDetectorOutFiles[
id]->Write(
"", TObject::kOverwrite);
852 if (mMCHeaderOnlyOutFile) {
853 mMCHeaderOnlyOutFile->Write(
"", TObject::kOverwrite);
859 std::map<uint32_t, uint32_t> mPartsCheckSum;
860 std::string mOutFileName;
865 TFile* mMCHeaderOnlyOutFile;
866 TTree* mMCHeaderTree;
868 template <
class K,
class V>
869 using Hashtable = tbb::concurrent_unordered_map<K, V>;
870 Hashtable<int, TFile*> mDetectorOutFiles;
871 Hashtable<int, TTree*> mDetectorToTTreeMap;
874 std::thread mMergerIOThread;
875 bool mergingInProgress =
false;
877 Hashtable<int, std::vector<std::vector<o2::MCTrack>*>> mMCTrackBuffer;
878 Hashtable<int, std::vector<std::vector<o2::TrackReference>*>> mTrackRefBuffer;
879 Hashtable<int, std::list<o2::data::SubEventInfo*>> mSubEventInfoBuffer;
880 Hashtable<int, bool> mFlushableEvents;
882 int mEventChecksum = 0;
883 int mNExpectedEvents = 0;
884 int mNextFlushID = 1;
887 bool mAsService =
false;
888 bool mForwardKine =
true;
889 bool mWriteToDisc =
true;
891 int mPipeToDriver = -1;
893 std::vector<std::unique_ptr<o2::base::Detector>> mDetectorInstances;
894 std::vector<int> mExternalDetIDs;
897 std::string mInitialOutputDir;
898 std::string mCurrentOutputDir;
901 fair::mq::Channel mPubChannel;
904 void initDetInstances();
905 void initExternalDetInstances();
906 void initHitFiles(std::string prefix);