diff --git a/MQ/mcbm/CbmDeviceEventBuilder.cxx b/MQ/mcbm/CbmDeviceEventBuilder.cxx index 0ab84e439a2f4824015e46f369e2b36dc4da508d..3a2eef200f6c571f71d2eacedcae5b557290120b 100644 --- a/MQ/mcbm/CbmDeviceEventBuilder.cxx +++ b/MQ/mcbm/CbmDeviceEventBuilder.cxx @@ -23,6 +23,8 @@ #include "FairMQLogger.h" #include "FairMQProgOptions.h" // device->fConfig #include "FairParGenericSet.h" +#include "FairRootFileSink.h" +#include "FairRootManager.h" #include "FairRunOnline.h" #include "BoostSerializer.h" @@ -59,6 +61,8 @@ try { //fbFillHistos = fConfig->GetValue<bool>("FillHistos"); //fbIgnoreTsOverlap = fConfig->GetValue<bool>("IgnOverMs"); + fsOutputFileName = fConfig->GetValue<std::string>("OutFileName"); //For storage of events + // Event builder algorithm params const std::vector<std::string> vsAddDet = fConfig->GetValue<std::vector<std::string>>("AddDet"); const std::vector<std::string> vsSetEvbuildWin = fConfig->GetValue<std::vector<std::string>>("SetEvbuildWin"); @@ -78,6 +82,31 @@ try { fdMinPublishTime = fConfig->GetValue<double_t>("PubTimeMin"); fdMaxPublishTime = fConfig->GetValue<double_t>("PubTimeMax"); + /// Prepare root output + if ("" != fsOutputFileName) { + fpRun = new FairRunOnline(); // is this needed? + fpFairRootMgr = FairRootManager::Instance(); + fpFairRootMgr->SetSink(new FairRootFileSink(fsOutputFileName)); + if (nullptr == fpFairRootMgr->GetOutFile()) { + throw InitTaskError("Could not open root file"); + } // if( nullptr == fpFairRootMgr->GetOutFile() ) + } // if( "" != fsOutputFileName ) + else { + throw InitTaskError("Empty output filename!"); + } // else of if( "" != fsOutputFileName ) + + LOG(info) << "Init Root Output to " << fsOutputFileName; + fpFairRootMgr->InitSink(); + + /// Create input vectors + fCbmTsEventHeader = new CbmTsEventHeader(); + fpFairRootMgr->Register("EventHeader.", "Event", fCbmTsEventHeader, kTRUE); + + /// Create storage vector for events + fEventsSel = new std::vector<CbmDigiEvent>(); + fpFairRootMgr->RegisterAny("DigiEvent", fEventsSel, kTRUE); + fpFairRootMgr->WriteFolder(); + // Get the information about created channels from the device // Check if the defined channels from the topology (by name) // are in the list of channels which are possible/allowed @@ -157,9 +186,6 @@ try { fEvbuildAlgo.SetTriggerWindow(selDet, dWinBeg, dWinEnd); } - - /// Create input vectors - fCbmTsEventHeader = new CbmTsEventHeader(); } catch (InitTaskError& e) { LOG(error) << e.what(); @@ -202,13 +228,12 @@ bool CbmDeviceEventBuilder::IsChannelNameAllowed(std::string channelName) return false; } - // handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0) bool CbmDeviceEventBuilder::HandleData(FairMQParts& parts, int /*index*/) { fulNumMessages++; - LOG(debug) << "Received message number " << fulNumMessages << " with " << parts.Size() << " parts" - << ", size0: " << parts.At(0)->GetSize(); + LOG(info) << "Received message number " << fulNumMessages << " with " << parts.Size() << " parts" + << ", size0: " << parts.At(0)->GetSize(); if (0 == fulNumMessages % 10000) LOG(info) << "Received " << fulNumMessages << " messages"; @@ -216,7 +241,8 @@ bool CbmDeviceEventBuilder::HandleData(FairMQParts& parts, int /*index*/) uint32_t uPartIdx = 0; /// TS header - Deserialize<RootSerializer>(*parts.At(uPartIdx), fCbmTsEventHeader); + CbmTsEventHeader* evtHeader = new CbmTsEventHeader(); + Deserialize<RootSerializer>(*parts.At(uPartIdx), evtHeader); ++uPartIdx; CbmDigiTimeslice ts; @@ -279,16 +305,42 @@ bool CbmDeviceEventBuilder::HandleData(FairMQParts& parts, int /*index*/) LOG(debug) << "PSD Vector size: " << ts.fData.fPsd.fDigis.size(); const std::vector<double> triggers = GetTriggerTimes(ts); + LOG(debug) << "triggers: " << triggers.size(); /// Create events std::vector<CbmDigiEvent> vEvents = fEvbuildAlgo(ts, triggers); + LOG(debug) << "vEvents size: " << vEvents.size(); /// Send events vector to ouput - if (!SendEvents(parts, vEvents)) return false; + if (!SendEvents(parts, vEvents)) { return false; } + + /// Write events to file + (*fEventsSel) = std::move(vEvents); + LOG(debug) << "fEventSel size: " << fEventsSel->size(); + + // FIXME: poor man solution with lots of data copy until we undertand how to properly deal + /// with FairMq messages ownership and memory managment + (*fCbmTsEventHeader) = std::move(*evtHeader); + + DumpTreeEntry(); return true; } +void CbmDeviceEventBuilder::DumpTreeEntry() +{ + // Unpacked digis + CbmEvent output to root file + + /// FairRunOnline style + fpFairRootMgr->StoreWriteoutBufferData(fpFairRootMgr->GetEventTime()); + fpFairRootMgr->FillEventHeader(fCbmTsEventHeader); + fpFairRootMgr->Fill(); + fpFairRootMgr->DeleteOldWriteoutBufferData(); + + /// Clear event vector + fEventsSel->clear(); +} + std::vector<double> CbmDeviceEventBuilder::GetTriggerTimes(const CbmDigiTimeslice& ts) { std::vector<double> vDigiTimes; @@ -336,9 +388,7 @@ bool CbmDeviceEventBuilder::SendEvents(FairMQParts& partsIn, const std::vector<C oaEvt << vEvents; std::string* strMsgEvt = new std::string(ossEvt.str()); - FairMQParts partsOut(std::move(partsIn)); - - partsOut.AddPart(NewMessage( + FairMQParts partsOut(NewMessage( const_cast<char*>(strMsgEvt->c_str()), // data strMsgEvt->length(), // size [](void*, void* object) { delete static_cast<std::string*>(object); }, @@ -351,8 +401,26 @@ bool CbmDeviceEventBuilder::SendEvents(FairMQParts& partsIn, const std::vector<C return true; } +void CbmDeviceEventBuilder::Finish() +{ + // Clean closure of output to root file + fpFairRootMgr->Write(); + fpFairRootMgr->CloseSink(); + fbFinishDone = kTRUE; +} + CbmDeviceEventBuilder::~CbmDeviceEventBuilder() { + /// Close things properly if not alredy done + if (!fbFinishDone) Finish(); + + /// Clear events vector + if (fEventsSel) { + fEventsSel->clear(); + delete fEventsSel; + } + if (fpRun) { delete fpRun; } + /// Clear metadata delete fCbmTsEventHeader; } diff --git a/MQ/mcbm/CbmDeviceEventBuilder.h b/MQ/mcbm/CbmDeviceEventBuilder.h index 2f4328ec4fdf2b2d4b2fdff0179270a8e8321b0c..d1dc5241f54912a5928ccf6170ac752d248748eb 100644 --- a/MQ/mcbm/CbmDeviceEventBuilder.h +++ b/MQ/mcbm/CbmDeviceEventBuilder.h @@ -30,6 +30,9 @@ class CbmTsEventHeader; +class FairRunOnline; +class FairRootManager; + class CbmDeviceEventBuilder : public FairMQDevice { public: CbmDeviceEventBuilder(); @@ -41,6 +44,8 @@ protected: bool HandleCommand(FairMQMessagePtr&, int); private: + Bool_t fbFinishDone = false; //! Keep track of whether the Finish was already called + /// Constants /// Control flags @@ -50,6 +55,8 @@ private: /// User settings parameters /// Algo enum settings ECbmModuleId fTriggerDet = ECbmModuleId::kT0; + + std::string fsOutputFileName = ""; /// message queues std::string fsChannelNameDataInput = "unpts_0"; std::string fsChannelNameDataOutput = "events"; @@ -89,6 +96,13 @@ private: /// TS information in header CbmTsEventHeader* fCbmTsEventHeader = nullptr; + /// Data storage + FairRunOnline* fpRun = nullptr; + FairRootManager* fpFairRootMgr = nullptr; + + /// CbmEvents + std::vector<CbmDigiEvent>* fEventsSel = nullptr; //! output container of CbmEvents + bool IsChannelNameAllowed(std::string channelName); bool SendEvents(FairMQParts& partsIn, const std::vector<CbmDigiEvent>& vEvents); @@ -107,7 +121,8 @@ private: // Get detector type from string containing name ECbmModuleId GetDetectorId(std::string detName); - void Finish() {}; + void DumpTreeEntry(); + void Finish(); }; #endif /* CBMDEVICEEVENTBUILDER_H_ */ diff --git a/MQ/mcbm/runEventBuilder.cxx b/MQ/mcbm/runEventBuilder.cxx index 9b5226374c143cb34e5dd4247ed5c5cf35638bde..0323efc9d8d675ffabf7848b0699b9e4fb56f93d 100644 --- a/MQ/mcbm/runEventBuilder.cxx +++ b/MQ/mcbm/runEventBuilder.cxx @@ -21,6 +21,8 @@ void addCustomOptions(bpo::options_description& options) options.add_options()("FillHistos", bpo::value<bool>()->default_value(true), "Fill histograms and send them to histo server if true"); options.add_options()("IgnTsOver", bpo::value<bool>()->default_value(false), "Ignore TS overlap if true"); + options.add_options()("OutFileName", bpo::value<std::string>()->default_value("events.root"), + "Name (full or relative path) of the output .root file "); options.add_options()("TriggerDet", bpo::value<std::string>()->default_value("kT0"), "Set the trigger detector, use string matching an ECbmModuleId "); options.add_options()("AddDet", bpo::value<std::vector<std::string>>()->multitoken()->composing(), diff --git a/MQ/mcbm/startEventBuilder.sh.in b/MQ/mcbm/startEventBuilder.sh.in index d2c3936d39e88ac64235e4ee0d0954046377a38b..ea2028d8f9b2233da4de63d168dc493ca23eb974 100755 --- a/MQ/mcbm/startEventBuilder.sh.in +++ b/MQ/mcbm/startEventBuilder.sh.in @@ -171,6 +171,7 @@ while (( _iMoni < _nbmoni )); do EVTBUILDER+=" --PubTimeMin $_pubminsec" EVTBUILDER+=" --PubTimeMax $_pubmaxsec" EVTBUILDER+=" --FillHistos true" + EVTBUILDER+=" --OutFileName events.root" EVTBUILDER+=" --IgnTsOver false" EVTBUILDER+=" --TriggerDet kTof" EVTBUILDER+=" --TriggerWin 0.0" @@ -202,7 +203,7 @@ while (( _iMoni < _nbmoni )); do done -EVTSINK="DigiEventSink" +EVTSINK="EventSink" EVTSINK+=" --id evtsink1" EVTSINK+=" --severity info" #EVTSINK+=" --severity debug"