Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • le.koch/cbmroot
  • patrick.pfistner_AT_kit.edu/cbmroot
  • lena.rossel_AT_stud.uni-frankfurt.de/cbmroot
  • i.deppner/cbmroot
  • fweig/cbmroot
  • karpushkin_AT_inr.ru/cbmroot
  • v.akishina/cbmroot
  • rishat.sultanov_AT_cern.ch/cbmroot
  • l_fabe01_AT_uni-muenster.de/cbmroot
  • pwg-c2f/cbmroot
  • j.decuveland/cbmroot
  • a.toia/cbmroot
  • i.vassiliev/cbmroot
  • n.herrmann/cbmroot
  • o.lubynets/cbmroot
  • se.gorbunov/cbmroot
  • cornelius.riesen_AT_physik.uni-giessen.de/cbmroot
  • zhangqn17_AT_mails.tsinghua.edu.cn/cbmroot
  • bartosz.sobol/cbmroot
  • ajit.kumar/cbmroot
  • computing/cbmroot
  • a.agarwal_AT_vecc.gov.in/cbmroot
  • osingh/cbmroot
  • wielanek_AT_if.pw.edu.pl/cbmroot
  • malgorzata.karabowicz.stud_AT_pw.edu.pl/cbmroot
  • m.shiroya/cbmroot
  • s.roy/cbmroot
  • p.-a.loizeau/cbmroot
  • a.weber/cbmroot
  • ma.beyer/cbmroot
  • d.klein/cbmroot
  • d.smith/cbmroot
  • mvdsoft/cbmroot
  • d.spicker/cbmroot
  • y.h.leung/cbmroot
  • m.deveaux/cbmroot
  • mkunold/cbmroot
  • h.darwish/cbmroot
  • f_fido01_AT_uni-muenster.de/cbmroot
  • g.kozlov/cbmroot
  • d.emschermann/cbmroot
  • evgeny.lavrik/cbmroot
  • v.friese/cbmroot
  • f.uhlig/cbmroot
  • ebechtel_AT_ikf.uni-frankfurt.de/cbmroot
  • a.senger/cbmroot
  • praisig/cbmroot
  • s.lebedev/cbmroot
  • redelbach_AT_compeng.uni-frankfurt.de/cbmroot
  • p.subramani/cbmroot
  • a_meye37_AT_uni-muenster.de/cbmroot
  • om/cbmroot
  • o.golosov/cbmroot
  • l.chlad/cbmroot
  • a.bercuci/cbmroot
  • d.ramirez/cbmroot
  • v.singhal/cbmroot
  • h.schiller/cbmroot
  • apuntke/cbmroot
  • f.zorn/cbmroot
  • rubio_AT_physi.uni-heidelberg.de/cbmroot
  • p.chudoba/cbmroot
  • apuntke/mcbmroot
  • r.karabowicz/cbmroot
64 results
Show changes
Showing
with 6757 additions and 0 deletions
/* Copyright (C) 2020-2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau, Dominik Smith [committer] */
/**
* CbmDeviceBuildRawEvents.cxx
*
* @since 2020-05-24
* @author P.-A. Loizeau
*/
#include "CbmDeviceBuildRawEvents.h"
/// CBM headers
#include "CbmEvent.h"
#include "CbmFlesCanvasTools.h"
#include "CbmMQDefs.h"
#include "CbmMatch.h"
#include "CbmMvdDigi.h"
#include "TimesliceMetaData.h"
/// FAIRROOT headers
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairParGenericSet.h"
#include "FairRunOnline.h"
#include "BoostSerializer.h"
#include "RootSerializer.h"
/// FAIRSOFT headers (geant, boost, ...)
#include "TCanvas.h"
#include "TFile.h"
#include "TH1.h"
#include "TList.h"
#include "TNamed.h"
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/utility.hpp>
/// C/C++ headers
#include <array>
#include <iomanip>
#include <stdexcept>
#include <string>
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
using namespace std;
CbmDeviceBuildRawEvents::CbmDeviceBuildRawEvents() { fpAlgo = new CbmAlgoBuildRawEvents(); }
void CbmDeviceBuildRawEvents::InitTask()
try {
/// Read options from executable
LOG(info) << "Init options for CbmDeviceBuildRawEvents.";
fbFillHistos = fConfig->GetValue<bool>("FillHistos");
fbIgnoreTsOverlap = fConfig->GetValue<bool>("IgnOverMs");
fsEvtOverMode = fConfig->GetValue<std::string>("EvtOverMode");
fsRefDet = fConfig->GetValue<std::string>("RefDet");
fvsAddDet = fConfig->GetValue<std::vector<std::string>>("AddDet");
fvsDelDet = fConfig->GetValue<std::vector<std::string>>("DelDet");
fvsSetTrigWin = fConfig->GetValue<std::vector<std::string>>("SetTrigWin");
fvsSetTrigMinNb = fConfig->GetValue<std::vector<std::string>>("SetTrigMinNb");
fsChannelNameDataInput = fConfig->GetValue<std::string>("TsNameIn");
fsChannelNameDataOutput = fConfig->GetValue<std::string>("EvtNameOut");
fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
fsChannelNameHistosConfig = fConfig->GetValue<std::string>("ChNameHistCfg");
fsChannelNameCanvasConfig = fConfig->GetValue<std::string>("ChNameCanvCfg");
fsAllowedChannels[0] = fsChannelNameDataInput;
fuPublishFreqTs = fConfig->GetValue<uint32_t>("PubFreqTs");
fdMinPublishTime = fConfig->GetValue<double_t>("PubTimeMin");
fdMaxPublishTime = fConfig->GetValue<double_t>("PubTimeMax");
// 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
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
//logger::SetLogLevel("INFO");
int noChannel = fChannels.size();
LOG(info) << "Number of defined channels: " << noChannel;
for (auto const& entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
if (std::string::npos != entry.first.find(fsChannelNameDataInput)) {
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
OnData(entry.first, &CbmDeviceBuildRawEvents::HandleData);
}
}
/// FIXME: Disable clang formatting for now as it corrupts all alignment
/* clang-format off */
/// Initialize the Algorithm parameters
fpAlgo->SetFillHistos(fbFillHistos);
fpAlgo->SetIgnoreTsOverlap(fbIgnoreTsOverlap);
/// Extract Event Overlap Mode
EOverlapModeRaw mode =
("NoOverlap" == fsEvtOverMode ? EOverlapModeRaw::NoOverlap
: ("MergeOverlap" == fsEvtOverMode ? EOverlapModeRaw::MergeOverlap
: ("AllowOverlap" == fsEvtOverMode ? EOverlapModeRaw::AllowOverlap
: EOverlapModeRaw::NoOverlap)));
fpAlgo->SetEventOverlapMode(mode);
/// Extract refdet
RawEventBuilderDetector refDet = ("kBmon" == fsRefDet ? kRawEventBuilderDetBmon
: ("kSts" == fsRefDet ? kRawEventBuilderDetSts
: ("kMuch" == fsRefDet ? kRawEventBuilderDetMuch
: ("kTrd" == fsRefDet ? kRawEventBuilderDetTrd
: ("kTof" == fsRefDet ? kRawEventBuilderDetTof
: ("kRich" == fsRefDet ? kRawEventBuilderDetRich
: ("kPsd" == fsRefDet ? kRawEventBuilderDetPsd
: kRawEventBuilderDetUndef)))))));
if (kRawEventBuilderDetUndef != refDet) {
fpAlgo->SetReferenceDetector(refDet);
}
else {
LOG(info) << "CbmDeviceBuildRawEvents::InitTask => Trying to change "
"reference to unsupported detector, ignored! "
<< fsRefDet;
}
/// Extract detector to add if any
for (std::vector<std::string>::iterator itStrAdd = fvsAddDet.begin();
itStrAdd != fvsAddDet.end();
++itStrAdd) {
RawEventBuilderDetector addDet = ("kBmon" == *itStrAdd ? kRawEventBuilderDetBmon
: ("kSts" == *itStrAdd ? kRawEventBuilderDetSts
: ("kMuch" == *itStrAdd ? kRawEventBuilderDetMuch
: ("kTrd" == *itStrAdd ? kRawEventBuilderDetTrd
: ("kTof" == *itStrAdd ? kRawEventBuilderDetTof
: ("kRich" == *itStrAdd ? kRawEventBuilderDetRich
: ("kPsd" == *itStrAdd ? kRawEventBuilderDetPsd
: kRawEventBuilderDetUndef)))))));
if (kRawEventBuilderDetUndef != addDet) {
fpAlgo->AddDetector(addDet);
}
else {
LOG(info) << "CbmDeviceBuildRawEvents::InitTask => Trying to add "
"unsupported detector, ignored! "
<< (*itStrAdd);
continue;
}
}
/// Extract detector to remove if any
for (std::vector<std::string>::iterator itStrRem = fvsDelDet.begin();
itStrRem != fvsDelDet.end();
++itStrRem) {
RawEventBuilderDetector remDet = ("kBmon" == *itStrRem ? kRawEventBuilderDetBmon
: ("kSts" == *itStrRem ? kRawEventBuilderDetSts
: ("kMuch" == *itStrRem ? kRawEventBuilderDetMuch
: ("kTrd" == *itStrRem ? kRawEventBuilderDetTrd
: ("kTof" == *itStrRem ? kRawEventBuilderDetTof
: ("kRich" == *itStrRem ? kRawEventBuilderDetRich
: ("kPsd" == *itStrRem ? kRawEventBuilderDetPsd
: kRawEventBuilderDetUndef)))))));
if (kRawEventBuilderDetUndef != remDet) {
fpAlgo->RemoveDetector(remDet);
}
else {
LOG(info) << "CbmDeviceBuildRawEvents::InitTask => Trying to remove "
"unsupported detector, ignored! "
<< (*itStrRem);
continue;
}
}
/// Extract Trigger window to add if any
for (std::vector<std::string>::iterator itStrTrigWin = fvsSetTrigWin.begin();
itStrTrigWin != fvsSetTrigWin.end();
++itStrTrigWin) {
size_t charPosDel = (*itStrTrigWin).find(',');
if (std::string::npos == charPosDel) {
LOG(info)
<< "CbmDeviceBuildRawEvents::InitTask => "
<< "Trying to set trigger window with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found "
<< (*itStrTrigWin) << " )";
continue;
}
/// Detector Enum Tag
std::string sSelDet = (*itStrTrigWin).substr(0, charPosDel);
ECbmModuleId selDet = ("kBmon" == sSelDet ? ECbmModuleId::kBmon
: ("kSts" == sSelDet ? ECbmModuleId::kSts
: ("kMuch" == sSelDet ? ECbmModuleId::kMuch
: ("kTrd" == sSelDet ? ECbmModuleId::kTrd
: ("kTof" == sSelDet ? ECbmModuleId::kTof
: ("kRich" == sSelDet ? ECbmModuleId::kRich
: ("kPsd" == sSelDet ? ECbmModuleId::kPsd
: ECbmModuleId::kNotExist)))))));
if (ECbmModuleId::kNotExist == selDet) {
LOG(info)
<< "CbmDeviceBuildRawEvents::InitTask => "
<< "Trying to set trigger window for unsupported detector, ignored! "
<< sSelDet;
continue;
}
/// Window beginning
charPosDel++;
std::string sNext = (*itStrTrigWin).substr(charPosDel);
charPosDel = sNext.find(',');
if (std::string::npos == charPosDel) {
LOG(info)
<< "CbmDeviceBuildRawEvents::InitTask => "
<< "Trying to set trigger window with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found "
<< (*itStrTrigWin) << " )";
continue;
}
Double_t dWinBeg = std::stod(sNext.substr(0, charPosDel));
/// Window end
charPosDel++;
Double_t dWinEnd = std::stod(sNext.substr(charPosDel));
fpAlgo->SetTriggerWindow(selDet, dWinBeg, dWinEnd);
}
/// Extract MinNb for trigger if any
for (std::vector<std::string>::iterator itStrMinNb = fvsSetTrigMinNb.begin();
itStrMinNb != fvsSetTrigMinNb.end();
++itStrMinNb) {
size_t charPosDel = (*itStrMinNb).find(',');
if (std::string::npos == charPosDel) {
LOG(info)
<< "CbmDeviceBuildRawEvents::InitTask => "
<< "Trying to set trigger min Nb with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,uMinNb but instead found " << (*itStrMinNb)
<< " )";
continue;
}
/// Detector Enum Tag
std::string sSelDet = (*itStrMinNb).substr(0, charPosDel);
ECbmModuleId selDet = ("kBmon" == sSelDet ? ECbmModuleId::kBmon
: ("kSts" == sSelDet ? ECbmModuleId::kSts
: ("kMuch" == sSelDet ? ECbmModuleId::kMuch
: ("kTrd" == sSelDet ? ECbmModuleId::kTrd
: ("kTof" == sSelDet ? ECbmModuleId::kTof
: ("kRich" == sSelDet ? ECbmModuleId::kRich
: ("kPsd" == sSelDet ? ECbmModuleId::kPsd
: ECbmModuleId::kNotExist)))))));
if (ECbmModuleId::kNotExist == selDet) {
LOG(info)
<< "CbmDeviceBuildRawEvents::InitTask => "
<< "Trying to set trigger min Nb for unsupported detector, ignored! "
<< sSelDet;
continue;
}
/// Min number
charPosDel++;
UInt_t uMinNb = std::stoul((*itStrMinNb).substr(charPosDel));
fpAlgo->SetTriggerMinNumber(selDet, uMinNb);
}
/// FIXME: Re-enable clang formatting after formatted lines
/* clang-format on */
/// Create input vectors
fvDigiBmon = new std::vector<CbmBmonDigi>();
fvDigiSts = new std::vector<CbmStsDigi>();
fvDigiMuch = new std::vector<CbmMuchBeamTimeDigi>();
fvDigiTrd = new std::vector<CbmTrdDigi>();
fvDigiTof = new std::vector<CbmTofDigi>();
fvDigiRich = new std::vector<CbmRichDigi>();
fvDigiPsd = new std::vector<CbmPsdDigi>();
fTimeSliceMetaDataArray = new TClonesArray("TimesliceMetaData", 1);
if (NULL == fTimeSliceMetaDataArray) { throw InitTaskError("Failed creating the TS meta data TClonesarray "); }
fpAlgo->SetTimeSliceMetaDataArray(fTimeSliceMetaDataArray);
/// Digis storage
fpAlgo->SetDigis(fvDigiBmon);
fpAlgo->SetDigis(fvDigiSts);
fpAlgo->SetDigis(fvDigiMuch);
fpAlgo->SetDigis(fvDigiTrd);
fpAlgo->SetDigis(fvDigiTof);
fpAlgo->SetDigis(fvDigiRich);
fpAlgo->SetDigis(fvDigiPsd);
// Mvd currently not implemented in event builder
//std::vector<CbmMvdDigi>* pMvdDigi = new std::vector<CbmMvdDigi>();
/// Create output TClonesArray
fEvents = new TClonesArray("CbmEvent", 500);
/// Now that everything is set, initialize the Algorithm
if (kFALSE == fpAlgo->InitAlgo()) { throw InitTaskError("Failed to initilize the algorithm class."); }
/// Histograms management
if (kTRUE == fbFillHistos) {
/// Obtain vector of pointers on each histo from the algo (+ optionally desired folder)
std::vector<std::pair<TNamed*, std::string>> vHistos = fpAlgo->GetHistoVector();
/// Obtain vector of pointers on each canvas from the algo (+ optionally desired folder)
std::vector<std::pair<TCanvas*, std::string>> vCanvases = fpAlgo->GetCanvasVector();
/// Add pointers to each histo in the histo array
/// Create histo config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Histo name, Folder >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto) {
// LOG(info) << "Registering " << vHistos[ uHisto ].first->GetName()
// << " in " << vHistos[ uHisto ].second.data()
// ;
fArrayHisto.Add(vHistos[uHisto].first);
std::pair<std::string, std::string> psHistoConfig(vHistos[uHisto].first->GetName(), vHistos[uHisto].second);
fvpsHistosFolder.push_back(psHistoConfig);
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, psHistoConfig);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist, psHistoConfig);
/// Send message to the common histogram config messages queue
if (Send(messageHist, fsChannelNameHistosConfig) < 0) { throw InitTaskError("Problem sending histo config"); }
LOG(info) << "Config of hist " << psHistoConfig.first.data() << " in folder " << psHistoConfig.second.data();
}
/// Create canvas config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Canvas name, config >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv) {
// LOG(info) << "Registering " << vCanvases[ uCanv ].first->GetName()
// << " in " << vCanvases[ uCanv ].second.data();
std::string sCanvName = (vCanvases[uCanv].first)->GetName();
std::string sCanvConf = GenerateCanvasConfigString(vCanvases[uCanv].first);
std::pair<std::string, std::string> psCanvConfig(sCanvName, sCanvConf);
fvpsCanvasConfig.push_back(psCanvConfig);
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, psCanvConfig);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageCan, psCanvConfig);
/// Send message to the common canvas config messages queue
if (Send(messageCan, fsChannelNameCanvasConfig) < 0) { throw InitTaskError("Problem sending canvas config"); }
LOG(info) << "Config string of Canvas " << psCanvConfig.first.data() << " is " << psCanvConfig.second.data();
}
}
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
}
bool CbmDeviceBuildRawEvents::IsChannelNameAllowed(std::string channelName)
{
for (auto const& entry : fsAllowedChannels) {
std::size_t pos1 = channelName.find(entry);
if (pos1 != std::string::npos) {
const vector<std::string>::const_iterator pos =
std::find(fsAllowedChannels.begin(), fsAllowedChannels.end(), entry);
const vector<std::string>::size_type idx = pos - fsAllowedChannels.begin();
LOG(info) << "Found " << entry << " in " << channelName;
LOG(info) << "Channel name " << channelName << " found in list of allowed channel names at position " << idx;
return true;
}
}
LOG(info) << "Channel name " << channelName << " not found in list of allowed channel names.";
LOG(error) << "Stop device.";
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 CbmDeviceBuildRawEvents::HandleData(FairMQParts& parts, int /*index*/)
{
fulNumMessages++;
LOG(debug) << "Received message number " << fulNumMessages << " with " << parts.Size() << " parts"
<< ", size0: " << parts.At(0)->GetSize();
if (0 == fulNumMessages % 10000) LOG(info) << "Received " << fulNumMessages << " messages";
/// Extract unpacked data from input message
uint32_t uPartIdx = 0;
/// TS metadata
// Deserialize<RootSerializer>(*parts.At(uPartIdx), fTsMetaData);
RootSerializer().Deserialize(*parts.At(uPartIdx), fTsMetaData);
new ((*fTimeSliceMetaDataArray)[fTimeSliceMetaDataArray->GetEntriesFast()])
TimesliceMetaData(std::move(*fTsMetaData));
++uPartIdx;
/// Bmon
std::string msgStrBmon(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issBmon(msgStrBmon);
boost::archive::binary_iarchive inputArchiveBmon(issBmon);
inputArchiveBmon >> *fvDigiBmon;
++uPartIdx;
/// STS
std::string msgStrSts(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issSts(msgStrSts);
boost::archive::binary_iarchive inputArchiveSts(issSts);
inputArchiveSts >> *fvDigiSts;
++uPartIdx;
/// MUCH
std::string msgStrMuch(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issMuch(msgStrMuch);
boost::archive::binary_iarchive inputArchiveMuch(issMuch);
inputArchiveMuch >> *fvDigiMuch;
++uPartIdx;
/// TRD
std::string msgStrTrd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTrd(msgStrTrd);
boost::archive::binary_iarchive inputArchiveTrd(issTrd);
inputArchiveTrd >> *fvDigiTrd;
++uPartIdx;
/// BmonF
std::string msgStrTof(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTof(msgStrTof);
boost::archive::binary_iarchive inputArchiveTof(issTof);
inputArchiveTof >> *fvDigiTof;
++uPartIdx;
/// RICH
std::string msgStrRich(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issRich(msgStrRich);
boost::archive::binary_iarchive inputArchiveRich(issRich);
inputArchiveRich >> *fvDigiRich;
++uPartIdx;
/// PSD
std::string msgStrPsd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issPsd(msgStrPsd);
boost::archive::binary_iarchive inputArchivePsd(issPsd);
inputArchivePsd >> *fvDigiPsd;
++uPartIdx;
/// Call Algo ProcessTs method
fpAlgo->ProcessTs();
/// Send events vector to ouput
if (!SendEvents(parts)) return false;
/// Clear metadata
fTimeSliceMetaDataArray->Clear();
/// Clear vectors
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
fvDigiTof->clear();
fvDigiRich->clear();
fvDigiPsd->clear();
/// Clear event vector after usage
fpAlgo->ClearEventVector();
fEvents->Clear("C");
/// Histograms management
if (kTRUE == fbFillHistos) {
/// Send histograms each 100 time slices. Should be each ~1s
/// Use also runtime checker to trigger sending after M s if
/// processing too slow or delay sending if processing too fast
std::chrono::system_clock::time_point currentTime = std::chrono::system_clock::now();
std::chrono::duration<double_t> elapsedSeconds = currentTime - fLastPublishTime;
if ((fdMaxPublishTime < elapsedSeconds.count())
|| (0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count())) {
SendHistograms();
fLastPublishTime = std::chrono::system_clock::now();
}
}
return true;
}
bool CbmDeviceBuildRawEvents::SendEvents(FairMQParts& partsIn)
{
/// Clear events TClonesArray before usage.
fEvents->Delete();
/// Get vector reference from algo
std::vector<CbmEvent*> vEvents = fpAlgo->GetEventVector();
/// Move CbmEvent from temporary vector to TClonesArray
for (CbmEvent* event : vEvents) {
LOG(debug) << "Vector: " << event->ToString();
new ((*fEvents)[fEvents->GetEntriesFast()]) CbmEvent(std::move(*event));
LOG(debug) << "TClonesArray: " << static_cast<CbmEvent*>(fEvents->At(fEvents->GetEntriesFast() - 1))->ToString();
}
/// Serialize the array of events into a single MQ message
FairMQMessagePtr message(NewMessage());
// Serialize<RootSerializer>(*message, fEvents);
RootSerializer().Serialize(*message, fEvents);
/// Add it at the end of the input composed message
FairMQParts partsOut(std::move(partsIn));
partsOut.AddPart(std::move(message));
if (Send(partsOut, fsChannelNameDataOutput) < 0) {
LOG(error) << "Problem sending data to " << fsChannelNameDataOutput;
return false;
}
return true;
}
bool CbmDeviceBuildRawEvents::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
// Serialize<RootSerializer>(*message, &fArrayHisto);
RootSerializer().Serialize(*message, &fArrayHisto);
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
LOG(error) << "Problem sending data";
return false;
}
/// Reset the histograms after sending them (but do not reset the time)
fpAlgo->ResetHistograms(kFALSE);
return true;
}
CbmDeviceBuildRawEvents::~CbmDeviceBuildRawEvents()
{
/// Clear metadata
fTimeSliceMetaDataArray->Clear();
delete fTsMetaData;
/// Clear vectors
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
fvDigiTof->clear();
fvDigiRich->clear();
fvDigiPsd->clear();
/// Clear events TClonesArray
fEvents->Delete();
delete fpRun;
delete fTimeSliceMetaDataArray;
delete fEvents;
delete fpAlgo;
}
void CbmDeviceBuildRawEvents::Finish() {}
/* Copyright (C) 2020-2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau, Dominik Smith [committer] */
/**
* CbmDeviceBuildRawEvents.h
*
* @since 2020-05-24
* @author P.-A. Loizeau
*/
#ifndef CBMDEVICEBUILDRAWEVENTS_H_
#define CBMDEVICEBUILDRAWEVENTS_H_
/// CBM headers
#include "CbmAlgoBuildRawEvents.h"
#include "CbmBmonDigi.h"
#include "CbmMuchBeamTimeDigi.h"
#include "CbmPsdDigi.h"
#include "CbmRichDigi.h"
#include "CbmStsDigi.h"
#include "CbmTofDigi.h"
#include "CbmTrdDigi.h"
/// FAIRROOT headers
#include "FairMQDevice.h"
/// FAIRSOFT headers (geant, boost, ...)
#include "Rtypes.h"
#include "TObjArray.h"
/// C/C++ headers
#include <chrono>
#include <map>
#include <vector>
class TList;
class TClonesArray;
class FairRunOnline;
class TimesliceMetaData;
class CbmDeviceBuildRawEvents : public FairMQDevice {
public:
CbmDeviceBuildRawEvents();
virtual ~CbmDeviceBuildRawEvents();
protected:
virtual void InitTask();
bool HandleData(FairMQParts&, int);
bool HandleCommand(FairMQMessagePtr&, int);
private:
/// Constants
/// Control flags
Bool_t fbIgnoreTsOverlap = kFALSE; //! Ignore data in Overlap part of the TS
Bool_t fbFillHistos = kTRUE; //! Switch ON/OFF filling of histograms
/// User settings parameters
/// Algo enum settings
std::string fsEvtOverMode = "NoOverlap";
std::string fsRefDet = "kBmon";
std::vector<std::string> fvsAddDet = {};
std::vector<std::string> fvsDelDet = {};
std::vector<std::string> fvsSetTrigWin = {};
std::vector<std::string> fvsSetTrigMinNb = {};
/// message queues
std::string fsChannelNameDataInput = "unpts_0";
std::string fsChannelNameDataOutput = "events";
std::string fsChannelNameCommands = "commands";
std::string fsChannelNameHistosInput = "histogram-in";
std::string fsChannelNameHistosConfig = "histo-conf";
std::string fsChannelNameCanvasConfig = "canvas-conf";
/// Histograms management
uint32_t fuPublishFreqTs = 100;
double_t fdMinPublishTime = 0.5;
double_t fdMaxPublishTime = 5.0;
/// List of MQ channels names
std::vector<std::string> fsAllowedChannels = {fsChannelNameDataInput};
/// Statistics & first TS rejection
uint64_t fulNumMessages = 0;
uint64_t fulTsCounter = 0;
std::chrono::system_clock::time_point fLastPublishTime = std::chrono::system_clock::now();
/// Processing algos
CbmAlgoBuildRawEvents* fpAlgo = nullptr;
/// TS MetaData stable values storage
size_t fuNbCoreMsPerTs = 0; //!
size_t fuNbOverMsPerTs = 0; //!
Double_t fdMsSizeInNs = 1280000; //! Size of a single MS, [nanoseconds]
Double_t fdTsCoreSizeInNs = -1.0; //! Total size of the core MS in a TS, [nanoseconds]
Double_t fdTsOverSizeInNs = -1.0; //! Total size of the overlap MS in a TS, [nanoseconds]
Double_t fdTsFullSizeInNs = -1.0; //! Total size of all MS in a TS, [nanoseconds]
/// Data reception
/// TS MetaData storage
TClonesArray* fTimeSliceMetaDataArray = nullptr; //!
TimesliceMetaData* fTsMetaData = nullptr;
/// Digis storage
std::vector<CbmBmonDigi>* fvDigiBmon = nullptr;
std::vector<CbmStsDigi>* fvDigiSts = nullptr;
std::vector<CbmMuchBeamTimeDigi>* fvDigiMuch = nullptr;
std::vector<CbmTrdDigi>* fvDigiTrd = nullptr;
std::vector<CbmTofDigi>* fvDigiTof = nullptr;
std::vector<CbmRichDigi>* fvDigiRich = nullptr;
std::vector<CbmPsdDigi>* fvDigiPsd = nullptr;
/// Data emission
TClonesArray* fEvents = nullptr; //! output container of CbmEvents
// std::vector< CbmEvent * > & fEventVector; //! vector with all created events
/// Internal data registration (for FairRootManager -> DigiManager links)
FairRunOnline* fpRun = nullptr;
/// Array of histograms to send to the histogram server
TObjArray fArrayHisto = {};
/// Vector of string pairs with ( HistoName, FolderPath ) to send to the histogram server
std::vector<std::pair<std::string, std::string>> fvpsHistosFolder = {};
/// Vector of string pairs with ( CanvasName, CanvasConfig ) to send to the histogram server
/// Format of Can config is "NbPadX(U);NbPadY(U);ConfigPad1(s);....;ConfigPadXY(s)"
/// Format of Pad config is "GrixX(b),GridY(b),LogX(b),LogY(b),LogZ(b),HistoName(s),DrawOptions(s)"
std::vector<std::pair<std::string, std::string>> fvpsCanvasConfig = {};
bool IsChannelNameAllowed(std::string channelName);
void Finish();
bool SendEvents(FairMQParts& partsIn);
bool SendHistograms();
};
#endif /* CBMDEVICEBUILDRAWEVENTS_H_ */
/* Copyright (C) 2020-2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceDigiEventSink.cxx
*
* @since 2020-05-24
* @author P.-A. Loizeau
*/
#include "CbmDeviceDigiEventSink.h"
/// CBM headers
#include "CbmEvent.h"
#include "CbmFlesCanvasTools.h"
#include "CbmMQDefs.h"
#include "TimesliceMetaData.h"
/// FAIRROOT headers
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairParGenericSet.h"
#include "FairRootFileSink.h"
#include "FairRootManager.h"
#include "FairRunOnline.h"
#include "FairSource.h"
#include "BoostSerializer.h"
#include "RootSerializer.h"
/// FAIRSOFT headers (geant, boost, ...)
#include "TCanvas.h"
#include "TFile.h"
#include "TH1.h"
#include "TList.h"
#include "TNamed.h"
#include "TProfile.h"
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/utility.hpp>
/// C/C++ headers
#include <array>
#include <iomanip>
#include <stdexcept>
#include <string>
#include <thread> // this_thread::sleep_for
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
using namespace std;
//Bool_t bMcbm2018MonitorTaskBmonResetHistos = kFALSE;
CbmDeviceDigiEventSink::CbmDeviceDigiEventSink() {}
void CbmDeviceDigiEventSink::InitTask()
try {
/// Read options from executable
LOG(info) << "Init options for CbmDeviceDigiEventSink.";
fbStoreFullTs = fConfig->GetValue<bool>("StoreFullTs");
fsOutputFileName = fConfig->GetValue<std::string>("OutFileName");
fsChannelNameDataInput = fConfig->GetValue<std::string>("EvtNameIn");
fsAllowedChannels[0] = fsChannelNameDataInput;
fbBypassConsecutiveTs = fConfig->GetValue<bool>("BypassConsecutiveTs");
fbWriteMissingTs = fConfig->GetValue<bool>("WriteMissingTs");
fbDisableCompression = fConfig->GetValue<bool>("DisableCompression");
fiTreeFileMaxSize = fConfig->GetValue<int64_t>("TreeFileMaxSize");
fbDigiEventInput = fConfig->GetValue<bool>("DigiEventInput");
fbExclusiveTrdExtract = fConfig->GetValue<bool>("ExclusiveTrdExtract");
fbFillHistos = fConfig->GetValue<bool>("FillHistos");
fuPublishFreqTs = fConfig->GetValue<uint32_t>("PubFreqTs");
fdMinPublishTime = fConfig->GetValue<double_t>("PubTimeMin");
fdMaxPublishTime = fConfig->GetValue<double_t>("PubTimeMax");
fsHistosSuffix = fConfig->GetValue<std::string>("HistosSuffix");
fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
/// Associate the MissedTs Channel to the corresponding handler
OnData(fsChannelNameMissedTs, &CbmDeviceDigiEventSink::HandleMissTsData);
/// Associate the command Channel to the corresponding handler
OnData(fsChannelNameCommands, &CbmDeviceDigiEventSink::HandleCommand);
/// Associate the Event + Unp data Channel to the corresponding handler
// 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
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
//logger::SetLogLevel("INFO");
int noChannel = fChannels.size();
LOG(info) << "Number of defined channels: " << noChannel;
for (auto const& entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
if (std::string::npos != entry.first.find(fsChannelNameDataInput)) {
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
OnData(entry.first, &CbmDeviceDigiEventSink::HandleData);
} // if( entry.first.find( "ts" )
} // for( auto const &entry : fChannels )
// InitContainers();
/// Prepare storage TClonesArrays
/// TS MetaData storage
fTimeSliceMetaDataArray = new TClonesArray("TimesliceMetaData", 1);
if (NULL == fTimeSliceMetaDataArray) {
throw InitTaskError("Failed creating the TS meta data TClonesarray ");
} // if( NULL == fTimeSliceMetaDataArray )
/// Events storage
/// TODO: remove TObject from CbmEvent and switch to vectors!
fEventsSel = new std::vector<CbmDigiEvent>();
/// Prepare root output
if ("" != fsOutputFileName) {
fpRun = new FairRunOnline();
FairRootFileSink* pSink = new FairRootFileSink(fsOutputFileName);
fpFairRootMgr = FairRootManager::Instance();
fpFairRootMgr->SetSink(pSink);
if (nullptr == fpFairRootMgr->GetOutFile()) {
throw InitTaskError("Could not open root file");
} // if( nullptr == fpFairRootMgr->GetOutFile() )
if (fbDisableCompression) {
/// Completely disable the root file compression
pSink->GetRootFile()->SetCompressionLevel(0);
}
/// Set global size limit for all TTree in this process/Root instance
TTree::SetMaxTreeSize(fiTreeFileMaxSize);
} // if( "" != fsOutputFileName )
else {
throw InitTaskError("Empty output filename!");
} // else of if( "" != fsOutputFileName )
LOG(info) << "Init Root Output to " << fsOutputFileName;
fpFairRootMgr->InitSink();
fEvtHeader = new CbmTsEventHeader();
fpFairRootMgr->Register("EventHeader.", "Event", fEvtHeader, kTRUE);
/// Register all input data members with the FairRoot manager
/// TS MetaData
fpFairRootMgr->Register("TimesliceMetaData", "TS Meta Data", fTimeSliceMetaDataArray, kTRUE);
/// CbmEvent
fpFairRootMgr->RegisterAny("DigiEvent", fEventsSel, kTRUE);
/// Full TS Digis storage (optional usage, controlled by fbStoreFullTs!)
if (fbStoreFullTs) {
fvDigiBmon = new std::vector<CbmBmonDigi>();
fvDigiSts = new std::vector<CbmStsDigi>();
fvDigiMuch = new std::vector<CbmMuchDigi>();
fvDigiTrd = new std::vector<CbmTrdDigi>();
fvDigiTof = new std::vector<CbmTofDigi>();
fvDigiRich = new std::vector<CbmRichDigi>();
fvDigiPsd = new std::vector<CbmPsdDigi>();
fpFairRootMgr->RegisterAny(CbmBmonDigi::GetBranchName(), fvDigiBmon, kTRUE);
fpFairRootMgr->RegisterAny(CbmStsDigi::GetBranchName(), fvDigiSts, kTRUE);
fpFairRootMgr->RegisterAny(CbmMuchDigi::GetBranchName(), fvDigiMuch, kTRUE);
fpFairRootMgr->RegisterAny(CbmTrdDigi::GetBranchName(), fvDigiTrd, kTRUE);
fpFairRootMgr->RegisterAny(CbmTofDigi::GetBranchName(), fvDigiTof, kTRUE);
fpFairRootMgr->RegisterAny(CbmRichDigi::GetBranchName(), fvDigiRich, kTRUE);
fpFairRootMgr->RegisterAny(CbmPsdDigi::GetBranchName(), fvDigiPsd, kTRUE);
}
fpFairRootMgr->WriteFolder();
LOG(info) << "Initialized outTree with rootMgr at " << fpFairRootMgr;
/// Histograms management
if (kTRUE == fbFillHistos) {
/// Comment to prevent clang format single lining
if (kFALSE == InitHistograms()) { throw InitTaskError("Failed to initialize the histograms."); }
} // if( kTRUE == fbFillHistos )
fbInitDone = true;
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
}
bool CbmDeviceDigiEventSink::IsChannelNameAllowed(std::string channelName)
{
for (auto const& entry : fsAllowedChannels) {
std::size_t pos1 = channelName.find(entry);
if (pos1 != std::string::npos) {
const vector<std::string>::const_iterator pos =
std::find(fsAllowedChannels.begin(), fsAllowedChannels.end(), entry);
const vector<std::string>::size_type idx = pos - fsAllowedChannels.begin();
LOG(info) << "Found " << entry << " in " << channelName;
LOG(info) << "Channel name " << channelName << " found in list of allowed channel names at position " << idx;
return true;
} // if (pos1!=std::string::npos)
} // for(auto const &entry : fsAllowedChannels)
LOG(info) << "Channel name " << channelName << " not found in list of allowed channel names.";
LOG(error) << "Stop device.";
return false;
}
bool CbmDeviceDigiEventSink::InitHistograms()
{
/// Histos creation and obtain pointer on them
/// Trigger histo creation, filling vHistos and vCanvases
// bool initOK =CreateHistograms();
bool initOK = true;
/// Obtain vector of pointers on each histo from the algo (+ optionally desired folder) or create them locally
// ALGO: std::vector<std::pair<TNamed*, std::string>> vHistos = fMonitorAlgo->GetHistoVector();
std::vector<std::pair<TNamed*, std::string>> vHistos = {};
/* clang-format off */
fhFullTsBuffSizeEvo = new TProfile(Form("hFullTsBuffSizeEvo%s", fsHistosSuffix.data()),
"Evo. of the full TS buffer size; Time in run [s]; Size []",
720, 0, 7200);
fhMissTsBuffSizeEvo = new TProfile(Form("hMissTsBuffSizeEvo%s", fsHistosSuffix.data()),
"Evo. of the missed TS buffer size; Time in run [s]; Size []",
720, 0, 7200);
fhFullTsProcEvo = new TH1I(Form("hFullTsProcEvo%s", fsHistosSuffix.data()),
"Processed full TS; Time in run [s]; # []",
720, 0, 7200);
fhMissTsProcEvo = new TH1I(Form("hMissTsProcEvo%s", fsHistosSuffix.data()),
"Processed missing TS; Time in run [s]; # []",
720, 0, 7200);
fhTotalTsProcEvo = new TH1I(Form("hTotalTsProcEvo%s", fsHistosSuffix.data()),
"Total processed TS; Time in run [s]; # []",
720, 0, 7200);
fhTotalEventsEvo = new TH1I(Form("hTotalEventsEvo%s", fsHistosSuffix.data()),
"Processed events; Time in run [s]; # []",
720, 0, 7200);
/* clang-format on */
std::string sFolder = std::string("EvtSink") + fsHistosSuffix;
vHistos.push_back(std::pair<TNamed*, std::string>(fhFullTsBuffSizeEvo, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhMissTsBuffSizeEvo, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhFullTsProcEvo, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhMissTsProcEvo, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhTotalTsProcEvo, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhTotalEventsEvo, sFolder));
/// Obtain vector of pointers on each canvas from the algo (+ optionally desired folder) or create them locally
// ALGO: std::vector<std::pair<TCanvas*, std::string>> vCanvases = fMonitorAlgo->GetCanvasVector();
std::vector<std::pair<TCanvas*, std::string>> vCanvases = {};
fcEventSinkAllHist = new TCanvas(Form("cEventSinkAllHist%s", fsHistosSuffix.data()), "Event Sink Monitoring");
fcEventSinkAllHist->Divide(3, 2);
fcEventSinkAllHist->cd(1);
gPad->SetGridx();
gPad->SetGridy();
fhFullTsBuffSizeEvo->Draw("hist");
fcEventSinkAllHist->cd(2);
gPad->SetGridx();
gPad->SetGridy();
fhMissTsBuffSizeEvo->Draw("hist");
fcEventSinkAllHist->cd(3);
gPad->SetGridx();
gPad->SetGridy();
fhFullTsProcEvo->Draw("hist");
fcEventSinkAllHist->cd(4);
gPad->SetGridx();
gPad->SetGridy();
fhMissTsProcEvo->Draw("hist");
fcEventSinkAllHist->cd(5);
gPad->SetGridx();
gPad->SetGridy();
fhTotalTsProcEvo->Draw("hist");
fcEventSinkAllHist->cd(6);
gPad->SetGridx();
gPad->SetGridy();
gPad->SetLogy();
fhTotalEventsEvo->Draw("hist");
vCanvases.push_back(std::pair<TCanvas*, std::string>(fcEventSinkAllHist, std::string("canvases") + fsHistosSuffix));
/// Add pointers to each histo in the histo array
/// Create histo config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Histo name, Folder >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto) {
// LOG(info) << "Registering " << vHistos[ uHisto ].first->GetName()
// << " in " << vHistos[ uHisto ].second.data()
// ;
fArrayHisto.Add(vHistos[uHisto].first);
std::pair<std::string, std::string> psHistoConfig(vHistos[uHisto].first->GetName(), vHistos[uHisto].second);
fvpsHistosFolder.push_back(psHistoConfig);
LOG(info) << "Config of hist " << psHistoConfig.first.data() << " in folder " << psHistoConfig.second.data();
} // for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto )
/// Create canvas config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Canvas name, config >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv) {
// LOG(info) << "Registering " << vCanvases[ uCanv ].first->GetName()
// << " in " << vCanvases[ uCanv ].second.data();
std::string sCanvName = (vCanvases[uCanv].first)->GetName();
std::string sCanvConf = GenerateCanvasConfigString(vCanvases[uCanv].first);
std::pair<std::string, std::string> psCanvConfig(sCanvName, sCanvConf);
fvpsCanvasConfig.push_back(psCanvConfig);
LOG(info) << "Config string of Canvas " << psCanvConfig.first.data() << " is " << psCanvConfig.second.data();
} // for( UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv )
return initOK;
}
bool CbmDeviceDigiEventSink::ResetHistograms(bool bResetStartTime)
{
fhFullTsBuffSizeEvo->Reset();
fhMissTsBuffSizeEvo->Reset();
fhFullTsProcEvo->Reset();
fhMissTsProcEvo->Reset();
fhTotalTsProcEvo->Reset();
fhTotalEventsEvo->Reset();
if (bResetStartTime) {
/// Reset the start time of the time evolution histograms
fStartTime = std::chrono::system_clock::now();
}
return true;
}
//--------------------------------------------------------------------//
// handler is called whenever a message arrives on fsChannelNameMissedTs, with a reference to the message and a sub-channel index (here 0)
bool CbmDeviceDigiEventSink::HandleMissTsData(FairMQMessagePtr& msg, int /*index*/)
{
std::vector<uint64_t> vIndices;
std::string msgStrMissTs(static_cast<char*>(msg->GetData()), msg->GetSize());
std::istringstream issMissTs(msgStrMissTs);
boost::archive::binary_iarchive inputArchiveMissTs(issMissTs);
inputArchiveMissTs >> vIndices;
fvulMissedTsIndices.insert(fvulMissedTsIndices.end(), vIndices.begin(), vIndices.end());
/// Check TS queue and process it if needed (in case it filled a hole!)
if (!fbBypassConsecutiveTs) {
/// But only if Consecutive TS check is not disabled explicitly by user
CheckTsQueues();
}
return true;
}
//--------------------------------------------------------------------//
// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
bool CbmDeviceDigiEventSink::HandleData(FairMQParts& parts, int /*index*/)
{
fulNumMessages++;
LOG(debug) << "Received message number " << fulNumMessages << " with " << parts.Size() << " parts"
<< ", size0: " << parts.At(0)->GetSize();
if (0 == fulNumMessages % 10000) LOG(info) << "Received " << fulNumMessages << " messages";
/// Unpack the message
CbmEventTimeslice unpTs(parts, fbDigiEventInput);
/// FIXME: Need to check if TS arrived in order (probably not!!!) + buffer!!!
LOG(debug) << "Next TS check " << fuPrevTsIndex << " " << fulTsCounter << " " << unpTs.fTsMetaData.GetIndex()
<< " Storage size: " << fmFullTsStorage.size();
if (fbBypassConsecutiveTs || (fuPrevTsIndex + 1 == unpTs.fTsMetaData.GetIndex())
|| (0 == fuPrevTsIndex && 0 == fulTsCounter && 0 == unpTs.fTsMetaData.GetIndex())) {
LOG(debug) << "TS direct to dump";
/// Fill all storage variables registers for data output
PrepareTreeEntry(unpTs);
/// Trigger FairRoot manager to dump Tree entry
DumpTreeEntry();
/// Update counters
fuPrevTsIndex = unpTs.fTsMetaData.GetIndex();
fulTsCounter++;
}
else {
LOG(debug) << "TS direct to storage";
/// If not consecutive to last TS sent,
fmFullTsStorage.emplace_hint(fmFullTsStorage.end(),
std::pair<uint64_t, CbmEventTimeslice>(unpTs.fTsMetaData.GetIndex(), unpTs));
}
LOG(debug) << "TS metadata checked";
/// Clear metadata => crashes, maybe not needed as due to move the pointer is invalidated?
// delete fTsMetaData;
if (fbBypassConsecutiveTs) {
/// Skip checking the TS buffer as writing straight to file
/// => Just check if we are done and can close the file or not
if (fbReceivedEof) {
/// In this case we cannot check if the last TS received/processed is the final one due to lack of order
/// => use instead the fact that we received all expected TS
if ((fulTsCounter + fvulMissedTsIndices.size()) == fuTotalTsCount) {
LOG(info) << "CbmDeviceDigiEventSink::HandleData => "
<< "Found all expected TS (" << fulTsCounter << ") and total nb of TS " << fuTotalTsCount
<< " after accounting for the ones reported as missing by the source (" << fvulMissedTsIndices.size()
<< ")";
Finish();
} // if ((fulTsCounter + fvulMissedTsIndices.size()) == fuTotalTsCount)
}
}
else {
/// Check TS queue and process it if needed (in case it filled a hole!)
CheckTsQueues();
LOG(debug) << "TS queues checked";
}
/// Histograms management
if (kTRUE == fbFillHistos) {
std::chrono::system_clock::time_point currentTime = std::chrono::system_clock::now();
/// Fill histograms every 5 or more seconds
/// TODO: make it a parameter
std::chrono::duration<double_t> elapsedSecondsFill = currentTime - fLastFillTime;
if (1.0 < elapsedSecondsFill.count()) {
std::chrono::duration<double_t> secInRun = currentTime - fStartTime;
/// Rely on the fact that all histos have same X axis to avoid multiple "current bin" search
/*
int32_t iBinIndex = fhFullTsBuffSizeEvo->FindBin(secInRun.count());
fhFullTsBuffSizeEvo->SetBinContent(iBinIndex, fmFullTsStorage.size());
fhMissTsBuffSizeEvo->SetBinContent(iBinIndex, fvulMissedTsIndices.size());
fhFullTsProcEvo->SetBinContent(iBinIndex, fulTsCounter);
fhMissTsProcEvo->SetBinContent(iBinIndex, fulMissedTsCounter);
fhTotalTsProcEvo->SetBinContent(iBinIndex, (fulTsCounter + fulMissedTsCounter));
fhTotalEventsEvo->SetBinContent(iBinIndex, fulProcessedEvents);
*/
fhFullTsBuffSizeEvo->Fill(secInRun.count(), fmFullTsStorage.size());
fhMissTsBuffSizeEvo->Fill(secInRun.count(), fvulMissedTsIndices.size());
fhFullTsProcEvo->Fill(secInRun.count(), (fulTsCounter - fulLastFullTsCounter));
fhMissTsProcEvo->Fill(secInRun.count(), (fulMissedTsCounter - fulLastMissTsCounter));
fhTotalTsProcEvo->Fill(secInRun.count(),
(fulTsCounter - fulLastFullTsCounter + fulMissedTsCounter - fulLastMissTsCounter));
fhTotalEventsEvo->Fill(secInRun.count(), fulProcessedEvents - fulLastProcessedEvents);
fLastFillTime = currentTime;
fulLastFullTsCounter = fulTsCounter;
fulLastMissTsCounter = fulMissedTsCounter;
fulLastProcessedEvents = fulProcessedEvents;
}
/// Send histograms each N timeslices.
/// Use also runtime checker to trigger sending after M s if
/// processing too slow or delay sending if processing too fast
std::chrono::duration<double_t> elapsedSeconds = currentTime - fLastPublishTime;
if ((fdMaxPublishTime < elapsedSeconds.count())
|| (0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count())) {
if (!fbConfigSent) {
// Send the configuration only once per run!
fbConfigSent = SendHistoConfAndData();
} // if( !fbConfigSent )
else
SendHistograms();
fLastPublishTime = currentTime;
} // if( ( fdMaxPublishTime < elapsedSeconds.count() ) || ( 0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count() ) )
} // if( kTRUE == fbFillHistos )
LOG(debug) << "Processed TS with saving " << (fulTsCounter + fulMissedTsCounter) << " TS (" << fulTsCounter
<< " full ones and " << fulMissedTsCounter << " missed/empty ones)";
LOG(debug) << "Buffers are " << fmFullTsStorage.size() << " full TS and " << fvulMissedTsIndices.size()
<< " missed/empty ones)";
return true;
}
//--------------------------------------------------------------------//
bool CbmDeviceDigiEventSink::HandleCommand(FairMQMessagePtr& msg, int /*index*/)
{
/*
std::string sCommand( static_cast< char * >( msg->GetData() ),
msg->GetSize() );
*/
std::string sCommand;
std::string msgStrCmd(static_cast<char*>(msg->GetData()), msg->GetSize());
std::istringstream issCmd(msgStrCmd);
boost::archive::binary_iarchive inputArchiveCmd(issCmd);
inputArchiveCmd >> sCommand;
std::string sCmdTag = sCommand;
size_t charPosDel = sCommand.find(' ');
if (std::string::npos != charPosDel) {
sCmdTag = sCommand.substr(0, charPosDel);
} // if( std::string::npos != charPosDel )
if ("EOF" == sCmdTag) {
fbReceivedEof = true;
/// Extract the last TS index and global full TS count
if (std::string::npos == charPosDel) {
LOG(fatal) << "CbmDeviceDigiEventSink::HandleCommand => "
<< "Incomplete EOF command received: " << sCommand;
return false;
} // if( std::string::npos == charPosDel )
/// Last TS index
charPosDel++;
std::string sNext = sCommand.substr(charPosDel);
charPosDel = sNext.find(' ');
if (std::string::npos == charPosDel) {
LOG(fatal) << "CbmDeviceDigiEventSink::HandleCommand => "
<< "Incomplete EOF command received: " << sCommand;
return false;
} // if( std::string::npos == charPosDel )
fuLastTsIndex = std::stoul(sNext.substr(0, charPosDel));
/// Total TS count
charPosDel++;
fuTotalTsCount = std::stoul(sNext.substr(charPosDel));
LOG(info) << "CbmDeviceDigiEventSink::HandleCommand => "
<< "Received EOF command with final TS index " << fuLastTsIndex << " and total nb TS " << fuTotalTsCount;
/// End of data: clean save of data + close file + send last state of histos if enabled
if (fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount) {
LOG(info) << "CbmDeviceDigiEventSink::HandleCommand => "
<< "Found final TS index " << fuLastTsIndex << " and total nb TS " << fuTotalTsCount;
Finish();
} // if( fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount )
} // if( "EOF" == sCmdTag )
else if ("STOP" == sCmdTag) {
/// TODO: different treatment in case of "BAD" ending compared to EOF?
/// Source failure: clean save of received data + close file + send last state of histos if enabled
Finish();
} // else if( "STOP" == sCmdTag )
else {
LOG(warning) << "Unknown command received: " << sCmdTag << " => will be ignored!";
} // else if command not recognized
return true;
}
//--------------------------------------------------------------------//
void CbmDeviceDigiEventSink::CheckTsQueues()
{
bool bHoleFoundInBothQueues = false;
std::map<uint64_t, CbmEventTimeslice>::iterator itFullTs = fmFullTsStorage.begin();
std::vector<uint64_t>::iterator itMissTs = fvulMissedTsIndices.begin();
while (!bHoleFoundInBothQueues) {
/// Check if the first TS in the full TS queue is the next one
if (fmFullTsStorage.end() != itFullTs && fuPrevTsIndex + 1 == (*itFullTs).first) {
/// Fill all storage variables registers for data output
PrepareTreeEntry((*itFullTs).second);
/// Trigger FairRoot manager to dump Tree entry
DumpTreeEntry();
/// Update counters
fuPrevTsIndex = (*itFullTs).first;
fulTsCounter++;
/// Increment iterator
++itFullTs;
continue;
} // if( fmFullTsStorage.end() != itFullTs && fuPrevTsIndex + 1 == (*itFullTs).first() )
if (fmFullTsStorage.end() != itFullTs)
LOG(debug) << "CbmDeviceDigiEventSink::CheckTsQueues => Full TS " << (*itFullTs).first << " VS "
<< (fuPrevTsIndex + 1);
/// Check if the first TS in the missed TS queue is the next one
if (fvulMissedTsIndices.end() != itMissTs
&& ((0 == fuPrevTsIndex && fuPrevTsIndex == (*itMissTs))
|| ((0 < fulTsCounter || 0 < fulMissedTsCounter) && fuPrevTsIndex + 1 == (*itMissTs)))) {
if (fbWriteMissingTs) {
/// Prepare entry with only dummy TS metadata and empty storage variables
new ((*fTimeSliceMetaDataArray)[fTimeSliceMetaDataArray->GetEntriesFast()])
TimesliceMetaData(0, 0, 0, (*itMissTs));
/// Trigger FairRoot manager to dump Tree entry
DumpTreeEntry();
}
/// Update counters
fuPrevTsIndex = (*itMissTs);
fulMissedTsCounter++;
/// Increment iterator
++itMissTs;
continue;
} // if( fvulMissedTsIndices.end() != itMissTs && fuPrevTsIndex + 1 == (*itMissTs ) )
if (fvulMissedTsIndices.end() != itMissTs)
LOG(debug) << "CbmDeviceDigiEventSink::CheckTsQueues => Empty TS " << (*itMissTs) << " VS "
<< (fuPrevTsIndex + 1);
/// Should be reached only if both queues at the end or hole found in both
bHoleFoundInBothQueues = true;
} // while( !bHoleFoundInBothQueues )
LOG(debug) << "CbmDeviceDigiEventSink::CheckTsQueues => buffered TS " << fmFullTsStorage.size()
<< " buffered empties " << fvulMissedTsIndices.size();
for (auto it = fmFullTsStorage.begin(); it != fmFullTsStorage.end(); ++it) {
LOG(debug) << "CbmDeviceDigiEventSink::CheckTsQueues => buffered TS index " << (*it).first;
}
/// Delete the processed entries
fmFullTsStorage.erase(fmFullTsStorage.begin(), itFullTs);
fvulMissedTsIndices.erase(fvulMissedTsIndices.begin(), itMissTs);
/// End of data: clean save of data + close file + send last state of histos if enabled
if (fbReceivedEof && fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount) {
LOG(info) << "CbmDeviceDigiEventSink::CheckTsQueues => "
<< "Found final TS index " << fuLastTsIndex << " and total nb TS " << fuTotalTsCount;
Finish();
} // if( fbReceivedEof && fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount )
}
//--------------------------------------------------------------------//
void CbmDeviceDigiEventSink::PrepareTreeEntry(CbmEventTimeslice unpTs)
{
/// FIXME: poor man solution with lots of data copy until we undertsnad how to properly deal
/// with FairMq messages ownership and memory managment
(*fEvtHeader) = std::move(unpTs.fCbmTsEventHeader);
/// FIXME: Not sure if this is the proper way to insert the data
new ((*fTimeSliceMetaDataArray)[fTimeSliceMetaDataArray->GetEntriesFast()])
TimesliceMetaData(std::move(unpTs.fTsMetaData));
/// Extract CbmEvent vector from input message
// FU, 29.06.22 Remove std::move to allow copy ellision
(*fEventsSel) = unpTs.GetSelectedData(fbExclusiveTrdExtract);
if (kTRUE == fbFillHistos) {
/// Accumulated counts, will show rise + plateau pattern in spill
fulProcessedEvents += fEventsSel->size();
}
/// Full TS Digis storage (optional usage, controlled by fbStoreFullTs!)
if (fbStoreFullTs) {
if (0 < unpTs.fvDigiBmon.size()) fvDigiBmon->assign(unpTs.fvDigiBmon.begin(), unpTs.fvDigiBmon.end());
if (0 < unpTs.fvDigiSts.size()) fvDigiSts->assign(unpTs.fvDigiSts.begin(), unpTs.fvDigiSts.end());
if (0 < unpTs.fvDigiMuch.size()) fvDigiMuch->assign(unpTs.fvDigiMuch.begin(), unpTs.fvDigiMuch.end());
if (0 < unpTs.fvDigiTrd.size()) fvDigiTrd->assign(unpTs.fvDigiTrd.begin(), unpTs.fvDigiTrd.end());
if (0 < unpTs.fvDigiTof.size()) fvDigiTof->assign(unpTs.fvDigiTof.begin(), unpTs.fvDigiTof.end());
if (0 < unpTs.fvDigiRich.size()) fvDigiRich->assign(unpTs.fvDigiRich.begin(), unpTs.fvDigiRich.end());
if (0 < unpTs.fvDigiPsd.size()) fvDigiPsd->assign(unpTs.fvDigiPsd.begin(), unpTs.fvDigiPsd.end());
}
}
void CbmDeviceDigiEventSink::DumpTreeEntry()
{
// Unpacked digis + CbmEvent output to root file
/*
* NH style
// fpFairRootMgr->FillEventHeader(fEvtHeader);
// LOG(info) << "Fill WriteOutBuffer with FairRootManager at " << fpFairRootMgr;
// fpOutRootFile->cd();
fpFairRootMgr->Fill();
fpFairRootMgr->StoreWriteoutBufferData( fpFairRootMgr->GetEventTime() );
//fpFairRootMgr->StoreAllWriteoutBufferData();
fpFairRootMgr->DeleteOldWriteoutBufferData();
*/
/// FairRunOnline style
fpFairRootMgr->StoreWriteoutBufferData(fpFairRootMgr->GetEventTime());
auto source = fpFairRootMgr->GetSource();
if (source) { source->FillEventHeader(fEvtHeader); }
fpFairRootMgr->Fill();
fpFairRootMgr->DeleteOldWriteoutBufferData();
// fpFairRootMgr->Write();
/// Clear metadata array
fTimeSliceMetaDataArray->Clear();
/// Clear event vector
fEventsSel->clear();
/// Full TS Digis storage (optional usage, controlled by fbStoreFullTs!)
if (fbStoreFullTs) {
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
fvDigiTof->clear();
fvDigiRich->clear();
fvDigiPsd->clear();
}
}
//--------------------------------------------------------------------//
bool CbmDeviceDigiEventSink::SendHistoConfAndData()
{
/// Prepare multiparts message and header
std::pair<uint32_t, uint32_t> pairHeader(fvpsHistosFolder.size(), fvpsCanvasConfig.size());
FairMQMessagePtr messageHeader(NewMessage());
// Serialize<BoostSerializer<std::pair<uint32_t, uint32_t>>>(*messageHeader, pairHeader);
BoostSerializer<std::pair<uint32_t, uint32_t>>().Serialize(*messageHeader, pairHeader);
FairMQParts partsOut;
partsOut.AddPart(std::move(messageHeader));
for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto) {
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, fvpsHistosFolder[uHisto]);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist, fvpsHistosFolder[uHisto]);
partsOut.AddPart(std::move(messageHist));
} // for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto)
/// Catch case where no histos are registered!
/// => Add empty message
if (0 == fvpsHistosFolder.size()) {
FairMQMessagePtr messageHist(NewMessage());
partsOut.AddPart(std::move(messageHist));
}
for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv) {
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, fvpsCanvasConfig[uCanv]);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageCan, fvpsCanvasConfig[uCanv]);
partsOut.AddPart(std::move(messageCan));
} // for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv)
/// Catch case where no Canvases are registered!
/// => Add empty message
if (0 == fvpsCanvasConfig.size()) {
FairMQMessagePtr messageHist(NewMessage());
partsOut.AddPart(std::move(messageHist));
}
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr msgHistos(NewMessage());
RootSerializer().Serialize(*msgHistos, &fArrayHisto);
partsOut.AddPart(std::move(msgHistos));
/// Send the multi-parts message to the common histogram messages queue
if (Send(partsOut, fsChannelNameHistosInput) < 0) {
LOG(error) << "CbmTsConsumerReqDevExample::SendHistoConfAndData => Problem sending data";
return false;
} // if( Send( partsOut, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
ResetHistograms(false);
return true;
}
bool CbmDeviceDigiEventSink::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
RootSerializer().Serialize(*message, &fArrayHisto);
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
LOG(error) << "Problem sending data";
return false;
} // if( Send( message, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
ResetHistograms(false);
return true;
}
//--------------------------------------------------------------------//
void CbmDeviceDigiEventSink::PostRun()
{
// Needed to avoid due to other end of ZMQ channel being already gone if called during Finish/destructor
if (kTRUE == fbFillHistos) {
SendHistograms();
fLastPublishTime = std::chrono::system_clock::now();
} // if( kTRUE == fbFillHistos )
}
//--------------------------------------------------------------------//
CbmDeviceDigiEventSink::~CbmDeviceDigiEventSink()
{
/// FIXME: Add pointers check before delete
/// Close things properly if not already done
if (fbInitDone && !fbFinishDone) Finish();
/// Clear events vector
if (fbInitDone) {
fEventsSel->clear();
delete fEventsSel;
}
delete fpRun;
}
void CbmDeviceDigiEventSink::Finish()
{
LOG(info) << "Performing clean close of the file";
// Clean closure of output to root file
fpFairRootMgr->Write(); // Broken due to FileMaxSize?!?
fpFairRootMgr->CloseSink();
LOG(info) << "File closed after saving " << (fulTsCounter + fulMissedTsCounter) << " TS (" << fulTsCounter
<< " full ones and " << fulMissedTsCounter << " missed/empty ones)";
LOG(info) << "Still buffered TS " << fmFullTsStorage.size() << " and still buffered empties "
<< fvulMissedTsIndices.size();
if (fair::mq::State::Running == GetCurrentState()) {
/// Force state transitions only if not already done by ODC/DDS!
ChangeState(fair::mq::Transition::Stop);
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
ChangeState(fair::mq::Transition::End);
}
fbFinishDone = kTRUE;
}
CbmEventTimeslice::CbmEventTimeslice(FairMQParts& parts, bool bDigiEvtInput)
{
fbDigiEvtInput = bDigiEvtInput;
uint32_t uPartIdx = 0;
if (fbDigiEvtInput) {
/// Digi events => Extract selected data from input message
if (3 != parts.Size()) {
LOG(error) << "CbmEventTimeslice::CbmEventTimeslice => Wrong number of parts to deserialize DigiEvents: "
<< parts.Size() << " VS 3!";
LOG(fatal) << "Probably the wrong value was used for the option DigiEventInput of the Sink or DigiEventOutput of "
<< "the event builder";
}
/// (1) TS header
TObject* tempObjectPointer = nullptr;
RootSerializer().Deserialize(*parts.At(uPartIdx), tempObjectPointer);
if (tempObjectPointer && TString(tempObjectPointer->ClassName()).EqualTo("CbmTsEventHeader")) {
fCbmTsEventHeader = *(static_cast<CbmTsEventHeader*>(tempObjectPointer));
}
else {
LOG(fatal) << "Failed to deserialize the TS header";
}
++uPartIdx;
/// (2) TS metadata
tempObjectPointer = nullptr;
RootSerializer().Deserialize(*parts.At(uPartIdx), tempObjectPointer);
if (tempObjectPointer && TString(tempObjectPointer->ClassName()).EqualTo("TimesliceMetaData")) {
fTsMetaData = *(static_cast<TimesliceMetaData*>(tempObjectPointer));
}
else {
LOG(fatal) << "Failed to deserialize the TS metadata";
}
++uPartIdx;
/// (3) Events
std::string msgStrEvt(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issEvt(msgStrEvt);
boost::archive::binary_iarchive inputArchiveEvt(issEvt);
inputArchiveEvt >> fvDigiEvents;
++uPartIdx;
LOG(debug) << "Input event array " << fvDigiEvents.size();
}
else {
/// Raw data + raw events => Extract unpacked data from input message
if (10 != parts.Size()) {
LOG(error) << "CbmEventTimeslice::CbmEventTimeslice => Wrong number of parts to deserialize raw data + events: "
<< parts.Size() << " VS 10!";
LOG(fatal) << "Probably the wrong value was used for the option DigiEventInput of the Sink or DigiEventOutput of "
<< "the event builder";
}
/// (1) TS header
TObject* tempObjectPointer = nullptr;
RootSerializer().Deserialize(*parts.At(uPartIdx), tempObjectPointer);
if (tempObjectPointer && TString(tempObjectPointer->ClassName()).EqualTo("CbmTsEventHeader")) {
fCbmTsEventHeader = *(static_cast<CbmTsEventHeader*>(tempObjectPointer));
}
else {
LOG(fatal) << "Failed to deserialize the TS header";
}
++uPartIdx;
/// (2) Bmon
std::string msgStrBmon(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issBmon(msgStrBmon);
boost::archive::binary_iarchive inputArchiveBmon(issBmon);
inputArchiveBmon >> fvDigiBmon;
++uPartIdx;
/// (3) STS
std::string msgStrSts(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issSts(msgStrSts);
boost::archive::binary_iarchive inputArchiveSts(issSts);
inputArchiveSts >> fvDigiSts;
++uPartIdx;
/// (4) MUCH
std::string msgStrMuch(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issMuch(msgStrMuch);
boost::archive::binary_iarchive inputArchiveMuch(issMuch);
inputArchiveMuch >> fvDigiMuch;
++uPartIdx;
/// (5) TRD
std::string msgStrTrd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTrd(msgStrTrd);
boost::archive::binary_iarchive inputArchiveTrd(issTrd);
inputArchiveTrd >> fvDigiTrd;
++uPartIdx;
/// (6) BmonF
std::string msgStrTof(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTof(msgStrTof);
boost::archive::binary_iarchive inputArchiveTof(issTof);
inputArchiveTof >> fvDigiTof;
++uPartIdx;
/// (7) RICH
std::string msgStrRich(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issRich(msgStrRich);
boost::archive::binary_iarchive inputArchiveRich(issRich);
inputArchiveRich >> fvDigiRich;
++uPartIdx;
/// (8) PSD
std::string msgStrPsd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issPsd(msgStrPsd);
boost::archive::binary_iarchive inputArchivePsd(issPsd);
inputArchivePsd >> fvDigiPsd;
++uPartIdx;
/// (9) TS metadata
tempObjectPointer = nullptr;
RootSerializer().Deserialize(*parts.At(uPartIdx), tempObjectPointer);
if (tempObjectPointer && TString(tempObjectPointer->ClassName()).EqualTo("TimesliceMetaData")) {
fTsMetaData = *(static_cast<TimesliceMetaData*>(tempObjectPointer));
}
else {
LOG(fatal) << "Failed to deserialize the TS metadata";
}
++uPartIdx;
/// (10) Events
/// FIXME: Find out if possible to use only the boost serializer/deserializer
/*
std::string msgStrEvt(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issEvt(msgStrEvt);
boost::archive::binary_iarchive inputArchiveEvt(issEvt);
inputArchiveEvt >> fvEvents;
++uPartIdx;
LOG(info) << "Input event array " << fvEvents.size();
*/
std::vector<CbmEvent>* pvOutEvents = nullptr;
RootSerializer().Deserialize(*parts.At(uPartIdx), pvOutEvents);
fvEvents = std::move(*pvOutEvents);
LOG(debug) << "Input event array " << fvEvents.size();
}
}
CbmEventTimeslice::~CbmEventTimeslice()
{
fvDigiBmon.clear();
fvDigiSts.clear();
fvDigiMuch.clear();
fvDigiTrd.clear();
fvDigiTof.clear();
fvDigiRich.clear();
fvDigiPsd.clear();
fvEvents.clear();
fvDigiEvents.clear();
}
void CbmEventTimeslice::ExtractSelectedData(bool bExclusiveTrdExtract)
{
fvDigiEvents.reserve(fvEvents.size());
/// Loop on events in input vector
for (CbmEvent event : fvEvents) {
CbmDigiEvent selEvent;
selEvent.fTime = event.GetStartTime();
selEvent.fNumber = event.GetNumber();
/// For pure digi based event, we select "continuous slices of digis"
/// => Copy block of [First Digi index, last digi index] with assign(it_start, it_stop)
/// => No data increase for most detectors as we use time window selection
/// Keep TRD1D + TRD2D support as single det, otherwise may lead to holes in the digi sequence!
/// => Need option to keep the loop to avoid adding extra digis if comparison to CbmEvents wanted
/// Get the proper order for block selection as TRD1D and TRD2D may insert indices in separate loops
/// => Needed to ensure that the start and stop of the block copy do not trigger a vector size exception
event.SortIndices();
/// for each detector, find the data in the Digi vectors and copy them
/// TODO: Template + loop on list of data types?
/// ==> Bmon
uint32_t uNbDigis = (0 < event.GetNofData(ECbmDataType::kBmonDigi) ? event.GetNofData(ECbmDataType::kBmonDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiBmon.begin() + event.GetIndex(ECbmDataType::kBmonDigi, 0);
auto stopIt = fvDigiBmon.begin() + event.GetIndex(ECbmDataType::kBmonDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fBmon.fDigis.assign(startIt, stopIt);
}
/// ==> STS
uNbDigis = (0 < event.GetNofData(ECbmDataType::kStsDigi) ? event.GetNofData(ECbmDataType::kStsDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiSts.begin() + event.GetIndex(ECbmDataType::kStsDigi, 0);
auto stopIt = fvDigiSts.begin() + event.GetIndex(ECbmDataType::kStsDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fSts.fDigis.assign(startIt, stopIt);
}
/// ==> MUCH
uNbDigis = (0 < event.GetNofData(ECbmDataType::kMuchDigi) ? event.GetNofData(ECbmDataType::kMuchDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiMuch.begin() + event.GetIndex(ECbmDataType::kMuchDigi, 0);
auto stopIt = fvDigiMuch.begin() + event.GetIndex(ECbmDataType::kMuchDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fMuch.fDigis.assign(startIt, stopIt);
}
/// ==> TRD + TRD2D
uNbDigis = (0 < event.GetNofData(ECbmDataType::kTrdDigi) ? event.GetNofData(ECbmDataType::kTrdDigi) : 0);
if (uNbDigis) {
if (bExclusiveTrdExtract) {
for (uint32_t uDigiInEvt = 0; uDigiInEvt < uNbDigis; ++uDigiInEvt) {
/// Copy each digi in the event by itself to make sure we skip ones outside their own selection window but
/// inside the selection window of the other TRD subsystem, effectively enforcing differetn windows:
/// [t, t+dt](TRD) = [t, t+dt](TRD1D) + [t, t+dt](TRD2D)
/// => Exclusive but slower
selEvent.fData.fTrd.fDigis.push_back(fvDigiTrd[event.GetIndex(ECbmDataType::kTrdDigi, uDigiInEvt)]);
}
}
else {
/// Block copy of all TRD digis, has feature that it may include digis which are not matching the selection
/// window of a given TRD subsystem, effectively making a larger selection window:
/// [t, t+dt](TRD) = [t, t+dt](TRD1D) U [t, t+dt](TRD2D)
/// => Faster but inclusive, will lead to more TRD hits and tracks than expected
auto startIt = fvDigiTrd.begin() + event.GetIndex(ECbmDataType::kTrdDigi, 0);
auto stopIt = fvDigiTrd.begin() + event.GetIndex(ECbmDataType::kTrdDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fTrd.fDigis.assign(startIt, stopIt);
}
}
/// ==> TOF
uNbDigis = (0 < event.GetNofData(ECbmDataType::kTofDigi) ? event.GetNofData(ECbmDataType::kTofDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiTof.begin() + event.GetIndex(ECbmDataType::kTofDigi, 0);
auto stopIt = fvDigiTof.begin() + event.GetIndex(ECbmDataType::kTofDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fTof.fDigis.assign(startIt, stopIt);
}
/// ==> RICH
uNbDigis = (0 < event.GetNofData(ECbmDataType::kRichDigi) ? event.GetNofData(ECbmDataType::kRichDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiRich.begin() + event.GetIndex(ECbmDataType::kRichDigi, 0);
auto stopIt = fvDigiRich.begin() + event.GetIndex(ECbmDataType::kRichDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fRich.fDigis.assign(startIt, stopIt);
}
/// ==> PSD
uNbDigis = (0 < event.GetNofData(ECbmDataType::kPsdDigi) ? event.GetNofData(ECbmDataType::kPsdDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiPsd.begin() + event.GetIndex(ECbmDataType::kPsdDigi, 0);
auto stopIt = fvDigiPsd.begin() + event.GetIndex(ECbmDataType::kPsdDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fPsd.fDigis.assign(startIt, stopIt);
}
fvDigiEvents.push_back(selEvent);
}
}
/* Copyright (C) 2020-2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceDigiEventSink.h
*
* @since 2020-05-04
* @author P.-A. Loizeau
*/
#ifndef CBMDEVICEDIGIEVTSINK_H_
#define CBMDEVICEDIGIEVTSINK_H_
/// CBM headers
#include "CbmBmonDigi.h"
#include "CbmDigiEvent.h"
#include "CbmEvent.h"
#include "CbmMqTMessage.h"
#include "CbmMuchDigi.h"
#include "CbmPsdDigi.h"
#include "CbmRichDigi.h"
#include "CbmStsDigi.h"
#include "CbmTofDigi.h"
#include "CbmTrdDigi.h"
#include "CbmTsEventHeader.h"
#include "TimesliceMetaData.h"
/// FAIRROOT headers
#include "FairMQDevice.h"
/// FAIRSOFT headers (geant, boost, ...)
#include "Rtypes.h"
#include "TClonesArray.h"
#include "TObjArray.h"
/// C/C++ headers
#include <chrono>
#include <map>
#include <vector>
class TCanvas;
class TFile;
class TH1;
class TProfile;
class TList;
class TClonesArray;
//class TimesliceMetaData;
class FairRunOnline;
class FairRootManager;
class CbmEventTimeslice {
/// TODO: rename to CbmTsWithEvents
public:
CbmEventTimeslice(FairMQParts& parts, bool bDigiEvtInput = false);
~CbmEventTimeslice();
void ExtractSelectedData(bool bExclusiveTrdExtract = true);
std::vector<CbmDigiEvent>& GetSelectedData(bool bExclusiveTrdExtract = true)
{
if (!fbDigiEvtInput) ExtractSelectedData(bExclusiveTrdExtract);
return fvDigiEvents;
}
/// Input Type
bool fbDigiEvtInput = false;
/// TS information in header
CbmTsEventHeader fCbmTsEventHeader;
/// Raw data
std::vector<CbmBmonDigi> fvDigiBmon;
std::vector<CbmStsDigi> fvDigiSts;
std::vector<CbmMuchDigi> fvDigiMuch;
std::vector<CbmTrdDigi> fvDigiTrd;
std::vector<CbmTofDigi> fvDigiTof;
std::vector<CbmRichDigi> fvDigiRich;
std::vector<CbmPsdDigi> fvDigiPsd;
/// extra Metadata
TimesliceMetaData fTsMetaData;
/// Raw events
std::vector<CbmEvent> fvEvents;
/// Digi events
std::vector<CbmDigiEvent> fvDigiEvents;
};
class CbmDeviceDigiEventSink : public FairMQDevice {
public:
CbmDeviceDigiEventSink();
virtual ~CbmDeviceDigiEventSink();
protected:
virtual void InitTask();
bool HandleMissTsData(FairMQMessagePtr&, int);
bool HandleData(FairMQParts&, int);
bool HandleCommand(FairMQMessagePtr&, int);
virtual void PostRun();
private:
/// Constants
/// Control flags
bool fbStoreFullTs = false; //! If true, store digis vectors with full TS in addition to selected events
bool fbBypassConsecutiveTs = false; //! Switch ON/OFF the bypass of the consecutive TS buffer before writing to file
bool fbWriteMissingTs = false; //! Switch ON/OFF writing of empty TS to file for the missing ones (if no bypass)
bool fbDisableCompression = false; //! Switch ON/OFF the ROOT file compression
bool fbDigiEventInput = false; //! Switch ON/OFF the input of CbmDigiEvents instead of raw data + CbmEvents
bool fbExclusiveTrdExtract = true; //! Switch ON/OFF loop based extraction of TRD digis due to 1D/2D
bool fbFillHistos = false; //! Switch ON/OFF filling of histograms
bool fbInitDone = false; //! Keep track of whether the Init was already fully completed
bool fbFinishDone = false; //! Keep track of whether the Finish was already called
/// User settings parameters
/// Algo enum settings
std::string fsOutputFileName = "mcbm_digis_events.root";
/// message queues
std::string fsChannelNameMissedTs = "missedts";
std::string fsChannelNameDataInput = "events";
std::string fsChannelNameCommands = "commands";
std::string fsChannelNameHistosInput = "histogram-in";
/// Output file/tree management
int64_t fiTreeFileMaxSize = 10000000000LL; //! Default value: ~10 GB
/// Histograms management
uint32_t fuPublishFreqTs = 100;
double_t fdMinPublishTime = 0.5;
double_t fdMaxPublishTime = 5.0;
std::string fsHistosSuffix = "";
/// List of MQ channels names
std::vector<std::string> fsAllowedChannels = {fsChannelNameDataInput};
/// Parameters management
// TList* fParCList = nullptr;
// Bool_t InitParameters( TList* fParCList );
/// Statistics & missed TS detection
uint64_t fuPrevTsIndex = 0;
uint64_t fulNumMessages = 0;
uint64_t fulTsCounter = 0;
uint64_t fulMissedTsCounter = 0;
uint64_t fulProcessedEvents = 0;
uint64_t fulLastFullTsCounter = 0;
uint64_t fulLastMissTsCounter = 0;
uint64_t fulLastProcessedEvents = 0;
std::chrono::system_clock::time_point fLastPublishTime = std::chrono::system_clock::now();
std::chrono::system_clock::time_point fLastFillTime = std::chrono::system_clock::now();
std::chrono::system_clock::time_point fStartTime = std::chrono::system_clock::now();
/// Control Commands reception
bool fbReceivedEof = false;
uint64_t fuLastTsIndex = 0;
uint64_t fuTotalTsCount = 0;
/// Data reception
/// Event (TS) header
CbmTsEventHeader* fEvtHeader = nullptr;
/// TS MetaData storage
TClonesArray* fTimeSliceMetaDataArray = nullptr; //!
// TimesliceMetaData* fTsMetaData = nullptr;
/// CbmEvents
std::vector<CbmDigiEvent>* fEventsSel = nullptr; //! output container of CbmEvents
/// Full TS Digis storage (optional usage, controlled by fbStoreFullTs!)
std::vector<CbmBmonDigi>* fvDigiBmon = nullptr;
std::vector<CbmStsDigi>* fvDigiSts = nullptr;
std::vector<CbmMuchDigi>* fvDigiMuch = nullptr;
std::vector<CbmTrdDigi>* fvDigiTrd = nullptr;
std::vector<CbmTofDigi>* fvDigiTof = nullptr;
std::vector<CbmRichDigi>* fvDigiRich = nullptr;
std::vector<CbmPsdDigi>* fvDigiPsd = nullptr;
/// Storage for re-ordering
/// Missed TS vector
std::vector<uint64_t> fvulMissedTsIndices = {};
/// Buffered TS
std::map<uint64_t, CbmEventTimeslice> fmFullTsStorage = {};
/// Data storage
FairRunOnline* fpRun = nullptr;
FairRootManager* fpFairRootMgr = nullptr;
/// Array of histograms to send to the histogram server
TObjArray fArrayHisto = {};
/// Vector of string pairs with ( HistoName, FolderPath ) to send to the histogram server
std::vector<std::pair<std::string, std::string>> fvpsHistosFolder = {};
/// Vector of string pairs with ( CanvasName, CanvasConfig ) to send to the histogram server
/// Format of Can config is "NbPadX(U);NbPadY(U);ConfigPad1(s);....;ConfigPadXY(s)"
/// Format of Pad config is "GrixX(b),GridY(b),LogX(b),LogY(b),LogZ(b),HistoName(s),DrawOptions(s)"
std::vector<std::pair<std::string, std::string>> fvpsCanvasConfig = {};
/// Flag indicating whether the histograms and canvases configurations were already published
bool fbConfigSent = false;
TProfile* fhFullTsBuffSizeEvo;
TProfile* fhMissTsBuffSizeEvo;
TH1* fhFullTsProcEvo;
TH1* fhMissTsProcEvo;
TH1* fhTotalTsProcEvo;
TH1* fhTotalEventsEvo;
TCanvas* fcEventSinkAllHist;
/// Internal methods
bool IsChannelNameAllowed(std::string channelName);
bool InitHistograms();
bool ResetHistograms(bool bResetStartTime = false);
void CheckTsQueues();
void PrepareTreeEntry(CbmEventTimeslice unpTs);
void DumpTreeEntry();
bool SendHistoConfAndData();
bool SendHistograms();
void Finish();
};
#endif /* CBMDEVICEDIGIEVTSINK_H_ */
/* Copyright (C) 2020 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceMcbmEventBuilderWin.cxx
*
* @since 2020-05-24
* @author P.-A. Loizeau
*/
#include "CbmDeviceMcbmEventBuilderWin.h"
/// CBM headers
#include "CbmEvent.h"
#include "CbmFlesCanvasTools.h"
#include "CbmMQDefs.h"
#include "CbmMatch.h"
#include "CbmMvdDigi.h"
#include "TimesliceMetaData.h"
/// FAIRROOT headers
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairParGenericSet.h"
#include "FairRunOnline.h"
#include "BoostSerializer.h"
#include "RootSerializer.h"
/// FAIRSOFT headers (geant, boost, ...)
#include "TCanvas.h"
#include "TFile.h"
#include "TH1.h"
#include "TList.h"
#include "TNamed.h"
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/utility.hpp>
/// C/C++ headers
#include <array>
#include <iomanip>
#include <stdexcept>
#include <string>
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
using namespace std;
//Bool_t bMcbm2018MonitorTaskBmonResetHistos = kFALSE;
CbmDeviceMcbmEventBuilderWin::CbmDeviceMcbmEventBuilderWin() { fpAlgo = new CbmMcbm2019TimeWinEventBuilderAlgo(); }
void CbmDeviceMcbmEventBuilderWin::InitTask()
try {
/// Read options from executable
LOG(info) << "Init options for CbmDeviceMcbmEventBuilderWin.";
fbFillHistos = fConfig->GetValue<bool>("FillHistos");
fbIgnoreTsOverlap = fConfig->GetValue<bool>("IgnOverMs");
fsEvtOverMode = fConfig->GetValue<std::string>("EvtOverMode");
fsRefDet = fConfig->GetValue<std::string>("RefDet");
fvsAddDet = fConfig->GetValue<std::vector<std::string>>("AddDet");
fvsDelDet = fConfig->GetValue<std::vector<std::string>>("DelDet");
fvsSetTrigWin = fConfig->GetValue<std::vector<std::string>>("SetTrigWin");
fvsSetTrigMinNb = fConfig->GetValue<std::vector<std::string>>("SetTrigMinNb");
fsChannelNameDataInput = fConfig->GetValue<std::string>("TsNameIn");
fsChannelNameDataOutput = fConfig->GetValue<std::string>("EvtNameOut");
fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
fsChannelNameHistosConfig = fConfig->GetValue<std::string>("ChNameHistCfg");
fsChannelNameCanvasConfig = fConfig->GetValue<std::string>("ChNameCanvCfg");
fsAllowedChannels[0] = fsChannelNameDataInput;
fuPublishFreqTs = fConfig->GetValue<uint32_t>("PubFreqTs");
fdMinPublishTime = fConfig->GetValue<double_t>("PubTimeMin");
fdMaxPublishTime = fConfig->GetValue<double_t>("PubTimeMax");
// 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
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
//logger::SetLogLevel("INFO");
int noChannel = fChannels.size();
LOG(info) << "Number of defined channels: " << noChannel;
for (auto const& entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
if (std::string::npos != entry.first.find(fsChannelNameDataInput)) {
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
OnData(entry.first, &CbmDeviceMcbmEventBuilderWin::HandleData);
} // if( entry.first.find( "ts" )
} // for( auto const &entry : fChannels )
// InitContainers();
/// FIXME: Disable clang formatting for now as it corrupts all alignment
/* clang-format off */
/// Initialize the Algorithm parameters
fpAlgo->SetFillHistos(fbFillHistos);
fpAlgo->SetIgnoreTsOverlap(fbIgnoreTsOverlap);
/// Extract Event Overlap Mode
EOverlapMode mode =
("NoOverlap" == fsEvtOverMode ? EOverlapMode::NoOverlap
: ("MergeOverlap" == fsEvtOverMode ? EOverlapMode::MergeOverlap
: ("AllowOverlap" == fsEvtOverMode ? EOverlapMode::AllowOverlap
: EOverlapMode::NoOverlap)));
fpAlgo->SetEventOverlapMode(mode);
/// Extract refdet
EventBuilderDetector refDet = ("kBmon" == fsRefDet ? kEventBuilderDetBmon
: ("kSts" == fsRefDet ? kEventBuilderDetSts
: ("kMuch" == fsRefDet ? kEventBuilderDetMuch
: ("kTrd" == fsRefDet ? kEventBuilderDetTrd
: ("kTof" == fsRefDet ? kEventBuilderDetTof
: ("kRich" == fsRefDet ? kEventBuilderDetRich
: ("kPsd" == fsRefDet ? kEventBuilderDetPsd
: kEventBuilderDetUndef)))))));
if (kEventBuilderDetUndef != refDet) {
fpAlgo->SetReferenceDetector(refDet);
} // if( kEventBuilderDetUndef != refDet )
else {
LOG(info) << "CbmDeviceMcbmEventBuilderWin::InitTask => Trying to change "
"reference to unsupported detector, ignored! "
<< fsRefDet;
} // else of if( kEventBuilderDetUndef != refDet
/// Extract detector to add if any
for (std::vector<std::string>::iterator itStrAdd = fvsAddDet.begin();
itStrAdd != fvsAddDet.end();
++itStrAdd) {
EventBuilderDetector addDet = ("kBmon" == *itStrAdd ? kEventBuilderDetBmon
: ("kSts" == *itStrAdd ? kEventBuilderDetSts
: ("kMuch" == *itStrAdd ? kEventBuilderDetMuch
: ("kTrd" == *itStrAdd ? kEventBuilderDetTrd
: ("kTof" == *itStrAdd ? kEventBuilderDetTof
: ("kRich" == *itStrAdd ? kEventBuilderDetRich
: ("kPsd" == *itStrAdd ? kEventBuilderDetPsd
: kEventBuilderDetUndef)))))));
if (kEventBuilderDetUndef != addDet) {
fpAlgo->AddDetector(addDet);
} // if( kEventBuilderDetUndef != addDet )
else {
LOG(info) << "CbmDeviceMcbmEventBuilderWin::InitTask => Trying to add "
"unsupported detector, ignored! "
<< (*itStrAdd);
continue;
} // else of if( kEventBuilderDetUndef != addDet )
} // for( std::vector< std::string >::iterator itStrAdd = fvsAddDet.begin(); itStrAdd != fvsAddDet.end(); ++itStrAdd )
/// Extract detector to remove if any
for (std::vector<std::string>::iterator itStrRem = fvsDelDet.begin();
itStrRem != fvsDelDet.end();
++itStrRem) {
EventBuilderDetector remDet = ("kBmon" == *itStrRem ? kEventBuilderDetBmon
: ("kSts" == *itStrRem ? kEventBuilderDetSts
: ("kMuch" == *itStrRem ? kEventBuilderDetMuch
: ("kTrd" == *itStrRem ? kEventBuilderDetTrd
: ("kTof" == *itStrRem ? kEventBuilderDetTof
: ("kRich" == *itStrRem ? kEventBuilderDetRich
: ("kPsd" == *itStrRem ? kEventBuilderDetPsd
: kEventBuilderDetUndef)))))));
if (kEventBuilderDetUndef != remDet) {
fpAlgo->RemoveDetector(remDet);
} // if( kEventBuilderDetUndef != remDet )
else {
LOG(info) << "CbmDeviceMcbmEventBuilderWin::InitTask => Trying to remove "
"unsupported detector, ignored! "
<< (*itStrRem);
continue;
} // else of if( kEventBuilderDetUndef != remDet )
} // for( std::vector< std::string >::iterator itStrAdd = fvsAddDet.begin(); itStrAdd != fvsAddDet.end(); ++itStrAdd )
/// Extract Trigger window to add if any
for (std::vector<std::string>::iterator itStrTrigWin = fvsSetTrigWin.begin();
itStrTrigWin != fvsSetTrigWin.end();
++itStrTrigWin) {
size_t charPosDel = (*itStrTrigWin).find(',');
if (std::string::npos == charPosDel) {
LOG(info)
<< "CbmDeviceMcbmEventBuilderWin::InitTask => "
<< "Trying to set trigger window with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found "
<< (*itStrTrigWin) << " )";
continue;
} // if( std::string::npos == charPosDel )
/// Detector Enum Tag
std::string sSelDet = (*itStrTrigWin).substr(0, charPosDel);
ECbmModuleId selDet = ("kBmon" == sSelDet ? ECbmModuleId::kBmon
: ("kSts" == sSelDet ? ECbmModuleId::kSts
: ("kMuch" == sSelDet ? ECbmModuleId::kMuch
: ("kTrd" == sSelDet ? ECbmModuleId::kTrd
: ("kTof" == sSelDet ? ECbmModuleId::kTof
: ("kRich" == sSelDet ? ECbmModuleId::kRich
: ("kPsd" == sSelDet ? ECbmModuleId::kPsd
: ECbmModuleId::kNotExist)))))));
if (ECbmModuleId::kNotExist == selDet) {
LOG(info)
<< "CbmDeviceMcbmEventBuilderWin::InitTask => "
<< "Trying to set trigger window for unsupported detector, ignored! "
<< sSelDet;
continue;
} // if( ECbmModuleId::kNotExist == selDet )
/// Window beginning
charPosDel++;
std::string sNext = (*itStrTrigWin).substr(charPosDel);
charPosDel = sNext.find(',');
if (std::string::npos == charPosDel) {
LOG(info)
<< "CbmDeviceMcbmEventBuilderWin::InitTask => "
<< "Trying to set trigger window with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found "
<< (*itStrTrigWin) << " )";
continue;
} // if( std::string::npos == charPosDel )
Double_t dWinBeg = std::stod(sNext.substr(0, charPosDel));
/// Window end
charPosDel++;
Double_t dWinEnd = std::stod(sNext.substr(charPosDel));
fpAlgo->SetTriggerWindow(selDet, dWinBeg, dWinEnd);
} // for( std::vector< std::string >::iterator itStrTrigWin = fvsSetTrigWin.begin(); itStrTrigWin != fvsSetTrigWin.end(); ++itStrTrigWin )
/// Extract MinNb for trigger if any
for (std::vector<std::string>::iterator itStrMinNb = fvsSetTrigMinNb.begin();
itStrMinNb != fvsSetTrigMinNb.end();
++itStrMinNb) {
size_t charPosDel = (*itStrMinNb).find(',');
if (std::string::npos == charPosDel) {
LOG(info)
<< "CbmDeviceMcbmEventBuilderWin::InitTask => "
<< "Trying to set trigger min Nb with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,uMinNb but instead found " << (*itStrMinNb)
<< " )";
continue;
} // if( std::string::npos == charPosDel )
/// Detector Enum Tag
std::string sSelDet = (*itStrMinNb).substr(0, charPosDel);
ECbmModuleId selDet = ("kBmon" == sSelDet ? ECbmModuleId::kBmon
: ("kSts" == sSelDet ? ECbmModuleId::kSts
: ("kMuch" == sSelDet ? ECbmModuleId::kMuch
: ("kTrd" == sSelDet ? ECbmModuleId::kTrd
: ("kTof" == sSelDet ? ECbmModuleId::kTof
: ("kRich" == sSelDet ? ECbmModuleId::kRich
: ("kPsd" == sSelDet ? ECbmModuleId::kPsd
: ECbmModuleId::kNotExist)))))));
if (ECbmModuleId::kNotExist == selDet) {
LOG(info)
<< "CbmDeviceMcbmEventBuilderWin::InitTask => "
<< "Trying to set trigger min Nb for unsupported detector, ignored! "
<< sSelDet;
continue;
} // if( ECbmModuleId::kNotExist == selDet )
/// Min number
charPosDel++;
UInt_t uMinNb = std::stoul((*itStrMinNb).substr(charPosDel));
fpAlgo->SetTriggerMinNumber(selDet, uMinNb);
} // for( std::vector< std::string >::iterator itStrMinNb = fvsSetTrigMinNb.begin(); itStrMinNb != fvsSetTrigMinNb.end(); ++itStrMinNb )
/// FIXME: Re-enable clang formatting after formatted lines
/* clang-format on */
/// Create input vectors
fvDigiBmon = new std::vector<CbmTofDigi>();
fvDigiSts = new std::vector<CbmStsDigi>();
fvDigiMuch = new std::vector<CbmMuchBeamTimeDigi>();
fvDigiTrd = new std::vector<CbmTrdDigi>();
fvDigiTof = new std::vector<CbmTofDigi>();
fvDigiRich = new std::vector<CbmRichDigi>();
fvDigiPsd = new std::vector<CbmPsdDigi>();
/// Register all input data members with the FairRoot manager
fpRun = new FairRunOnline(0);
FairRootManager* ioman = nullptr;
ioman = FairRootManager::Instance();
if (NULL == ioman) { throw InitTaskError("No FairRootManager instance"); }
fTimeSliceMetaDataArray = new TClonesArray("TimesliceMetaData", 1);
if (NULL == fTimeSliceMetaDataArray) { throw InitTaskError("Failed creating the TS meta data TClonesarray "); }
ioman->Register("TimesliceMetaData", "TS Meta Data", fTimeSliceMetaDataArray, kFALSE);
/// Digis storage
ioman->RegisterAny("BmonDigi", fvDigiBmon, kFALSE);
ioman->RegisterAny("StsDigi", fvDigiSts, kFALSE);
ioman->RegisterAny("MuchBeamTimeDigi", fvDigiMuch, kFALSE);
ioman->RegisterAny("TrdDigi", fvDigiTrd, kFALSE);
ioman->RegisterAny("TofDigi", fvDigiTof, kFALSE);
ioman->RegisterAny("RichDigi", fvDigiRich, kFALSE);
ioman->RegisterAny("PsdDigi", fvDigiPsd, kFALSE);
/// Feint to avoid crash of DigiManager due to missing source pointer
/// validity check in FairRootManager.h at line 461
std::vector<CbmMvdDigi>* pMvdDigi = new std::vector<CbmMvdDigi>();
ioman->RegisterAny("MvdDigi", pMvdDigi, kFALSE);
std::vector<CbmMatch>* pFakeMatch = new std::vector<CbmMatch>();
ioman->RegisterAny("MvdDigiMatch", pFakeMatch, kFALSE);
ioman->RegisterAny("StsDigiMatch", pFakeMatch, kFALSE);
ioman->RegisterAny("MuchBeamTimeDigiMatch", pFakeMatch, kFALSE);
ioman->RegisterAny("TrdDigiMatch", pFakeMatch, kFALSE);
ioman->RegisterAny("TofDigiMatch", pFakeMatch, kFALSE);
ioman->RegisterAny("RichDigiMatch", pFakeMatch, kFALSE);
ioman->RegisterAny("PsdDigiMatch", pFakeMatch, kFALSE);
/// Create output TClonesArray
/// TODO: remove TObject from CbmEvent and switch to vectors!
fEvents = new TClonesArray("CbmEvent", 500);
/// Now that everything is set, initialize the Algorithm
if (kFALSE == fpAlgo->InitAlgo()) {
throw InitTaskError("Failed to initilize the algorithm class.");
} // if( kFALSE == fpAlgo->InitAlgo() )
/// Histograms management
if (kTRUE == fbFillHistos) {
/// Obtain vector of pointers on each histo from the algo (+ optionally desired folder)
std::vector<std::pair<TNamed*, std::string>> vHistos = fpAlgo->GetHistoVector();
/// Obtain vector of pointers on each canvas from the algo (+ optionally desired folder)
std::vector<std::pair<TCanvas*, std::string>> vCanvases = fpAlgo->GetCanvasVector();
/// Add pointers to each histo in the histo array
/// Create histo config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Histo name, Folder >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto) {
// LOG(info) << "Registering " << vHistos[ uHisto ].first->GetName()
// << " in " << vHistos[ uHisto ].second.data()
// ;
fArrayHisto.Add(vHistos[uHisto].first);
std::pair<std::string, std::string> psHistoConfig(vHistos[uHisto].first->GetName(), vHistos[uHisto].second);
fvpsHistosFolder.push_back(psHistoConfig);
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, psHistoConfig);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist, psHistoConfig);
/// Send message to the common histogram config messages queue
if (Send(messageHist, fsChannelNameHistosConfig) < 0) {
throw InitTaskError("Problem sending histo config");
} // if( Send( messageHist, fsChannelNameHistosConfig ) < 0 )
LOG(info) << "Config of hist " << psHistoConfig.first.data() << " in folder " << psHistoConfig.second.data();
} // for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto )
/// Create canvas config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Canvas name, config >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv) {
// LOG(info) << "Registering " << vCanvases[ uCanv ].first->GetName()
// << " in " << vCanvases[ uCanv ].second.data();
std::string sCanvName = (vCanvases[uCanv].first)->GetName();
std::string sCanvConf = GenerateCanvasConfigString(vCanvases[uCanv].first);
std::pair<std::string, std::string> psCanvConfig(sCanvName, sCanvConf);
fvpsCanvasConfig.push_back(psCanvConfig);
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, psCanvConfig);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageCan, psCanvConfig);
/// Send message to the common canvas config messages queue
if (Send(messageCan, fsChannelNameCanvasConfig) < 0) {
throw InitTaskError("Problem sending canvas config");
} // if( Send( messageCan, fsChannelNameCanvasConfig ) < 0 )
LOG(info) << "Config string of Canvas " << psCanvConfig.first.data() << " is " << psCanvConfig.second.data();
} // for( UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv )
} // if( kTRUE == fbFillHistos )
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
}
bool CbmDeviceMcbmEventBuilderWin::IsChannelNameAllowed(std::string channelName)
{
for (auto const& entry : fsAllowedChannels) {
std::size_t pos1 = channelName.find(entry);
if (pos1 != std::string::npos) {
const vector<std::string>::const_iterator pos =
std::find(fsAllowedChannels.begin(), fsAllowedChannels.end(), entry);
const vector<std::string>::size_type idx = pos - fsAllowedChannels.begin();
LOG(info) << "Found " << entry << " in " << channelName;
LOG(info) << "Channel name " << channelName << " found in list of allowed channel names at position " << idx;
return true;
} // if (pos1!=std::string::npos)
} // for(auto const &entry : fsAllowedChannels)
LOG(info) << "Channel name " << channelName << " not found in list of allowed channel names.";
LOG(error) << "Stop device.";
return false;
}
/*
Bool_t CbmDeviceMcbmEventBuilderWin::InitContainers()
{
LOG(info) << "Init parameter containers for CbmDeviceMcbmEventBuilderWin.";
if( kFALSE == InitParameters( fpAlgo ->GetParList() ) )
return kFALSE;
/// Need to add accessors for all options
fpAlgo ->SetIgnoreOverlapMs( fbIgnoreOverlapMs );
Bool_t initOK = fpAlgo->InitContainers();
// Bool_t initOK = fMonitorAlgo->ReInitContainers();
return initOK;
}
Bool_t CbmDeviceMcbmEventBuilderWin::InitParameters( TList* fParCList )
{
for( int iparC = 0; iparC < fParCList->GetEntries(); iparC++ )
{
FairParGenericSet* tempObj = (FairParGenericSet*)( fParCList->At( iparC ) );
fParCList->Remove( tempObj );
std::string paramName{ tempObj->GetName() };
// NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
// Should only be used for small data because of the cost of an additional copy
// Her must come the proper Runid
std::string message = paramName + ",111";
LOG(info) << "Requesting parameter container " << paramName << ", sending message: " << message;
FairMQMessagePtr req( NewSimpleMessage(message) );
FairMQMessagePtr rep( NewMessage() );
FairParGenericSet* newObj = nullptr;
if( Send(req, "parameters") > 0 )
{
if( Receive( rep, "parameters" ) >= 0)
{
if( 0 != rep->GetSize() )
{
CbmMqTMessage tmsg( rep->GetData(), rep->GetSize() );
newObj = static_cast< FairParGenericSet* >( tmsg.ReadObject( tmsg.GetClass() ) );
LOG( info ) << "Received unpack parameter from the server:";
newObj->print();
} // if( 0 != rep->GetSize() )
else
{
LOG( error ) << "Received empty reply. Parameter not available";
return kFALSE;
} // else of if( 0 != rep->GetSize() )
} // if( Receive( rep, "parameters" ) >= 0)
} // if( Send(req, "parameters") > 0 )
fParCList->AddAt( newObj, iparC );
delete tempObj;
} // for( int iparC = 0; iparC < fParCList->GetEntries(); iparC++ )
return kTRUE;
}
*/
// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
bool CbmDeviceMcbmEventBuilderWin::HandleData(FairMQParts& parts, int /*index*/)
{
fulNumMessages++;
LOG(debug) << "Received message number " << fulNumMessages << " with " << parts.Size() << " parts"
<< ", size0: " << parts.At(0)->GetSize();
if (0 == fulNumMessages % 10000) LOG(info) << "Received " << fulNumMessages << " messages";
/// Extract unpacked data from input message
uint32_t uPartIdx = 0;
/// TS metadata
/// TODO: code order of vectors in the TS MetaData!!
/*
std::string msgStrTsMeta( static_cast< char * >( parts.At( uPartIdx )->GetData() ),
( parts.At( uPartIdx ) )->GetSize() );
std::istringstream issTsMeta(msgStrTsMeta);
boost::archive::binary_iarchive inputArchiveTsMeta(issTsMeta);
inputArchiveTsMeta >> (*fTsMetaData);
++uPartIdx;
*/
// Deserialize<RootSerializer>(*parts.At(uPartIdx), fTsMetaData);
RootSerializer().Deserialize(*parts.At(uPartIdx), fTsMetaData);
/// FIXME: Not if this is the proper way to insert the data
new ((*fTimeSliceMetaDataArray)[fTimeSliceMetaDataArray->GetEntriesFast()
// ] ) TimesliceMetaData( *fTsMetaData ) ;
]) TimesliceMetaData(std::move(*fTsMetaData));
++uPartIdx;
/// BMON
std::string msgStrBmon(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issBmon(msgStrBmon);
boost::archive::binary_iarchive inputArchiveBmon(issBmon);
inputArchiveBmon >> *fvDigiBmon;
++uPartIdx;
/// STS
std::string msgStrSts(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issSts(msgStrSts);
boost::archive::binary_iarchive inputArchiveSts(issSts);
inputArchiveSts >> *fvDigiSts;
++uPartIdx;
/// MUCH
std::string msgStrMuch(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issMuch(msgStrMuch);
boost::archive::binary_iarchive inputArchiveMuch(issMuch);
inputArchiveMuch >> *fvDigiMuch;
++uPartIdx;
/// TRD
std::string msgStrTrd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTrd(msgStrTrd);
boost::archive::binary_iarchive inputArchiveTrd(issTrd);
inputArchiveTrd >> *fvDigiTrd;
++uPartIdx;
/// TOF
std::string msgStrTof(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTof(msgStrTof);
boost::archive::binary_iarchive inputArchiveTof(issTof);
inputArchiveTof >> *fvDigiTof;
++uPartIdx;
/// RICH
std::string msgStrRich(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issRich(msgStrRich);
boost::archive::binary_iarchive inputArchiveRich(issRich);
inputArchiveRich >> *fvDigiRich;
++uPartIdx;
/// PSD
std::string msgStrPsd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issPsd(msgStrPsd);
boost::archive::binary_iarchive inputArchivePsd(issPsd);
inputArchivePsd >> *fvDigiPsd;
++uPartIdx;
/// Call Algo ProcessTs method
fpAlgo->ProcessTs();
/// Send events vector to ouput
if (!SendEvents(parts)) return false;
/// Clear metadata
fTimeSliceMetaDataArray->Clear();
// delete fTsMetaData;
/// Clear vectors
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
fvDigiTof->clear();
fvDigiRich->clear();
fvDigiPsd->clear();
/// Clear event vector after usage
fpAlgo->ClearEventVector();
fEvents->Clear("C");
// fEvents->Clear();
/// Histograms management
if (kTRUE == fbFillHistos) {
/// Send histograms each 100 time slices. Should be each ~1s
/// Use also runtime checker to trigger sending after M s if
/// processing too slow or delay sending if processing too fast
std::chrono::system_clock::time_point currentTime = std::chrono::system_clock::now();
std::chrono::duration<double_t> elapsedSeconds = currentTime - fLastPublishTime;
if ((fdMaxPublishTime < elapsedSeconds.count())
|| (0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count())) {
SendHistograms();
fLastPublishTime = std::chrono::system_clock::now();
} // if( ( fdMaxPublishTime < elapsedSeconds.count() ) || ( 0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count() ) )
} // if( kTRUE == fbFillHistos )
return true;
}
bool CbmDeviceMcbmEventBuilderWin::SendEvents(FairMQParts& partsIn)
{
/// Clear events TClonesArray before usage.
fEvents->Delete();
// fEvents->Clear();
/// Get vector reference from algo
std::vector<CbmEvent*> vEvents = fpAlgo->GetEventVector();
/// Move CbmEvent from temporary vector to TClonesArray
for (CbmEvent* event : vEvents) {
LOG(debug) << "Vector: " << event->ToString();
new ((*fEvents)[fEvents->GetEntriesFast()]) CbmEvent(std::move(*event));
// new ( (*fEvents)[fEvents->GetEntriesFast()] ) CbmEvent( *event );
LOG(debug) << "TClonesArray: " << static_cast<CbmEvent*>(fEvents->At(fEvents->GetEntriesFast() - 1))->ToString();
} // for( CbmEvent* event: vEvents )
/// Serialize the array of events into a single MQ message
FairMQMessagePtr message(NewMessage());
// Serialize<RootSerializer>(*message, fEvents);
RootSerializer().Serialize(*message, fEvents);
/// Add it at the end of the input composed message
/// FIXME: use move or fix addition of new part to avoid full message copy
FairMQParts partsOut(std::move(partsIn));
partsOut.AddPart(std::move(message));
// /// Get vector from algo
// fEventVector = fpAlgo->GetEventVector();
//
// /// Prepare serialized versions of the events vector
// std::stringstream ossEvents;
// boost::archive::binary_oarchive oaEvents(ossEvents);
// oaEvents << fpAlgo->GetEventVector();
// std::string* strMsgEvents = new std::string(ossEvents.str());
//
// /// Create message
// FairMQMessagePtr msg( NewMessage( const_cast< char * >( strMsgEvents->c_str() ), // data
// strMsgEvents->length(), // size
// []( void * /*data*/, void* object ){ delete static_cast< std::string * >( object ); },
// strMsgEvents ) ); // object that manages the data
/// Send message
// if( Send( message, fsChannelNameDataOutput ) < 0 )
if (Send(partsOut, fsChannelNameDataOutput) < 0) {
LOG(error) << "Problem sending data to " << fsChannelNameDataOutput;
return false;
}
return true;
}
bool CbmDeviceMcbmEventBuilderWin::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
// Serialize<RootSerializer>(*message, &fArrayHisto);
RootSerializer().Serialize(*message, &fArrayHisto);
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
LOG(error) << "Problem sending data";
return false;
} // if( Send( message, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
fpAlgo->ResetHistograms(kFALSE);
return true;
}
CbmDeviceMcbmEventBuilderWin::~CbmDeviceMcbmEventBuilderWin()
{
/// Clear metadata
fTimeSliceMetaDataArray->Clear();
delete fTsMetaData;
/// Clear vectors
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
fvDigiTof->clear();
fvDigiRich->clear();
fvDigiPsd->clear();
/// Clear events TClonesArray
fEvents->Delete();
delete fpRun;
delete fTimeSliceMetaDataArray;
delete fEvents;
delete fpAlgo;
}
void CbmDeviceMcbmEventBuilderWin::Finish() {}
/* Copyright (C) 2020 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceMcbmEventBuilderWin.h
*
* @since 2020-05-24
* @author P.-A. Loizeau
*/
#ifndef CBMDEVICEMCBMEVTBUILDERWIN_H_
#define CBMDEVICEMCBMEVTBUILDERWIN_H_
/// CBM headers
#include "CbmMcbm2019TimeWinEventBuilderAlgo.h"
#include "CbmMqTMessage.h"
#include "CbmMuchBeamTimeDigi.h"
#include "CbmPsdDigi.h"
#include "CbmRichDigi.h"
#include "CbmStsDigi.h"
#include "CbmTofDigi.h"
#include "CbmTrdDigi.h"
/// FAIRROOT headers
#include "FairMQDevice.h"
/// FAIRSOFT headers (geant, boost, ...)
#include "Rtypes.h"
#include "TObjArray.h"
/// C/C++ headers
#include <chrono>
#include <map>
#include <vector>
class TList;
class TClonesArray;
class FairRunOnline;
class TimesliceMetaData;
class CbmDeviceMcbmEventBuilderWin : public FairMQDevice {
public:
CbmDeviceMcbmEventBuilderWin();
virtual ~CbmDeviceMcbmEventBuilderWin();
protected:
virtual void InitTask();
bool HandleData(FairMQParts&, int);
bool HandleCommand(FairMQMessagePtr&, int);
private:
/// Constants
/// Control flags
Bool_t fbIgnoreTsOverlap = kFALSE; //! Ignore data in Overlap part of the TS
Bool_t fbFillHistos = kTRUE; //! Switch ON/OFF filling of histograms
/// User settings parameters
/// Algo enum settings
std::string fsEvtOverMode = "NoOverlap";
std::string fsRefDet = "kBmon";
std::vector<std::string> fvsAddDet = {};
std::vector<std::string> fvsDelDet = {};
std::vector<std::string> fvsSetTrigWin = {};
std::vector<std::string> fvsSetTrigMinNb = {};
/// message queues
std::string fsChannelNameDataInput = "unpts_0";
std::string fsChannelNameDataOutput = "events";
std::string fsChannelNameCommands = "commands";
std::string fsChannelNameHistosInput = "histogram-in";
std::string fsChannelNameHistosConfig = "histo-conf";
std::string fsChannelNameCanvasConfig = "canvas-conf";
/// Histograms management
uint32_t fuPublishFreqTs = 100;
double_t fdMinPublishTime = 0.5;
double_t fdMaxPublishTime = 5.0;
/// List of MQ channels names
std::vector<std::string> fsAllowedChannels = {fsChannelNameDataInput};
/// Parameters management
// TList* fParCList = nullptr;
// Bool_t InitParameters( TList* fParCList );
/// Statistics & first TS rejection
uint64_t fulNumMessages = 0;
uint64_t fulTsCounter = 0;
std::chrono::system_clock::time_point fLastPublishTime = std::chrono::system_clock::now();
/// Processing algos
CbmMcbm2019TimeWinEventBuilderAlgo* fpAlgo = nullptr;
/// TS MetaData stable values storage
size_t fuNbCoreMsPerTs = 0; //!
size_t fuNbOverMsPerTs = 0; //!
Double_t fdMsSizeInNs = 1280000; //! Size of a single MS, [nanoseconds]
Double_t fdTsCoreSizeInNs = -1.0; //! Total size of the core MS in a TS, [nanoseconds]
Double_t fdTsOverSizeInNs = -1.0; //! Total size of the overlap MS in a TS, [nanoseconds]
Double_t fdTsFullSizeInNs = -1.0; //! Total size of all MS in a TS, [nanoseconds]
/// Data reception
/// TS MetaData storage
TClonesArray* fTimeSliceMetaDataArray = nullptr; //!
TimesliceMetaData* fTsMetaData = nullptr;
/// Digis storage
std::vector<CbmTofDigi>* fvDigiBmon = nullptr;
std::vector<CbmStsDigi>* fvDigiSts = nullptr;
std::vector<CbmMuchBeamTimeDigi>* fvDigiMuch = nullptr;
std::vector<CbmTrdDigi>* fvDigiTrd = nullptr;
std::vector<CbmTofDigi>* fvDigiTof = nullptr;
std::vector<CbmRichDigi>* fvDigiRich = nullptr;
std::vector<CbmPsdDigi>* fvDigiPsd = nullptr;
/// Data emission
TClonesArray* fEvents = nullptr; //! output container of CbmEvents
// std::vector< CbmEvent * > & fEventVector; //! vector with all created events
/// Internal data registration (for FairRootManager -> DigiManager links)
FairRunOnline* fpRun = nullptr;
/// Array of histograms to send to the histogram server
TObjArray fArrayHisto = {};
/// Vector of string pairs with ( HistoName, FolderPath ) to send to the histogram server
std::vector<std::pair<std::string, std::string>> fvpsHistosFolder = {};
/// Vector of string pairs with ( CanvasName, CanvasConfig ) to send to the histogram server
/// Format of Can config is "NbPadX(U);NbPadY(U);ConfigPad1(s);....;ConfigPadXY(s)"
/// Format of Pad config is "GrixX(b),GridY(b),LogX(b),LogY(b),LogZ(b),HistoName(s),DrawOptions(s)"
std::vector<std::pair<std::string, std::string>> fvpsCanvasConfig = {};
bool IsChannelNameAllowed(std::string channelName);
// Bool_t InitContainers();
void Finish();
bool SendEvents(FairMQParts& partsIn);
bool SendHistograms();
};
#endif /* CBMDEVICEMCBMEVTBUILDERWIN_H_ */
/* Copyright (C) 2020-2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceMcbmEventSink.cxx
*
* @since 2020-05-24
* @author P.-A. Loizeau
*/
#include "CbmDeviceMcbmEventSink.h"
/// CBM headers
#include "CbmEvent.h"
#include "CbmFlesCanvasTools.h"
#include "CbmMQDefs.h"
#include "TimesliceMetaData.h"
/// FAIRROOT headers
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairParGenericSet.h"
#include "FairRootFileSink.h"
#include "FairRootManager.h"
#include "FairRunOnline.h"
#include "BoostSerializer.h"
#include "RootSerializer.h"
/// FAIRSOFT headers (geant, boost, ...)
#include "TCanvas.h"
#include "TFile.h"
#include "TH1.h"
#include "TList.h"
#include "TNamed.h"
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/utility.hpp>
/// C/C++ headers
#include <thread> // this_thread::sleep_for
#include <array>
#include <iomanip>
#include <stdexcept>
#include <string>
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
using namespace std;
//Bool_t bMcbm2018MonitorTaskBmonResetHistos = kFALSE;
CbmDeviceMcbmEventSink::CbmDeviceMcbmEventSink() {}
void CbmDeviceMcbmEventSink::InitTask()
try {
/// Read options from executable
LOG(info) << "Init options for CbmDeviceMcbmEventSink.";
fsOutputFileName = fConfig->GetValue<std::string>("OutFileName");
fsChannelNameDataInput = fConfig->GetValue<std::string>("EvtNameIn");
fsAllowedChannels[0] = fsChannelNameDataInput;
fbFillHistos = fConfig->GetValue<bool>("FillHistos");
fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
fsChannelNameHistosConfig = fConfig->GetValue<std::string>("ChNameHistCfg");
fsChannelNameCanvasConfig = fConfig->GetValue<std::string>("ChNameCanvCfg");
fuPublishFreqTs = fConfig->GetValue<uint32_t>("PubFreqTs");
fdMinPublishTime = fConfig->GetValue<double_t>("PubTimeMin");
fdMaxPublishTime = fConfig->GetValue<double_t>("PubTimeMax");
/// Associate the MissedTs Channel to the corresponding handler
OnData(fsChannelNameMissedTs, &CbmDeviceMcbmEventSink::HandleMissTsData);
/// Associate the command Channel to the corresponding handler
OnData(fsChannelNameCommands, &CbmDeviceMcbmEventSink::HandleCommand);
/// Associate the Event + Unp data Channel to the corresponding handler
// 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
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
//logger::SetLogLevel("INFO");
int noChannel = fChannels.size();
LOG(info) << "Number of defined channels: " << noChannel;
for (auto const& entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
if (std::string::npos != entry.first.find(fsChannelNameDataInput)) {
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
OnData(entry.first, &CbmDeviceMcbmEventSink::HandleData);
} // if( entry.first.find( "ts" )
} // for( auto const &entry : fChannels )
// InitContainers();
/// Create input vectors
fvDigiBmon = new std::vector<CbmTofDigi>();
fvDigiSts = new std::vector<CbmStsDigi>();
fvDigiMuch = new std::vector<CbmMuchBeamTimeDigi>();
fvDigiTrd = new std::vector<CbmTrdDigi>();
fvDigiTof = new std::vector<CbmTofDigi>();
fvDigiRich = new std::vector<CbmRichDigi>();
fvDigiPsd = new std::vector<CbmPsdDigi>();
/// Prepare storage TClonesArrays
/// TS MetaData storage
fTimeSliceMetaDataArray = new TClonesArray("TimesliceMetaData", 1);
if (NULL == fTimeSliceMetaDataArray) {
throw InitTaskError("Failed creating the TS meta data TClonesarray ");
} // if( NULL == fTimeSliceMetaDataArray )
/// Events storage
/// TODO: remove TObject from CbmEvent and switch to vectors!
fEventsArray = new TClonesArray("CbmEvent", 500);
if (NULL == fEventsArray) {
throw InitTaskError("Failed creating the Events TClonesarray ");
} // if( NULL == fEventsArray )
/// Prepare root output
if ("" != fsOutputFileName) {
fpRun = new FairRunOnline();
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();
// fEvtHeader = new FairEventHeader();
// fEvtHeader->SetRunId(iRunId);
// rootMgr->Register("EventHeader.", "Event", fEvtHeader, kTRUE);
// rootMgr->FillEventHeader(fEvtHeader);
/// Register all input data members with the FairRoot manager
/// TS MetaData
fpFairRootMgr->Register("TimesliceMetaData", "TS Meta Data", fTimeSliceMetaDataArray, kTRUE);
/// Digis storage
fpFairRootMgr->RegisterAny("BmonDigi", fvDigiBmon, kTRUE);
fpFairRootMgr->RegisterAny("StsDigi", fvDigiSts, kTRUE);
fpFairRootMgr->RegisterAny("MuchBeamTimeDigi", fvDigiMuch, kTRUE);
fpFairRootMgr->RegisterAny("TrdDigi", fvDigiTrd, kTRUE);
fpFairRootMgr->RegisterAny("TofDigi", fvDigiTof, kTRUE);
fpFairRootMgr->RegisterAny("RichDigi", fvDigiRich, kTRUE);
fpFairRootMgr->RegisterAny("PsdDigi", fvDigiPsd, kTRUE);
/// CbmEvent
fpFairRootMgr->Register("CbmEvent", "Cbm Event", fEventsArray, kTRUE);
/*
TTree* outTree =new TTree(FairRootManager::GetTreeName(), "/cbmout", 99);
LOG(info) << "define Tree " << outTree->GetName();
fpFairRootMgr->GetSink()->SetOutTree(outTree);
*/
fpFairRootMgr->WriteFolder();
LOG(info) << "Initialized outTree with rootMgr at " << fpFairRootMgr;
/// Histograms management
if (kTRUE == fbFillHistos) {
/*
/// Obtain vector of pointers on each histo from the algo (+ optionally desired folder)
std::vector< std::pair< TNamed *, std::string > > vHistos = fpAlgo->GetHistoVector();
/// Obtain vector of pointers on each canvas from the algo (+ optionally desired folder)
std::vector< std::pair< TCanvas *, std::string > > vCanvases = fpAlgo->GetCanvasVector();
/// Add pointers to each histo in the histo array
/// Create histo config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Histo name, Folder >
/// and send it through a separate channel using the BoostSerializer
for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto )
{
// LOG(info) << "Registering " << vHistos[ uHisto ].first->GetName()
// << " in " << vHistos[ uHisto ].second.data()
// ;
fArrayHisto.Add( vHistos[ uHisto ].first );
std::pair< std::string, std::string > psHistoConfig( vHistos[ uHisto ].first->GetName(),
vHistos[ uHisto ].second );
fvpsHistosFolder.push_back( psHistoConfig );
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist( NewMessage() );
// Serialize< BoostSerializer < std::pair< std::string, std::string > > >( *messageHist, psHistoConfig );
BoostSerializer < std::pair< std::string, std::string > >.Serialize( *messageHist, psHistoConfig );
/// Send message to the common histogram config messages queue
if( Send( messageHist, fsChannelNameHistosConfig ) < 0 )
{
throw InitTaskError( "Problem sending histo config" );
} // if( Send( messageHist, fsChannelNameHistosConfig ) < 0 )
LOG(info) << "Config of hist " << psHistoConfig.first.data()
<< " in folder " << psHistoConfig.second.data() ;
} // for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto )
/// Create canvas config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Canvas name, config >
/// and send it through a separate channel using the BoostSerializer
for( UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv )
{
// LOG(info) << "Registering " << vCanvases[ uCanv ].first->GetName()
// << " in " << vCanvases[ uCanv ].second.data();
std::string sCanvName = (vCanvases[ uCanv ].first)->GetName();
std::string sCanvConf = GenerateCanvasConfigString( vCanvases[ uCanv ].first );
std::pair< std::string, std::string > psCanvConfig( sCanvName, sCanvConf );
fvpsCanvasConfig.push_back( psCanvConfig );
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan( NewMessage() );
// Serialize< BoostSerializer < std::pair< std::string, std::string > > >( *messageCan, psCanvConfig );
BoostSerializer < std::pair< std::string, std::string > >.Serialize( *messageCan, psCanvConfig );
/// Send message to the common canvas config messages queue
if( Send( messageCan, fsChannelNameCanvasConfig ) < 0 )
{
throw InitTaskError( "Problem sending canvas config" );
} // if( Send( messageCan, fsChannelNameCanvasConfig ) < 0 )
LOG(info) << "Config string of Canvas " << psCanvConfig.first.data()
<< " is " << psCanvConfig.second.data() ;
} // for( UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv )
*/
} // if( kTRUE == fbFillHistos )
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
}
bool CbmDeviceMcbmEventSink::IsChannelNameAllowed(std::string channelName)
{
for (auto const& entry : fsAllowedChannels) {
std::size_t pos1 = channelName.find(entry);
if (pos1 != std::string::npos) {
const vector<std::string>::const_iterator pos =
std::find(fsAllowedChannels.begin(), fsAllowedChannels.end(), entry);
const vector<std::string>::size_type idx = pos - fsAllowedChannels.begin();
LOG(info) << "Found " << entry << " in " << channelName;
LOG(info) << "Channel name " << channelName << " found in list of allowed channel names at position " << idx;
return true;
} // if (pos1!=std::string::npos)
} // for(auto const &entry : fsAllowedChannels)
LOG(info) << "Channel name " << channelName << " not found in list of allowed channel names.";
LOG(error) << "Stop device.";
return false;
}
/*
Bool_t CbmDeviceMcbmEventSink::InitContainers()
{
LOG(info) << "Init parameter containers for CbmDeviceMcbmEventSink.";
if( kFALSE == InitParameters( fpAlgo ->GetParList() ) )
return kFALSE;
/// Need to add accessors for all options
fpAlgo ->SetIgnoreOverlapMs( fbIgnoreOverlapMs );
Bool_t initOK = fpAlgo->InitContainers();
// Bool_t initOK = fMonitorAlgo->ReInitContainers();
return initOK;
}
Bool_t CbmDeviceMcbmEventSink::InitParameters( TList* fParCList )
{
for( int iparC = 0; iparC < fParCList->GetEntries(); iparC++ )
{
FairParGenericSet* tempObj = (FairParGenericSet*)( fParCList->At( iparC ) );
fParCList->Remove( tempObj );
std::string paramName{ tempObj->GetName() };
// NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
// Should only be used for small data because of the cost of an additional copy
// Her must come the proper Runid
std::string message = paramName + ",111";
LOG(info) << "Requesting parameter container " << paramName << ", sending message: " << message;
FairMQMessagePtr req( NewSimpleMessage(message) );
FairMQMessagePtr rep( NewMessage() );
FairParGenericSet* newObj = nullptr;
if( Send(req, "parameters") > 0 )
{
if( Receive( rep, "parameters" ) >= 0)
{
if( 0 != rep->GetSize() )
{
CbmMqTMessage tmsg( rep->GetData(), rep->GetSize() );
newObj = static_cast< FairParGenericSet* >( tmsg.ReadObject( tmsg.GetClass() ) );
LOG( info ) << "Received unpack parameter from the server:";
newObj->print();
} // if( 0 != rep->GetSize() )
else
{
LOG( error ) << "Received empty reply. Parameter not available";
return kFALSE;
} // else of if( 0 != rep->GetSize() )
} // if( Receive( rep, "parameters" ) >= 0)
} // if( Send(req, "parameters") > 0 )
fParCList->AddAt( newObj, iparC );
delete tempObj;
} // for( int iparC = 0; iparC < fParCList->GetEntries(); iparC++ )
return kTRUE;
}
*/
//--------------------------------------------------------------------//
// handler is called whenever a message arrives on fsChannelNameMissedTs, with a reference to the message and a sub-channel index (here 0)
bool CbmDeviceMcbmEventSink::HandleMissTsData(FairMQMessagePtr& msg, int /*index*/)
{
std::vector<uint64_t> vIndices;
std::string msgStrMissTs(static_cast<char*>(msg->GetData()), msg->GetSize());
std::istringstream issMissTs(msgStrMissTs);
boost::archive::binary_iarchive inputArchiveMissTs(issMissTs);
inputArchiveMissTs >> vIndices;
fvulMissedTsIndices.insert(fvulMissedTsIndices.end(), vIndices.begin(), vIndices.end());
/// Check TS queue and process it if needed (in case it filled a hole!)
CheckTsQueues();
return true;
}
//--------------------------------------------------------------------//
// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
bool CbmDeviceMcbmEventSink::HandleData(FairMQParts& parts, int /*index*/)
{
fulNumMessages++;
LOG(debug) << "Received message number " << fulNumMessages << " with " << parts.Size() << " parts"
<< ", size0: " << parts.At(0)->GetSize();
if (0 == fulNumMessages % 10000) LOG(info) << "Received " << fulNumMessages << " messages";
/// Extract unpacked data from input message
uint32_t uPartIdx = 0;
/// TS metadata
/// TODO: code order of vectors in the TS MetaData!!
/*
std::string msgStrTsMeta( static_cast< char * >( parts.At( uPartIdx )->GetData() ),
( parts.At( uPartIdx ) )->GetSize() );
std::istringstream issTsMeta(msgStrTsMeta);
boost::archive::binary_iarchive inputArchiveTsMeta(issTsMeta);
inputArchiveTsMeta >> (*fTsMetaData);
++uPartIdx;
*/
// Deserialize<RootSerializer>(*parts.At(uPartIdx), fTsMetaData);
RootSerializer().Deserialize(*parts.At(uPartIdx), fTsMetaData);
LOG(debug) << "TS metadata extracted";
/// FIXME: Need to check if TS arrived in order (probably not!!!) + buffer!!!
if (fuPrevTsIndex + 1 == fTsMetaData->GetIndex()
|| (0 == fuPrevTsIndex && 0 == fulTsCounter && 0 == fTsMetaData->GetIndex())) {
LOG(debug) << "TS direct to dump";
/// Fill all storage variables registers for data output
PrepareTreeEntry(parts);
/// Trigger FairRoot manager to dump Tree entry
DumpTreeEntry();
/// Update counters
fuPrevTsIndex = fTsMetaData->GetIndex();
fulTsCounter++;
} // if( fuPrevTsIndex + 1 == fTsMetaData->GetIndex() || ( 0 == fuPrevTsIndex && 0 == fulTsCounter ) )
else {
LOG(debug) << "TS direct to storage";
/// If not consecutive to last TS sent,
fmFullTsStorage.emplace_hint(fmFullTsStorage.end(), std::pair<uint64_t, CbmUnpackedTimeslice>(
fTsMetaData->GetIndex(), CbmUnpackedTimeslice(parts)));
} // else of if( fuPrevTsIndex + 1 == fTsMetaData->GetIndex() || ( 0 == fuPrevTsIndex && 0 == fulTsCounter && 0 == fTsMetaData->GetIndex() )
LOG(debug) << "TS metadata checked";
/// Clear metadata => crashes, maybe not needed as due to move the pointer is invalidated?
// delete fTsMetaData;
/// Check TS queue and process it if needed (in case it filled a hole!)
CheckTsQueues();
LOG(debug) << "TS queues checked";
/// Histograms management
if (kTRUE == fbFillHistos) {
/// Send histograms each 100 time slices. Should be each ~1s
/// Use also runtime checker to trigger sending after M s if
/// processing too slow or delay sending if processing too fast
std::chrono::system_clock::time_point currentTime = std::chrono::system_clock::now();
std::chrono::duration<double_t> elapsedSeconds = currentTime - fLastPublishTime;
if ((fdMaxPublishTime < elapsedSeconds.count())
|| (0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count())) {
SendHistograms();
fLastPublishTime = std::chrono::system_clock::now();
} // if( ( fdMaxPublishTime < elapsedSeconds.count() ) || ( 0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count() ) )
} // if( kTRUE == fbFillHistos )
return true;
}
//--------------------------------------------------------------------//
bool CbmDeviceMcbmEventSink::HandleCommand(FairMQMessagePtr& msg, int /*index*/)
{
/*
std::string sCommand( static_cast< char * >( msg->GetData() ),
msg->GetSize() );
*/
std::string sCommand;
std::string msgStrCmd(static_cast<char*>(msg->GetData()), msg->GetSize());
std::istringstream issCmd(msgStrCmd);
boost::archive::binary_iarchive inputArchiveCmd(issCmd);
inputArchiveCmd >> sCommand;
std::string sCmdTag = sCommand;
size_t charPosDel = sCommand.find(' ');
if (std::string::npos != charPosDel) {
sCmdTag = sCommand.substr(0, charPosDel);
} // if( std::string::npos != charPosDel )
if ("EOF" == sCmdTag) {
fbReceivedEof = true;
/// Extract the last TS index and global full TS count
if (std::string::npos == charPosDel) {
LOG(fatal) << "CbmDeviceMcbmEventSink::HandleCommand => "
<< "Incomplete EOF command received: " << sCommand;
return false;
} // if( std::string::npos == charPosDel )
/// Last TS index
charPosDel++;
std::string sNext = sCommand.substr(charPosDel);
charPosDel = sNext.find(' ');
if (std::string::npos == charPosDel) {
LOG(fatal) << "CbmDeviceMcbmEventSink::HandleCommand => "
<< "Incomplete EOF command received: " << sCommand;
return false;
} // if( std::string::npos == charPosDel )
fuLastTsIndex = std::stoul(sNext.substr(0, charPosDel));
/// Total TS count
charPosDel++;
fuTotalTsCount = std::stoul(sNext.substr(charPosDel));
LOG(info) << "CbmDeviceMcbmEventSink::HandleCommand => "
<< "Received EOF command with final TS index " << fuLastTsIndex << " and total nb TS " << fuTotalTsCount;
/// End of data: clean save of data + close file + send last state of histos if enabled
if (fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount) {
LOG(info) << "CbmDeviceMcbmEventSink::HandleCommand => "
<< "Found final TS index " << fuLastTsIndex << " and total nb TS " << fuTotalTsCount;
Finish();
} // if( fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount )
} // if( "EOF" == sCmdTag )
else if ("STOP" == sCmdTag) {
/// TODO: different treatment in case of "BAD" ending compared to EOF?
/// Source failure: clean save of received data + close file + send last state of histos if enabled
Finish();
} // else if( "STOP" == sCmdTag )
else {
LOG(warning) << "Unknown command received: " << sCmdTag << " => will be ignored!";
} // else if command not recognized
return true;
}
//--------------------------------------------------------------------//
void CbmDeviceMcbmEventSink::CheckTsQueues()
{
bool bHoleFoundInBothQueues = false;
std::map<uint64_t, CbmUnpackedTimeslice>::iterator itFullTs = fmFullTsStorage.begin();
std::vector<uint64_t>::iterator itMissTs = fvulMissedTsIndices.begin();
while (!bHoleFoundInBothQueues) {
/// Check if the first TS in the full TS queue is the next one
if (fmFullTsStorage.end() != itFullTs && fuPrevTsIndex + 1 == (*itFullTs).first) {
/// Fill all storage variables registers for data output
PrepareTreeEntry((*itFullTs).second);
/// Trigger FairRoot manager to dump Tree entry
DumpTreeEntry();
/// Update counters
fuPrevTsIndex = (*itFullTs).first;
fulTsCounter++;
/// Increment iterator
++itFullTs;
continue;
} // if( fmFullTsStorage.end() != itFullTs && fuPrevTsIndex + 1 == (*itFullTs).first() )
/// Check if the first TS in the missed TS queue is the next one
if (fvulMissedTsIndices.end() != itMissTs && fuPrevTsIndex + 1 == (*itMissTs)) {
/// Prepare entry with only dummy TS metadata and empty storage variables
new ((*fTimeSliceMetaDataArray)[fTimeSliceMetaDataArray->GetEntriesFast()])
TimesliceMetaData(0, 0, 0, (*itMissTs));
/// Trigger FairRoot manager to dump Tree entry
DumpTreeEntry();
/// Update counters
fuPrevTsIndex = (*itMissTs);
fulMissedTsCounter++;
/// Increment iterator
++itMissTs;
continue;
} // if( fvulMissedTsIndices.end() != itMissTs && fuPrevTsIndex + 1 == (*itMissTs ) )
/// Should be reached only if both queues at the end or hole found in both
bHoleFoundInBothQueues = true;
} // while( !bHoleFoundInBothQueues )
/// Delete the processed entries
fmFullTsStorage.erase(fmFullTsStorage.begin(), itFullTs);
fvulMissedTsIndices.erase(fvulMissedTsIndices.begin(), itMissTs);
/// End of data: clean save of data + close file + send last state of histos if enabled
if (fbReceivedEof && fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount) {
LOG(info) << "CbmDeviceMcbmEventSink::CheckTsQueues => "
<< "Found final TS index " << fuLastTsIndex << " and total nb TS " << fuTotalTsCount;
Finish();
} // if( fbReceivedEof && fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount )
}
//--------------------------------------------------------------------//
void CbmDeviceMcbmEventSink::PrepareTreeEntry(CbmUnpackedTimeslice unpTs)
{
/// FIXME: poor man solution with lots of data copy until we undertsnad how to properly deal
/// with FairMq messages ownership and memory managment
/// FIXME: Not sure if this is the proper way to insert the data
new ((*fTimeSliceMetaDataArray)[fTimeSliceMetaDataArray->GetEntriesFast()])
TimesliceMetaData(std::move(unpTs.fTsMetaData));
/*
/// Explicit copy version: safe but slow
/// Bmon
fvDigiBmon->insert( fvDigiBmon->end(), unpTs.fvDigiBmon.begin(), unpTs.fvDigiBmon.end() );
/// STS
fvDigiSts->insert( fvDigiSts->end(), unpTs.fvDigiSts.begin(), unpTs.fvDigiSts.end() );
/// MUCH
fvDigiMuch->insert( fvDigiMuch->end(), unpTs.fvDigiMuch.begin(), unpTs.fvDigiMuch.end() );
/// TRD
fvDigiTrd->insert( fvDigiTrd->end(), unpTs.fvDigiTrd.begin(), unpTs.fvDigiTrd.end() );
/// BmonF
fvDigiTof->insert( fvDigiTof->end(), unpTs.fvDigiTof.begin(), unpTs.fvDigiTof.end() );
/// RICH
fvDigiRich->insert( fvDigiRich->end(), unpTs.fvDigiRich.begin(), unpTs.fvDigiRich.end() );
/// PSD
fvDigiPsd->insert( fvDigiPsd->end(), unpTs.fvDigiPsd.begin(), unpTs.fvDigiPsd.end() );
*/
/// move version: safe but slow
/// Bmon
(*fvDigiBmon) = std::move(unpTs.fvDigiBmon);
/// STS
(*fvDigiSts) = std::move(unpTs.fvDigiSts);
/// MUCH
(*fvDigiMuch) = std::move(unpTs.fvDigiMuch);
/// TRD
(*fvDigiTrd) = std::move(unpTs.fvDigiTrd);
/// BmonF
(*fvDigiTof) = std::move(unpTs.fvDigiTof);
/// RICH
(*fvDigiRich) = std::move(unpTs.fvDigiRich);
/// PSD
(*fvDigiPsd) = std::move(unpTs.fvDigiPsd);
/// Extract CbmEvent TClonesArray from input message
fEventsArray->AbsorbObjects(&(unpTs.fEventsArray));
}
void CbmDeviceMcbmEventSink::DumpTreeEntry()
{
// Unpacked digis + CbmEvent output to root file
/*
* NH style
// fpFairRootMgr->FillEventHeader(fEvtHeader);
// LOG(info) << "Fill WriteOutBuffer with FairRootManager at " << fpFairRootMgr;
// fpOutRootFile->cd();
fpFairRootMgr->Fill();
fpFairRootMgr->StoreWriteoutBufferData( fpFairRootMgr->GetEventTime() );
//fpFairRootMgr->StoreAllWriteoutBufferData();
fpFairRootMgr->DeleteOldWriteoutBufferData();
*/
/// FairRunOnline style
fpFairRootMgr->StoreWriteoutBufferData(fpFairRootMgr->GetEventTime());
fpFairRootMgr->Fill();
fpFairRootMgr->DeleteOldWriteoutBufferData();
/// Clear metadata array
fTimeSliceMetaDataArray->Clear();
/// Clear vectors
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
fvDigiTof->clear();
fvDigiRich->clear();
fvDigiPsd->clear();
/// Clear event array
// fEventsArray->Delete();
fEventsArray->Clear("C");
// fEventsArray->Clear();
}
//--------------------------------------------------------------------//
bool CbmDeviceMcbmEventSink::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
// Serialize<RootSerializer>(*message, &fArrayHisto);
RootSerializer().Serialize(*message, &fArrayHisto);
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
LOG(error) << "Problem sending data";
return false;
} // if( Send( message, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
// fpAlgo->ResetHistograms( kFALSE );
return true;
}
//--------------------------------------------------------------------//
CbmDeviceMcbmEventSink::~CbmDeviceMcbmEventSink()
{
/// FIXME: Add pointers check before delete
/// Close things properly if not alredy done
if (!fbFinishDone) Finish();
/// Clear metadata
fTimeSliceMetaDataArray->Clear();
delete fTimeSliceMetaDataArray;
delete fTsMetaData;
/// Clear vectors
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
fvDigiTof->clear();
fvDigiRich->clear();
fvDigiPsd->clear();
/// Clear events TClonesArray
fEventsArray->Clear();
delete fEventsArray;
delete fpRun;
}
void CbmDeviceMcbmEventSink::Finish()
{
// Clean closure of output to root file
fpFairRootMgr->Write();
// fpFairRootMgr->GetSource()->Close();
fpFairRootMgr->CloseSink();
LOG(info) << "File closed after saving " << (fulTsCounter + fulMissedTsCounter) << " TS (" << fulTsCounter
<< " full ones and " << fulMissedTsCounter << " missed/empty ones)";
if (kTRUE == fbFillHistos) {
SendHistograms();
fLastPublishTime = std::chrono::system_clock::now();
} // if( kTRUE == fbFillHistos )
ChangeState(fair::mq::Transition::Stop);
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
ChangeState(fair::mq::Transition::End);
fbFinishDone = kTRUE;
}
CbmUnpackedTimeslice::CbmUnpackedTimeslice(FairMQParts& parts) : fEventsArray("CbmEvent", 500)
{
/// Extract unpacked data from input message
uint32_t uPartIdx = 0;
/// TS metadata
/// TODO: code order of vectors in the TS MetaData!!
/*
std::string msgStrTsMeta( static_cast< char * >( parts.At( uPartIdx )->GetData() ),
( parts.At( uPartIdx ) )->GetSize() );
std::istringstream issTsMeta(msgStrTsMeta);
boost::archive::binary_iarchive inputArchiveTsMeta(issTsMeta);
inputArchiveTsMeta >> (*fTsMetaData);
++uPartIdx;
*/
TObject* tempObjectMeta = nullptr;
RootSerializer().Deserialize(*parts.At(uPartIdx), tempObjectMeta);
++uPartIdx;
if (TString(tempObjectMeta->ClassName()).EqualTo("TimesliceMetaData")) {
fTsMetaData = *(static_cast<TimesliceMetaData*>(tempObjectMeta));
} // if( TString( tempObject->ClassName() ).EqualTo( "TClonesArray") )
/// Bmon
std::string msgStrBmon(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issBmon(msgStrBmon);
boost::archive::binary_iarchive inputArchiveBmon(issBmon);
inputArchiveBmon >> fvDigiBmon;
++uPartIdx;
/// STS
std::string msgStrSts(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issSts(msgStrSts);
boost::archive::binary_iarchive inputArchiveSts(issSts);
inputArchiveSts >> fvDigiSts;
++uPartIdx;
/// MUCH
std::string msgStrMuch(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issMuch(msgStrMuch);
boost::archive::binary_iarchive inputArchiveMuch(issMuch);
inputArchiveMuch >> fvDigiMuch;
++uPartIdx;
/// TRD
std::string msgStrTrd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTrd(msgStrTrd);
boost::archive::binary_iarchive inputArchiveTrd(issTrd);
inputArchiveTrd >> fvDigiTrd;
++uPartIdx;
/// BmonF
std::string msgStrTof(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTof(msgStrTof);
boost::archive::binary_iarchive inputArchiveTof(issTof);
inputArchiveTof >> fvDigiTof;
++uPartIdx;
/// RICH
std::string msgStrRich(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issRich(msgStrRich);
boost::archive::binary_iarchive inputArchiveRich(issRich);
inputArchiveRich >> fvDigiRich;
++uPartIdx;
/// PSD
std::string msgStrPsd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issPsd(msgStrPsd);
boost::archive::binary_iarchive inputArchivePsd(issPsd);
inputArchivePsd >> fvDigiPsd;
++uPartIdx;
/// Extract CbmEvent TClonesArray from input message
TObject* tempObject = nullptr;
RootSerializer().Deserialize(*parts.At(uPartIdx), tempObject);
++uPartIdx;
if (TString(tempObject->ClassName()).EqualTo("TClonesArray")) {
TClonesArray* arrayEventsIn = static_cast<TClonesArray*>(tempObject);
/// Copy data in registered TClonesArray (by taking ownership!)
fEventsArray.AbsorbObjects(arrayEventsIn);
} // if( TString( tempObject->ClassName() ).EqualTo( "TClonesArray") )
}
CbmUnpackedTimeslice::~CbmUnpackedTimeslice()
{
fvDigiBmon.clear();
fvDigiSts.clear();
fvDigiMuch.clear();
fvDigiTrd.clear();
fvDigiTof.clear();
fvDigiRich.clear();
fvDigiPsd.clear();
// fEventsArray.Clear("C");
fEventsArray.Delete();
}
/* Copyright (C) 2020-2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceMcbmEventSink.h
*
* @since 2020-05-04
* @author P.-A. Loizeau
*/
#ifndef CBMDEVICEMCBMEVTSINK_H_
#define CBMDEVICEMCBMEVTSINK_H_
/// CBM headers
#include "CbmEvent.h"
#include "CbmMqTMessage.h"
#include "CbmMuchBeamTimeDigi.h"
#include "CbmPsdDigi.h"
#include "CbmRichDigi.h"
#include "CbmStsDigi.h"
#include "CbmTofDigi.h"
#include "CbmTrdDigi.h"
#include "TimesliceMetaData.h"
/// FAIRROOT headers
#include "FairMQDevice.h"
/// FAIRSOFT headers (geant, boost, ...)
#include "Rtypes.h"
#include "TClonesArray.h"
#include "TObjArray.h"
/// C/C++ headers
#include <chrono>
#include <map>
#include <vector>
class TFile;
class TList;
class TClonesArray;
//class TimesliceMetaData;
class FairRunOnline;
class FairRootManager;
class CbmUnpackedTimeslice {
/// TODO: rename to CbmTsWithEvents
public:
CbmUnpackedTimeslice(FairMQParts& parts);
~CbmUnpackedTimeslice();
TimesliceMetaData fTsMetaData;
std::vector<CbmTofDigi> fvDigiBmon;
std::vector<CbmStsDigi> fvDigiSts;
std::vector<CbmMuchBeamTimeDigi> fvDigiMuch;
std::vector<CbmTrdDigi> fvDigiTrd;
std::vector<CbmTofDigi> fvDigiTof;
std::vector<CbmRichDigi> fvDigiRich;
std::vector<CbmPsdDigi> fvDigiPsd;
TClonesArray fEventsArray;
};
class CbmDeviceMcbmEventSink : public FairMQDevice {
public:
CbmDeviceMcbmEventSink();
virtual ~CbmDeviceMcbmEventSink();
protected:
virtual void InitTask();
bool HandleMissTsData(FairMQMessagePtr&, int);
bool HandleData(FairMQParts&, int);
bool HandleCommand(FairMQMessagePtr&, int);
private:
/// Constants
/// Control flags
Bool_t fbFillHistos = kFALSE; //! Switch ON/OFF filling of histograms
Bool_t fbFinishDone = kFALSE; //! Keep track of whether the Finish was already called
/// User settings parameters
/// Algo enum settings
std::string fsOutputFileName = "mcbm_digis_events.root";
/// message queues
std::string fsChannelNameMissedTs = "missedts";
std::string fsChannelNameDataInput = "events";
std::string fsChannelNameCommands = "commands";
std::string fsChannelNameHistosInput = "histogram-in";
std::string fsChannelNameHistosConfig = "histo-conf";
std::string fsChannelNameCanvasConfig = "canvas-conf";
/// Histograms management
uint32_t fuPublishFreqTs = 100;
double_t fdMinPublishTime = 0.5;
double_t fdMaxPublishTime = 5.0;
/// List of MQ channels names
std::vector<std::string> fsAllowedChannels = {fsChannelNameDataInput};
/// Parameters management
// TList* fParCList = nullptr;
// Bool_t InitParameters( TList* fParCList );
/// Statistics & missed TS detection
uint64_t fuPrevTsIndex = 0;
uint64_t fulNumMessages = 0;
uint64_t fulTsCounter = 0;
uint64_t fulMissedTsCounter = 0;
std::chrono::system_clock::time_point fLastPublishTime = std::chrono::system_clock::now();
/// Control Commands reception
bool fbReceivedEof = false;
uint64_t fuLastTsIndex = 0;
uint64_t fuTotalTsCount = 0;
/// Data reception
/// Event (TS) header
// FairEventHeader* fEvtHeader;
/// TS MetaData storage
TClonesArray* fTimeSliceMetaDataArray = nullptr; //!
TimesliceMetaData* fTsMetaData = nullptr;
/// Digis storage
std::vector<CbmTofDigi>* fvDigiBmon = nullptr;
std::vector<CbmStsDigi>* fvDigiSts = nullptr;
std::vector<CbmMuchBeamTimeDigi>* fvDigiMuch = nullptr;
std::vector<CbmTrdDigi>* fvDigiTrd = nullptr;
std::vector<CbmTofDigi>* fvDigiTof = nullptr;
std::vector<CbmRichDigi>* fvDigiRich = nullptr;
std::vector<CbmPsdDigi>* fvDigiPsd = nullptr;
/// CbmEvents
TClonesArray* fEventsArray = nullptr; //! output container of CbmEvents
// std::vector< CbmEvent * > & fEventVector; //! vector with all created events
/// Storage for re-ordering
/// Missed TS vector
std::vector<uint64_t> fvulMissedTsIndices = {};
/// Buffered TS
std::map<uint64_t, CbmUnpackedTimeslice> fmFullTsStorage = {};
/// Data storage
FairRunOnline* fpRun = nullptr;
FairRootManager* fpFairRootMgr = nullptr;
/// Array of histograms to send to the histogram server
TObjArray fArrayHisto = {};
/// Vector of string pairs with ( HistoName, FolderPath ) to send to the histogram server
std::vector<std::pair<std::string, std::string>> fvpsHistosFolder = {};
/// Vector of string pairs with ( CanvasName, CanvasConfig ) to send to the histogram server
/// Format of Can config is "NbPadX(U);NbPadY(U);ConfigPad1(s);....;ConfigPadXY(s)"
/// Format of Pad config is "GrixX(b),GridY(b),LogX(b),LogY(b),LogZ(b),HistoName(s),DrawOptions(s)"
std::vector<std::pair<std::string, std::string>> fvpsCanvasConfig = {};
/// Internal methods
bool IsChannelNameAllowed(std::string channelName);
// Bool_t InitContainers();
void CheckTsQueues();
void PrepareTreeEntry(CbmUnpackedTimeslice unpTs);
void DumpTreeEntry();
bool SendHistograms();
void Finish();
};
#endif /* CBMDEVICEMCBMEVTSINK_H_ */
/* Copyright (C) 2020 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceMcbmMonitorPulser.cxx
*
* @since 2020-05-04
* @author P.-A Loizeau
*/
#include "CbmDeviceMcbmMonitorPulser.h"
#include "CbmMQDefs.h"
#include "TimesliceMetaData.h"
//#include "CbmMcbm2018MonitorAlgoTof.h"
#include "CbmFlesCanvasTools.h"
#include "StorableTimeslice.hpp"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairParGenericSet.h"
#include "TCanvas.h"
#include "TFile.h"
#include "TH1.h"
#include "TList.h"
#include "TNamed.h"
#include "BoostSerializer.h"
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/utility.hpp>
#include <array>
#include <iomanip>
#include <stdexcept>
#include <string>
#include "RootSerializer.h"
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
using namespace std;
//Bool_t bMcbm2018MonitorTaskTofResetHistos = kFALSE;
CbmDeviceMcbmMonitorPulser::CbmDeviceMcbmMonitorPulser()
// : fMonitorAlgo{ new CbmMcbm2018MonitorAlgoTof() }
{
}
void CbmDeviceMcbmMonitorPulser::InitTask()
try {
/// Read options from executable
LOG(info) << "Init options for CbmMqStarHistoServer.";
fbDebugMonitorMode = fConfig->GetValue<bool>("DebugMoni");
fuHistoryHistoSize = fConfig->GetValue<uint32_t>("HistEvoSz");
fuMinTotPulser = fConfig->GetValue<uint32_t>("PulsTotMin");
fuMaxTotPulser = fConfig->GetValue<uint32_t>("PulsTotMax");
fuPublishFreqTs = fConfig->GetValue<uint32_t>("PubFreqTs");
fdMinPublishTime = fConfig->GetValue<double_t>("PubTimeMin");
fdMaxPublishTime = fConfig->GetValue<double_t>("PubTimeMax");
fsChannelNameDataInput = fConfig->GetValue<std::string>("TsNameIn");
fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
fsChannelNameHistosConfig = fConfig->GetValue<std::string>("ChNameHistCfg");
fsChannelNameCanvasConfig = fConfig->GetValue<std::string>("ChNameCanvCfg");
fsAllowedChannels[0] = fsChannelNameDataInput;
LOG(info) << "Histograms publication frequency in TS: " << fuPublishFreqTs;
LOG(info) << "Histograms publication min. interval in s: " << fdMinPublishTime;
LOG(info) << "Histograms publication max. interval in s: " << fdMaxPublishTime;
/// Set the Monitor Algo in Absolute time scale
// fMonitorAlgo->UseAbsoluteTime();
// 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
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
//logger::SetLogLevel("INFO");
int noChannel = fChannels.size();
LOG(info) << "Number of defined channels: " << noChannel;
for (auto const& entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
if (std::string::npos != entry.first.find(fsChannelNameDataInput)) {
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
OnData(entry.first, &CbmDeviceMcbmMonitorPulser::HandleData);
} // if( std::string::npos != entry.first.find( fsChannelNameDataInput ) )
} // for( auto const &entry : fChannels )
InitContainers();
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
}
bool CbmDeviceMcbmMonitorPulser::IsChannelNameAllowed(std::string channelName)
{
for (auto const& entry : fsAllowedChannels) {
std::size_t pos1 = channelName.find(entry);
if (pos1 != std::string::npos) {
const vector<std::string>::const_iterator pos =
std::find(fsAllowedChannels.begin(), fsAllowedChannels.end(), entry);
const vector<std::string>::size_type idx = pos - fsAllowedChannels.begin();
LOG(info) << "Found " << entry << " in " << channelName;
LOG(info) << "Channel name " << channelName << " found in list of allowed channel names at position " << idx;
return true;
} // if (pos1!=std::string::npos)
} // for(auto const &entry : fsAllowedChannels)
LOG(info) << "Channel name " << channelName << " not found in list of allowed channel names.";
LOG(error) << "Stop device.";
return false;
}
Bool_t CbmDeviceMcbmMonitorPulser::InitContainers()
{
LOG(info) << "Init parameter containers for CbmDeviceMcbmMonitorPulser.";
Bool_t initOK = kTRUE;
/*
fParCList = fMonitorAlgo->GetParList();
for( int iparC = 0; iparC < fParCList->GetEntries(); iparC++ ) {
FairParGenericSet* tempObj = (FairParGenericSet*)( fParCList->At( iparC ) );
fParCList->Remove( tempObj );
std::string paramName{ tempObj->GetName() };
// NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
// Should only be used for small data because of the cost of an additional copy
// Her must come the proper Runid
std::string message = paramName + ",111";
LOG(info) << "Requesting parameter container " << paramName << ", sending message: " << message;
FairMQMessagePtr req( NewSimpleMessage(message) );
FairMQMessagePtr rep( NewMessage() );
FairParGenericSet* newObj = nullptr;
if ( Send(req, "parameters") > 0 ) {
if ( Receive( rep, "parameters" ) >= 0) {
if ( rep->GetSize() != 0 ) {
CbmMqTMessage tmsg( rep->GetData(), rep->GetSize() );
newObj = static_cast< FairParGenericSet* >( tmsg.ReadObject( tmsg.GetClass() ) );
LOG( info ) << "Received unpack parameter from the server:";
newObj->print();
} else {
LOG( error ) << "Received empty reply. Parameter not available";
} // if (rep->GetSize() != 0)
} // if (Receive(rep, "parameters") >= 0)
} // if (Send(req, "parameters") > 0)
fParCList->AddAt( newObj, iparC );
delete tempObj;
} // for ( int iparC = 0; iparC < fParCList->GetEntries(); iparC++ )
/// Need to add accessors for all options
fMonitorAlgo->SetIgnoreOverlapMs( fbIgnoreOverlapMs );
fMonitorAlgo->SetDebugMonitorMode( fbDebugMonitorMode );
fMonitorAlgo->SetIgnoreCriticalErrors( fbIgnoreCriticalErrors );
fMonitorAlgo->SetHistoryHistoSize( fuHistoryHistoSize );
fMonitorAlgo->SetPulserTotLimits( fuMinTotPulser, fuMaxTotPulser );
Bool_t initOK = fMonitorAlgo->InitContainers();
*/
// Bool_t initOK = fMonitorAlgo->ReInitContainers();
// CreateHistos();
/*
/// Histos creation and obtain pointer on them
/// Trigger histo creation on all associated algos
initOK &= fMonitorAlgo->CreateHistograms();
/// Obtain vector of pointers on each histo from the algo (+ optionally desired folder)
std::vector< std::pair< TNamed *, std::string > > vHistos = fMonitorAlgo->GetHistoVector();
/// Obtain vector of pointers on each canvas from the algo (+ optionally desired folder)
std::vector< std::pair< TCanvas *, std::string > > vCanvases = fMonitorAlgo->GetCanvasVector();
/// Add pointers to each histo in the histo array
/// Create histo config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Histo name, Folder >
/// and send it through a separate channel using the BoostSerializer
for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto )
{
// LOG(info) << "Registering " << vHistos[ uHisto ].first->GetName()
// << " in " << vHistos[ uHisto ].second.data()
// ;
fArrayHisto.Add( vHistos[ uHisto ].first );
std::pair< std::string, std::string > psHistoConfig( vHistos[ uHisto ].first->GetName(),
vHistos[ uHisto ].second );
fvpsHistosFolder.push_back( psHistoConfig );
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist( NewMessage() );
// Serialize< BoostSerializer < std::pair< std::string, std::string > > >( *messageHist, psHistoConfig );
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist,psHistoConfig);
/// Send message to the common histogram config messages queue
if( Send( messageHist, fsChannelNameHistosConfig ) < 0 )
{
LOG(error) << "Problem sending histo config";
return false;
} // if( Send( messageHist, fsChannelNameHistosConfig ) < 0 )
LOG(info) << "Config of hist " << psHistoConfig.first.data()
<< " in folder " << psHistoConfig.second.data() ;
} // for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto )
/// Create canvas config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Canvas name, config >
/// and send it through a separate channel using the BoostSerializer
for( UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv )
{
// LOG(info) << "Registering " << vCanvases[ uCanv ].first->GetName()
// << " in " << vCanvases[ uCanv ].second.data();
std::string sCanvName = (vCanvases[ uCanv ].first)->GetName();
std::string sCanvConf = GenerateCanvasConfigString( vCanvases[ uCanv ].first );
std::pair< std::string, std::string > psCanvConfig( sCanvName, sCanvConf );
fvpsCanvasConfig.push_back( psCanvConfig );
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan( NewMessage() );
// Serialize< BoostSerializer < std::pair< std::string, std::string > > >( *messageCan, psCanvConfig );
BoostSerializer < std::pair< std::string, std::string > >().Serialize( *messageCan, psCanvConfig );
/// Send message to the common canvas config messages queue
if( Send( messageCan, fsChannelNameCanvasConfig ) < 0 )
{
LOG(error) << "Problem sending canvas config";
return false;
} // if( Send( messageCan, fsChannelNameCanvasConfig ) < 0 )
LOG(info) << "Config string of Canvas " << psCanvConfig.first.data()
<< " is " << psCanvConfig.second.data() ;
} // for( UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv )
*/
return initOK;
}
// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
bool CbmDeviceMcbmMonitorPulser::HandleData(FairMQParts& parts, int /*index*/)
{
fulNumMessages++;
LOG(debug) << "Received message " << fulNumMessages << " with " << parts.Size() << " parts"
<< ", size0: " << parts.At(0)->GetSize();
uint32_t uPartIdx = 0;
/// TODO: code order of vectors in the TS MetaData!!
/*
std::string msgStrTsMeta( static_cast< char * >( parts.At( uPartIdx )->GetData() ),
( parts.At( uPartIdx ) )->GetSize() );
std::istringstream issTsMeta(msgStrTsMeta);
boost::archive::binary_iarchive inputArchiveTsMeta(issTsMeta);
inputArchiveTsMeta >> (*fTsMetaData);
++uPartIdx;
*/
// Deserialize<RootSerializer>(*parts.At(uPartIdx), fTsMetaData);
RootSerializer().Deserialize(*parts.At(uPartIdx), fTsMetaData);
++uPartIdx;
std::string msgStrBmon(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issBmon(msgStrBmon);
boost::archive::binary_iarchive inputArchiveBmon(issBmon);
inputArchiveBmon >> fvDigiBmon;
++uPartIdx;
std::string msgStrSts(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issSts(msgStrSts);
boost::archive::binary_iarchive inputArchiveSts(issSts);
inputArchiveSts >> fvDigiSts;
++uPartIdx;
std::string msgStrMuch(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issMuch(msgStrMuch);
boost::archive::binary_iarchive inputArchiveMuch(issMuch);
inputArchiveMuch >> fvDigiMuch;
++uPartIdx;
std::string msgStrTrd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTrd(msgStrTrd);
boost::archive::binary_iarchive inputArchiveTrd(issTrd);
inputArchiveTrd >> fvDigiTrd;
++uPartIdx;
std::string msgStrTof(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTof(msgStrTof);
boost::archive::binary_iarchive inputArchiveTof(issTof);
inputArchiveTof >> fvDigiTof;
++uPartIdx;
std::string msgStrRich(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issRich(msgStrRich);
boost::archive::binary_iarchive inputArchiveRich(issRich);
inputArchiveRich >> fvDigiRich;
++uPartIdx;
std::string msgStrPsd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issPsd(msgStrPsd);
boost::archive::binary_iarchive inputArchivePsd(issPsd);
inputArchivePsd >> fvDigiPsd;
++uPartIdx;
/// Process data in Algo
/// Clear vectors
delete fTsMetaData;
fvDigiBmon.clear();
fvDigiSts.clear();
fvDigiMuch.clear();
fvDigiTrd.clear();
fvDigiTof.clear();
fvDigiRich.clear();
fvDigiPsd.clear();
/*
LOG(debug) << "Received message number "<< fulNumMessages
<< " with size " << msg->GetSize();
if( 0 == fulNumMessages % 10000 )
LOG(info) << "Received " << fulNumMessages << " messages";
std::string msgStr( static_cast<char*>( msg->GetData() ), msg->GetSize() );
std::istringstream iss( msgStr );
boost::archive::binary_iarchive inputArchive( iss );
/// Create an empty TS and fill it with the incoming message
fles::StorableTimeslice component{ 0 };
inputArchive >> component;
/// Process the Timeslice
DoUnpack(component, 0);
/// Send histograms each 100 time slices. Should be each ~1s
/// Use also runtime checker to trigger sending after M s if
/// processing too slow or delay sending if processing too fast
std::chrono::system_clock::time_point currentTime = std::chrono::system_clock::now();
std::chrono::duration<double_t> elapsedSeconds = currentTime - fLastPublishTime;
if( ( fdMaxPublishTime < elapsedSeconds.count() ) ||
( 0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count() ) )
{
SendHistograms();
fLastPublishTime = std::chrono::system_clock::now();
} // if( ( fdMaxPublishTime < elapsedSeconds.count() ) || ( 0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count() ) )
*/
return true;
}
bool CbmDeviceMcbmMonitorPulser::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
// Serialize<RootSerializer>(*message, &fArrayHisto);
RootSerializer().Serialize(*message, &fArrayHisto);
// test code to check if deserialization works
/*
TObject* tempObject = nullptr;
// Deserialize<RootDeserializer>(*message, tempObject);
RootDeserializer().Deserialize(*message, tempObject);
if (TString(tempObject->ClassName()).EqualTo("TObjArray")) {
TObjArray* arrayHisto = static_cast<TObjArray*>(tempObject);
LOG(info) << "Array contains " << arrayHisto->GetEntriesFast()
<< " entries";
for (Int_t i = 0; i < arrayHisto->GetEntriesFast(); i++) {
TObject* obj = arrayHisto->At(i);
LOG(info) << obj->GetName();
TH1* histogram = static_cast<TH1*>(obj);
LOG(info) << histogram->GetNbinsX();
}
}
*/
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
LOG(error) << "Problem sending data";
return false;
} // if( Send( message, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
// fMonitorAlgo->ResetHistograms( kFALSE );
return true;
}
CbmDeviceMcbmMonitorPulser::~CbmDeviceMcbmMonitorPulser() {}
void CbmDeviceMcbmMonitorPulser::Finish() {}
/* Copyright (C) 2020 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceMcbmMonitorPulser.h
*
* @since 2020-05-04
* @author P.-A Loizeau
*/
#ifndef CBMDEVICEMCBMMONITORPULSER_H_
#define CBMDEVICEMCBMMONITORPULSER_H_
#include "CbmMqTMessage.h"
#include "CbmMuchBeamTimeDigi.h"
#include "CbmPsdDigi.h"
#include "CbmRichDigi.h"
#include "CbmStsDigi.h"
#include "CbmTofDigi.h"
#include "CbmTrdDigi.h"
#include "FairMQDevice.h"
#include "Rtypes.h"
#include "TObjArray.h"
#include <chrono>
#include <map>
#include <vector>
class TH1;
class TH2;
class TProfile;
class TList;
//class CbmMcbm2018MonitorAlgoTof;
class TimesliceMetaData;
class CbmDeviceMcbmMonitorPulser : public FairMQDevice {
public:
CbmDeviceMcbmMonitorPulser();
virtual ~CbmDeviceMcbmMonitorPulser();
protected:
virtual void InitTask();
bool HandleData(FairMQParts&, int);
private:
/// Constants
/*********************** SHOULD GO IN ALGO ****************************/
static const UInt_t kuNbChanSMX = 128;
static const UInt_t kuMaxNbStsDpbs = 2;
static const UInt_t kuMaxNbMuchDpbs = 6;
static const UInt_t kuMaxNbMuchAsics = 36;
static const UInt_t kuDefaultAddress = 0xFFFFFFFF;
static const UInt_t kuMaxChannelSts = 3000;
/*********************** SHOULD GO IN ALGO ****************************/
/// Control flags
Bool_t fbDebugMonitorMode = kFALSE; //! Switch ON the filling of a additional set of histograms
Bool_t fbIgnoreCriticalErrors = kTRUE; //! If ON not printout at all for critical errors
Bool_t fbComponentsAddedToList = kFALSE;
/// User settings parameters
std::string fsChannelNameDataInput = "unpts_0";
std::string fsChannelNameCommands = "commands";
std::string fsChannelNameHistosInput = "histogram-in";
std::string fsChannelNameHistosConfig = "histo-conf";
std::string fsChannelNameCanvasConfig = "canvas-conf";
uint32_t fuHistoryHistoSize = 3600;
uint32_t fuMinTotPulser = 185;
uint32_t fuMaxTotPulser = 195;
uint32_t fuPublishFreqTs = 100;
double_t fdMinPublishTime = 0.5;
double_t fdMaxPublishTime = 5.0;
/// List of MQ channels names
std::vector<std::string> fsAllowedChannels = {fsChannelNameDataInput};
/// Parameters management
/*
TList* fParCList = nullptr;
*/
/// Statistics & first TS rejection
uint64_t fulNumMessages = 0;
uint64_t fulTsCounter = 0;
std::chrono::system_clock::time_point fLastPublishTime = std::chrono::system_clock::now();
/// Data reception
/// TS MetaData storage
TimesliceMetaData* fTsMetaData = nullptr;
/// Digis storage
std::vector<CbmTofDigi> fvDigiBmon = {};
std::vector<CbmStsDigi> fvDigiSts = {};
std::vector<CbmMuchBeamTimeDigi> fvDigiMuch = {};
std::vector<CbmTrdDigi> fvDigiTrd = {};
std::vector<CbmTofDigi> fvDigiTof = {};
std::vector<CbmRichDigi> fvDigiRich = {};
std::vector<CbmPsdDigi> fvDigiPsd = {};
/// Processing algo
// CbmMcbm2018MonitorAlgoTof * fMonitorAlgo;
/// Array of histograms to send to the histogram server
TObjArray fArrayHisto = {};
/// Vector of string pairs with ( HistoName, FolderPath ) to send to the histogram server
std::vector<std::pair<std::string, std::string>> fvpsHistosFolder = {};
/// Vector of string pairs with ( CanvasName, CanvasConfig ) to send to the histogram server
/// Format of Can config is "NbPadX(U);NbPadY(U);ConfigPad1(s);....;ConfigPadXY(s)"
/// Format of Pad config is "GrixX(b),GridY(b),LogX(b),LogY(b),LogZ(b),HistoName(s),DrawOptions(s)"
std::vector<std::pair<std::string, std::string>> fvpsCanvasConfig = {};
bool IsChannelNameAllowed(std::string channelName);
Bool_t InitContainers();
void Finish();
bool SendHistograms();
/*********************** SHOULD GO IN ALGO ****************************/
void CheckInterSystemOffset();
template<class Digi>
Int_t FillSystemOffsetHistos(TH1* histo, TH2* histoEvo, TH2* histoEvoLong, TProfile* profMeanEvo, TH2* histoAFCK,
const Double_t T0Time, const Int_t offsetRange, Int_t iStartDigi,
ECbmModuleId iDetId = ECbmModuleId::kLastModule);
Int_t CalcNrBins(Int_t);
void CreateHistos();
/// Variables to store the previous digi time
Double_t fPrevTimeBmon = 0.;
Double_t fPrevTimeSts = 0.;
Double_t fPrevTimeMuch = 0.;
Double_t fPrevTimeTrd = 0.;
Double_t fPrevTimeTof = 0.;
Double_t fPrevTimeRich = 0.;
Double_t fPrevTimePsd = 0.;
/// Variables to store the first digi fitting the previous Bmon hits
/// => Time-order means the time window for following one can only be in a later digi
Int_t fPrevBmonFirstDigiSts = 0;
Int_t fPrevBmonFirstDigiMuch = 0;
Int_t fPrevBmonFirstDigiTrd = 0;
Int_t fPrevBmonFirstDigiTof = 0;
Int_t fPrevBmonFirstDigiRich = 0;
Int_t fPrevBmonFirstDigiPsd = 0;
/// User settings: Data correction parameters
/// Charge cut
UInt_t fuMinTotPulserBmon = 182;
UInt_t fuMaxTotPulserBmon = 190;
UInt_t fuMinAdcPulserSts = 90;
UInt_t fuMaxAdcPulserSts = 100;
UInt_t fuMinAdcPulserMuch = 5;
UInt_t fuMaxAdcPulserMuch = 15;
UInt_t fuMinChargePulserTrd = 0;
UInt_t fuMaxChargePulserTrd = 70000;
UInt_t fuMinTotPulserTof = 182;
UInt_t fuMaxTotPulserTof = 190;
UInt_t fuMinTotPulserRich = 90;
UInt_t fuMaxTotPulserRich = 105;
UInt_t fuMinAdcPulserPsd = 90;
UInt_t fuMaxAdcPulserPsd = 100;
/// Channel selection
UInt_t fuStsAddress = kuDefaultAddress;
UInt_t fuStsFirstCha = kuMaxChannelSts;
UInt_t fuStsLastChan = kuMaxChannelSts;
UInt_t fuMuchAsic = kuMaxNbMuchAsics;
UInt_t fuMuchFirstCha = kuNbChanSMX;
UInt_t fuMuchLastChan = kuNbChanSMX;
UInt_t fuTrdAddress = kuDefaultAddress;
UInt_t fuPsdAddress = kuDefaultAddress;
//
Int_t fNrTs = 0;
Int_t fOffsetRange = 1000;
Int_t fStsOffsetRange = 1000;
Int_t fMuchOffsetRange = 1000;
Int_t fTrdOffsetRange = 1000;
Int_t fTofOffsetRange = 1000;
Int_t fRichOffsetRange = 1000;
Int_t fPsdOffsetRange = 1000;
Int_t fBinWidth = 1;
TH1* fBmonStsDiff = nullptr;
TH1* fBmonMuchDiff = nullptr;
TH1* fBmonTrdDiff = nullptr;
TH1* fBmonTofDiff = nullptr;
TH1* fBmonRichDiff = nullptr;
TH1* fBmonPsdDiff = nullptr;
TH2* fBmonPsdDiffCharge = nullptr;
TH2* fBmonStsDiffEvo = nullptr;
TH2* fBmonMuchDiffEvo = nullptr;
TH2* fBmonTrdDiffEvo = nullptr;
TH2* fBmonTofDiffEvo = nullptr;
TH2* fBmonRichDiffEvo = nullptr;
TH2* fBmonPsdDiffEvo = nullptr;
TH2* fBmonStsDiffEvoLong = nullptr;
TH2* fBmonMuchDiffEvoLong = nullptr;
TH2* fBmonTrdDiffEvoLong = nullptr;
TH2* fBmonTofDiffEvoLong = nullptr;
TH2* fBmonRichDiffEvoLong = nullptr;
TH2* fBmonPsdDiffEvoLong = nullptr;
Double_t fdStartTime = -1;
TProfile* fBmonStsMeanEvo = nullptr;
TProfile* fBmonMuchMeanEvo = nullptr;
TProfile* fBmonTrdMeanEvo = nullptr;
TProfile* fBmonTofMeanEvo = nullptr;
TProfile* fBmonRichMeanEvo = nullptr;
TProfile* fBmonPsdMeanEvo = nullptr;
TH1* fBmonBmonDiff = nullptr;
TH1* fStsStsDiff = nullptr;
TH1* fMuchMuchDiff = nullptr;
TH1* fTrdTrdDiff = nullptr;
TH1* fTofTofDiff = nullptr;
TH1* fRichRichDiff = nullptr;
TH1* fPsdPsdDiff = nullptr;
TH2* fBmonStsNb = nullptr;
TH2* fBmonMuchNb = nullptr;
TH2* fBmonTrdNb = nullptr;
TH2* fBmonTofNb = nullptr;
TH2* fBmonRichNb = nullptr;
TH2* fBmonPsdNb = nullptr;
Int_t fiBmonNb = 0;
Int_t fiStsNb = 0;
Int_t fiMuchNb = 0;
Int_t fiTrdNb = 0;
Int_t fiTofNb = 0;
Int_t fiRichNb = 0;
Int_t fiPsdNb = 0;
TH1* fBmonAddress = nullptr;
TH1* fBmonChannel = nullptr;
TH2* fBmonStsDpbDiff = nullptr;
TH2* fBmonStsDpbDiffEvo[kuMaxNbStsDpbs];
TH1* fStsDpbCntsEvo[kuMaxNbStsDpbs];
TH2* fBmonMuchRocDiff = nullptr;
TH2* fBmonMuchAsicDiff = nullptr;
TH2* fBmonMuchAsicDiffEvo[kuMaxNbMuchAsics];
TH2* fDigisPerAsicEvo = nullptr;
Double_t fdLastMuchDigi[kuMaxNbMuchAsics][kuNbChanSMX];
Double_t fdLastMuchDigiPulser[kuMaxNbMuchAsics][kuNbChanSMX];
TH2* fSameChanDigisDistEvo = nullptr;
Double_t fdLastBmonDigiPulser = 0;
TH2* fDigiTimeEvoBmon = nullptr;
TH2* fDigiTimeEvoSts = nullptr;
TH2* fDigiTimeEvoMuch = nullptr;
TH2* fDigiTimeEvoTof = nullptr;
/*********************** SHOULD GO IN ALGO ****************************/
};
#endif /* CBMDEVICEMCBMMONITORPULSER_H_ */
/* Copyright (C) 2020 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceMcbmUnpack.cxx
*
* @since 2020-05-04
* @author P.-A. Loizeau
*/
#include "CbmDeviceMcbmUnpack.h"
#include "CbmFlesCanvasTools.h"
#include "CbmMQDefs.h"
#include "CbmMcbm2018UnpackerAlgoMuch.h"
#include "CbmMcbm2018UnpackerAlgoPsd.h"
#include "CbmMcbm2018UnpackerAlgoRich.h"
#include "CbmMcbm2018UnpackerAlgoSts.h"
#include "CbmMcbm2018UnpackerAlgoTof.h"
#include "CbmMcbm2018UnpackerAlgoTrdR.h"
#include "StorableTimeslice.hpp"
#include "TimesliceMetaData.h"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairParGenericSet.h"
#include "TCanvas.h"
#include "TFile.h"
#include "TH1.h"
#include "TList.h"
#include "TNamed.h"
#include "BoostSerializer.h"
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/utility.hpp>
#include <array>
#include <iomanip>
#include <stdexcept>
#include <string>
#include "RootSerializer.h"
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
using namespace std;
Bool_t bMcbm2018MonitorTaskBmonResetHistos = kFALSE;
CbmDeviceMcbmUnpack::CbmDeviceMcbmUnpack()
{
fUnpAlgoSts = new CbmMcbm2018UnpackerAlgoSts();
fUnpAlgoMuch = new CbmMcbm2018UnpackerAlgoMuch();
fUnpAlgoTrd = new CbmMcbm2018UnpackerAlgoTrdR();
fUnpAlgoTof = new CbmMcbm2018UnpackerAlgoTof();
fUnpAlgoRich = new CbmMcbm2018UnpackerAlgoRich();
fUnpAlgoPsd = new CbmMcbm2018UnpackerAlgoPsd();
}
void CbmDeviceMcbmUnpack::InitTask()
try {
/// Read options from executable
LOG(info) << "Init options for CbmDeviceMcbmUnpack.";
fbIgnoreOverlapMs = fConfig->GetValue<bool>("IgnOverMs");
fvsSetTimeOffs = fConfig->GetValue<std::vector<std::string>>("SetTrigWin");
fsChannelNameDataInput = fConfig->GetValue<std::string>("TsNameIn");
fsChannelNameDataOutput = fConfig->GetValue<std::string>("TsNameOut");
/// TODO: option to set fuDigiMaskedIdBmon !!!!
fsAllowedChannels[0] = fsChannelNameDataInput;
// 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
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
//logger::SetLogLevel("INFO");
int noChannel = fChannels.size();
LOG(info) << "Number of defined channels: " << noChannel;
for (auto const& entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
if (std::string::npos != entry.first.find(fsChannelNameDataInput)) {
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
OnData(entry.first, &CbmDeviceMcbmUnpack::HandleData);
} // if( entry.first.find( "ts" )
} // for( auto const &entry : fChannels )
InitContainers();
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
}
bool CbmDeviceMcbmUnpack::IsChannelNameAllowed(std::string channelName)
{
for (auto const& entry : fsAllowedChannels) {
std::size_t pos1 = channelName.find(entry);
if (pos1 != std::string::npos) {
const vector<std::string>::const_iterator pos =
std::find(fsAllowedChannels.begin(), fsAllowedChannels.end(), entry);
const vector<std::string>::size_type idx = pos - fsAllowedChannels.begin();
LOG(info) << "Found " << entry << " in " << channelName;
LOG(info) << "Channel name " << channelName << " found in list of allowed channel names at position " << idx;
return true;
} // if (pos1!=std::string::npos)
} // for(auto const &entry : fsAllowedChannels)
LOG(info) << "Channel name " << channelName << " not found in list of allowed channel names.";
LOG(error) << "Stop device.";
return false;
}
Bool_t CbmDeviceMcbmUnpack::InitContainers()
{
LOG(info) << "Init parameter containers for CbmDeviceMcbmUnpack.";
if (kFALSE == InitParameters(fUnpAlgoSts->GetParList())) return kFALSE;
if (kFALSE == InitParameters(fUnpAlgoMuch->GetParList())) return kFALSE;
if (kFALSE == InitParameters(fUnpAlgoTrd->GetParList())) return kFALSE;
if (kFALSE == InitParameters(fUnpAlgoTof->GetParList())) return kFALSE;
if (kFALSE == InitParameters(fUnpAlgoRich->GetParList())) return kFALSE;
if (kFALSE == InitParameters(fUnpAlgoPsd->GetParList())) return kFALSE;
/// Need to add accessors for all options
fUnpAlgoSts->SetIgnoreOverlapMs(fbIgnoreOverlapMs);
fUnpAlgoMuch->SetIgnoreOverlapMs(fbIgnoreOverlapMs);
fUnpAlgoTrd->SetIgnoreOverlapMs(fbIgnoreOverlapMs);
fUnpAlgoTof->SetIgnoreOverlapMs(fbIgnoreOverlapMs);
fUnpAlgoRich->SetIgnoreOverlapMs(fbIgnoreOverlapMs);
fUnpAlgoPsd->SetIgnoreOverlapMs(fbIgnoreOverlapMs);
/// Load time offsets
for (std::vector<std::string>::iterator itStrOffs = fvsSetTimeOffs.begin(); itStrOffs != fvsSetTimeOffs.end();
++itStrOffs) {
size_t charPosDel = (*itStrOffs).find(',');
if (std::string::npos == charPosDel) {
LOG(info) << "CbmDeviceMcbmUnpack::InitContainers => "
<< "Trying to set trigger window with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found " << (*itStrOffs) << " )";
} // if( std::string::npos == charPosDel )
/// Detector Enum Tag
std::string sSelDet = (*itStrOffs).substr(0, charPosDel);
/// Min number
charPosDel++;
Double_t dOffset = std::stod((*itStrOffs).substr(charPosDel));
if ("kSTS" == sSelDet) { fUnpAlgoSts->SetTimeOffsetNs(dOffset); } // if( "kSTS" == sSelDet )
else if ("kMUCH" == sSelDet) {
fUnpAlgoMuch->SetTimeOffsetNs(dOffset);
} // else if( "kMUCH" == sSelDet )
else if ("kTRD" == sSelDet) {
fUnpAlgoTrd->SetTimeOffsetNs(dOffset);
} // else if( "kTRD" == sSelDet )
else if ("kTOF" == sSelDet) {
fUnpAlgoTof->SetTimeOffsetNs(dOffset);
} // else if( "kTOF" == sSelDet )
else if ("kRICH" == sSelDet) {
fUnpAlgoRich->SetTimeOffsetNs(dOffset);
} // else if( "kRICH" == sSelDet )
else if ("kPSD" == sSelDet) {
fUnpAlgoPsd->SetTimeOffsetNs(dOffset);
} // else if( "kPSD" == sSelDet )
else {
LOG(info) << "CbmDeviceMcbmUnpack::InitContainers => Trying to set time "
"offset for unsupported detector, ignored! "
<< (sSelDet);
continue;
} // else of detector enum detection
} // for( std::vector< std::string >::iterator itStrAdd = fvsAddDet.begin(); itStrAdd != fvsAddDet.end(); ++itStrAdd )
/// Starting from first run on Tuesday 28/04/2020, STS uses bin sorter FW
fUnpAlgoSts->SetBinningFwFlag(kTRUE);
/// Starting from first run on Monday 04/05/2020, MUCH uses bin sorter FW
fUnpAlgoMuch->SetBinningFwFlag(kTRUE);
Bool_t initOK = fUnpAlgoSts->InitContainers();
initOK &= fUnpAlgoMuch->InitContainers();
initOK &= fUnpAlgoTrd->InitContainers();
initOK &= fUnpAlgoTof->InitContainers();
initOK &= fUnpAlgoRich->InitContainers();
initOK &= fUnpAlgoPsd->InitContainers();
/// Special case for TRD vector initialization
/// Get address of vector from algo in a kind of loopback ^^'
initOK &= fUnpAlgoTrd->SetDigiOutputPointer(&(fUnpAlgoTrd->GetVector()));
// Bool_t initOK = fMonitorAlgo->ReInitContainers();
return initOK;
}
Bool_t CbmDeviceMcbmUnpack::InitParameters(TList* fParCList)
{
for (int iparC = 0; iparC < fParCList->GetEntries(); iparC++) {
FairParGenericSet* tempObj = (FairParGenericSet*) (fParCList->At(iparC));
fParCList->Remove(tempObj);
std::string paramName {tempObj->GetName()};
// NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
// Should only be used for small data because of the cost of an additional copy
// Her must come the proper Runid
std::string message = paramName + ",111";
LOG(info) << "Requesting parameter container " << paramName << ", sending message: " << message;
FairMQMessagePtr req(NewSimpleMessage(message));
FairMQMessagePtr rep(NewMessage());
FairParGenericSet* newObj = nullptr;
if (Send(req, "parameters") > 0) {
if (Receive(rep, "parameters") >= 0) {
if (0 != rep->GetSize()) {
CbmMqTMessage tmsg(rep->GetData(), rep->GetSize());
newObj = static_cast<FairParGenericSet*>(tmsg.ReadObject(tmsg.GetClass()));
LOG(info) << "Received unpack parameter from the server:";
newObj->print();
} // if( 0 != rep->GetSize() )
else {
LOG(error) << "Received empty reply. Parameter not available";
return kFALSE;
} // else of if( 0 != rep->GetSize() )
} // if( Receive( rep, "parameters" ) >= 0)
} // if( Send(req, "parameters") > 0 )
fParCList->AddAt(newObj, iparC);
delete tempObj;
} // for( int iparC = 0; iparC < fParCList->GetEntries(); iparC++ )
return kTRUE;
}
// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
bool CbmDeviceMcbmUnpack::HandleData(FairMQMessagePtr& msg, int /*index*/)
{
fulNumMessages++;
LOG(debug) << "Received message number " << fulNumMessages << " with size " << msg->GetSize();
if (0 == fulNumMessages % 10000) LOG(info) << "Received " << fulNumMessages << " messages";
std::string msgStr(static_cast<char*>(msg->GetData()), msg->GetSize());
std::istringstream iss(msgStr);
boost::archive::binary_iarchive inputArchive(iss);
/// Create an empty TS and fill it with the incoming message
fles::StorableTimeslice ts {0};
inputArchive >> ts;
/// On first TS, extract the TS parameters from header (by definition stable over time)
if (-1.0 == fdTsCoreSizeInNs) {
fuNbCoreMsPerTs = ts.num_core_microslices();
fuNbOverMsPerTs = ts.num_microslices(0) - ts.num_core_microslices();
fdTsCoreSizeInNs = fdMsSizeInNs * (fuNbCoreMsPerTs);
fdTsOverSizeInNs = fdMsSizeInNs * (fuNbOverMsPerTs);
fdTsFullSizeInNs = fdTsCoreSizeInNs + fdTsOverSizeInNs;
LOG(info) << "Timeslice parameters: each TS has " << fuNbCoreMsPerTs << " Core MS and " << fuNbOverMsPerTs
<< " Overlap MS, for a core duration of " << fdTsCoreSizeInNs << " ns and a full duration of "
<< fdTsFullSizeInNs << " ns";
} // if( -1.0 == fdTsCoreSizeInNs )
fTsMetaData = new TimesliceMetaData(ts.descriptor(0, 0).idx, fdTsCoreSizeInNs, fdTsOverSizeInNs, ts.index());
/// Process the Timeslice
DoUnpack(ts, 0);
/// Send digi vectors to ouput
if (!SendUnpData()) return false;
delete fTsMetaData;
/// Clear the digis vectors in case it was filled
fUnpAlgoSts->ClearVector();
fUnpAlgoMuch->ClearVector();
fUnpAlgoTrd->ClearVector();
fUnpAlgoTof->ClearVector();
fUnpAlgoRich->ClearVector();
fUnpAlgoPsd->ClearVector();
/// Clear the digis vectors in case it was filled
fUnpAlgoSts->ClearErrorVector();
fUnpAlgoMuch->ClearErrorVector();
fUnpAlgoTrd->ClearErrorVector();
fUnpAlgoTof->ClearErrorVector();
fUnpAlgoRich->ClearErrorVector();
fUnpAlgoPsd->ClearErrorVector();
return true;
}
bool CbmDeviceMcbmUnpack::SendUnpData()
{
/// Prepare serialized versions of the TS Meta
/*
std::stringstream ossTsMeta;
boost::archive::binary_oarchive oaTsMeta(ossTsMeta);
oaTsMeta << *(fTsMetaData);
std::string* strMsgTsMetaE = new std::string(ossTsMeta.str());
*/
FairMQMessagePtr messTsMeta(NewMessage());
// Serialize<RootSerializer>(*messTsMeta, fTsMetaData);
RootSerializer().Serialize(*messTsMeta, fTsMetaData);
std::stringstream ossSts;
boost::archive::binary_oarchive oaSts(ossSts);
oaSts << fUnpAlgoSts->GetVector();
std::string* strMsgSts = new std::string(ossSts.str());
std::stringstream ossMuch;
boost::archive::binary_oarchive oaMuch(ossMuch);
oaMuch << fUnpAlgoMuch->GetVector();
std::string* strMsgMuch = new std::string(ossMuch.str());
std::stringstream ossTrd;
boost::archive::binary_oarchive oaTrd(ossTrd);
oaTrd << fUnpAlgoTrd->GetVector();
std::string* strMsgTrd = new std::string(ossTrd.str());
/// Split TOF vector in TOF and Bmon
std::vector<CbmTofDigi>& vDigiTofBmon = fUnpAlgoTof->GetVector();
std::vector<CbmTofDigi> vDigiTof = {};
std::vector<CbmTofDigi> vDigiBmon = {};
for (auto digi : vDigiTofBmon) {
if (fuDigiMaskedIdBmon == (digi.GetAddress() & fuDigiMaskId)) {
/// Insert data in Bmon output container
vDigiBmon.emplace_back(digi);
} // if( fuDigiMaskedIdBmon == ( digi.GetAddress() & fuDigiMaskId ) )
else {
/// Insert data in TOF output container
vDigiTof.emplace_back(digi);
} // else of if( fuDigiMaskedIdBmon == ( digi.GetAddress() & fuDigiMaskId ) )
} // for( auto digi: vDigi )
std::stringstream ossTof;
boost::archive::binary_oarchive oaTof(ossTof);
oaTof << vDigiTof;
std::string* strMsgTof = new std::string(ossTof.str());
std::stringstream ossBmon;
boost::archive::binary_oarchive oaBmon(ossBmon);
oaBmon << vDigiBmon;
std::string* strMsgBmon = new std::string(ossBmon.str());
std::stringstream ossRich;
boost::archive::binary_oarchive oaRich(ossRich);
oaRich << fUnpAlgoRich->GetVector();
std::string* strMsgRich = new std::string(ossRich.str());
std::stringstream ossPsd;
boost::archive::binary_oarchive oaPsd(ossPsd);
oaPsd << fUnpAlgoPsd->GetVector();
std::string* strMsgPsd = new std::string(ossPsd.str());
FairMQParts parts;
parts.AddPart(std::move(messTsMeta));
/*
parts.AddPart( NewMessage( const_cast< char * >( strMsgTsMetaE->c_str() ), // data
strMsgTsMetaE->length(), // size
[]( void* , void* object ){ delete static_cast< std::string * >( object ); },
strMsgTsMetaE
)
); // object that manages the data
*/
parts.AddPart(NewMessage(
const_cast<char*>(strMsgBmon->c_str()), // data
strMsgBmon->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgBmon)); // object that manages the data
parts.AddPart(NewMessage(
const_cast<char*>(strMsgSts->c_str()), // data
strMsgSts->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgSts)); // object that manages the data
parts.AddPart(NewMessage(
const_cast<char*>(strMsgMuch->c_str()), // data
strMsgMuch->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgMuch)); // object that manages the data
parts.AddPart(NewMessage(
const_cast<char*>(strMsgTrd->c_str()), // data
strMsgTrd->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgTrd)); // object that manages the data
parts.AddPart(NewMessage(
const_cast<char*>(strMsgTof->c_str()), // data
strMsgTof->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgTof)); // object that manages the data
parts.AddPart(NewMessage(
const_cast<char*>(strMsgRich->c_str()), // data
strMsgRich->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgRich)); // object that manages the data
parts.AddPart(NewMessage(
const_cast<char*>(strMsgPsd->c_str()), // data
strMsgPsd->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgPsd)); // object that manages the data
if (Send(parts, fsChannelNameDataOutput) < 0) {
LOG(error) << "Problem sending data to " << fsChannelNameDataOutput;
return false;
}
return true;
}
CbmDeviceMcbmUnpack::~CbmDeviceMcbmUnpack()
{
if (nullptr != fUnpAlgoSts) delete fUnpAlgoSts;
if (nullptr != fUnpAlgoMuch) delete fUnpAlgoMuch;
if (nullptr != fUnpAlgoTrd) delete fUnpAlgoTrd;
if (nullptr != fUnpAlgoTof) delete fUnpAlgoTof;
if (nullptr != fUnpAlgoRich) delete fUnpAlgoRich;
if (nullptr != fUnpAlgoPsd) delete fUnpAlgoPsd;
}
Bool_t CbmDeviceMcbmUnpack::DoUnpack(const fles::Timeslice& ts, size_t /*component*/)
{
fulTsCounter++;
if (kFALSE == fbComponentsAddedToList) {
for (uint32_t uCompIdx = 0; uCompIdx < ts.num_components(); ++uCompIdx) {
switch (ts.descriptor(uCompIdx, 0).sys_id) {
case kusSysIdSts: {
fUnpAlgoSts->AddMsComponentToList(uCompIdx, kusSysIdSts);
break;
} // case kusSysIdSts
case kusSysIdMuch: {
fUnpAlgoMuch->AddMsComponentToList(uCompIdx, kusSysIdMuch);
break;
} // case kusSysIdMuch
case kusSysIdTrd: {
fUnpAlgoTrd->AddMsComponentToList(uCompIdx, kusSysIdTrd);
break;
} // case kusSysIdTrd
case kusSysIdTof: {
fUnpAlgoTof->AddMsComponentToList(uCompIdx, kusSysIdTof);
break;
} // case kusSysIdTof
case kusSysIdBmon: {
fUnpAlgoTof->AddMsComponentToList(uCompIdx, kusSysIdBmon);
break;
} // case kusSysIdBmon
case kusSysIdRich: {
fUnpAlgoRich->AddMsComponentToList(uCompIdx, kusSysIdRich);
break;
} // case kusSysIdRich
case kusSysIdPsd: {
fUnpAlgoPsd->AddMsComponentToList(uCompIdx, kusSysIdPsd);
break;
} // case kusSysIdPsd
default: break;
} // switch( ts.descriptor( uCompIdx, 0 ).sys_id )
} // for( uint32_t uComp = 0; uComp < ts.num_components(); ++uComp )
fbComponentsAddedToList = kTRUE;
} // if( kFALSE == fbComponentsAddedToList )
if (kFALSE == fUnpAlgoSts->ProcessTs(ts)) {
LOG(error) << "Failed processing TS " << ts.index() << " in STS unpacker algorithm class";
return kFALSE;
} // if( kFALSE == fUnpAlgoSts->ProcessTs( ts ) )
if (kFALSE == fUnpAlgoMuch->ProcessTs(ts)) {
LOG(error) << "Failed processing TS " << ts.index() << " in MUCH unpacker algorithm class";
return kFALSE;
} // if( kFALSE == fUnpAlgoMuch->ProcessTs( ts ) )
if (kFALSE == fUnpAlgoTrd->ProcessTs(ts)) {
LOG(error) << "Failed processing TS " << ts.index() << " in TRD unpacker algorithm class";
return kFALSE;
} // if( kFALSE == fUnpAlgoTrd->ProcessTs( ts ) )
if (kFALSE == fUnpAlgoTof->ProcessTs(ts)) {
LOG(error) << "Failed processing TS " << ts.index() << " in TOF unpacker algorithm class";
return kFALSE;
} // if( kFALSE == fUnpAlgoTof->ProcessTs( ts ) )
if (kFALSE == fUnpAlgoRich->ProcessTs(ts)) {
LOG(error) << "Failed processing TS " << ts.index() << " in RICH unpacker algorithm class";
return kFALSE;
} // if( kFALSE == fUnpAlgoRich->ProcessTs( ts ) )
if (kFALSE == fUnpAlgoPsd->ProcessTs(ts)) {
LOG(error) << "Failed processing TS " << ts.index() << " in PSD unpacker algorithm class";
return kFALSE;
} // if( kFALSE == fUnpAlgoPsd->ProcessTs( ts ) )
if (0 == fulTsCounter % 10000) LOG(info) << "Processed " << fulTsCounter << " time slices";
return kTRUE;
}
void CbmDeviceMcbmUnpack::Finish() {}
/* Copyright (C) 2020 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceMcbmUnpack.h
*
* @since 2020-05-04
* @author P.-A. Loizeau
*/
#ifndef CBMDEVICEMCBMUNPACK_H_
#define CBMDEVICEMCBMUNPACK_H_
#include "CbmMqTMessage.h"
#include "Timeslice.hpp"
#include "FairMQDevice.h"
#include "Rtypes.h"
#include "TObjArray.h"
#include <map>
#include <vector>
class TList;
class CbmMcbm2018UnpackerAlgoSts;
class CbmMcbm2018UnpackerAlgoMuch;
class CbmMcbm2018UnpackerAlgoTrdR;
class CbmMcbm2018UnpackerAlgoTof;
class CbmMcbm2018UnpackerAlgoRich;
class CbmMcbm2018UnpackerAlgoPsd;
class TimesliceMetaData;
class CbmDeviceMcbmUnpack : public FairMQDevice {
public:
CbmDeviceMcbmUnpack();
virtual ~CbmDeviceMcbmUnpack();
protected:
virtual void InitTask();
bool HandleData(FairMQMessagePtr&, int);
bool HandleCommand(FairMQMessagePtr&, int);
private:
/// Constants
static const uint16_t kusSysIdSts = 0x10;
static const uint16_t kusSysIdMuch = 0x50;
static const uint16_t kusSysIdTrd = 0x40;
static const uint16_t kusSysIdTof = 0x60;
static const uint16_t kusSysIdBmon = 0x90;
static const uint16_t kusSysIdRich = 0x30;
static const uint16_t kusSysIdPsd = 0x80;
/// Control flags
Bool_t fbIgnoreOverlapMs = false; //! Ignore Overlap Ms: all fuOverlapMsNb MS at the end of timeslice
Bool_t fbComponentsAddedToList = kFALSE;
/// User settings parameters
std::string fsChannelNameDataInput = "fullts";
std::string fsChannelNameDataOutput = "unpts_0";
std::string fsChannelNameCommands = "commands";
UInt_t fuDigiMaskedIdBmon = 0x00005006;
UInt_t fuDigiMaskId = 0x0001FFFF;
/// List of MQ channels names
std::vector<std::string> fsAllowedChannels = {fsChannelNameDataInput};
/// Parameters management
// TList* fParCList = nullptr;
Bool_t InitParameters(TList* fParCList);
/// Statistics & first TS rejection
uint64_t fulNumMessages = 0;
uint64_t fulTsCounter = 0;
/// Processing algos
CbmMcbm2018UnpackerAlgoSts* fUnpAlgoSts = nullptr;
CbmMcbm2018UnpackerAlgoMuch* fUnpAlgoMuch = nullptr;
CbmMcbm2018UnpackerAlgoTrdR* fUnpAlgoTrd = nullptr;
CbmMcbm2018UnpackerAlgoTof* fUnpAlgoTof = nullptr;
CbmMcbm2018UnpackerAlgoRich* fUnpAlgoRich = nullptr;
CbmMcbm2018UnpackerAlgoPsd* fUnpAlgoPsd = nullptr;
/// Time offsets
std::vector<std::string> fvsSetTimeOffs = {};
/// TS MetaData storage
size_t fuNbCoreMsPerTs = 0; //!
size_t fuNbOverMsPerTs = 0; //!
Double_t fdMsSizeInNs = 1280000; //! Size of a single MS, [nanoseconds]
Double_t fdTsCoreSizeInNs = -1.0; //! Total size of the core MS in a TS, [nanoseconds]
Double_t fdTsOverSizeInNs = -1.0; //! Total size of the overlap MS in a TS, [nanoseconds]
Double_t fdTsFullSizeInNs = -1.0; //! Total size of all MS in a TS, [nanoseconds]
TimesliceMetaData* fTsMetaData;
bool IsChannelNameAllowed(std::string channelName);
Bool_t InitContainers();
Bool_t DoUnpack(const fles::Timeslice& ts, size_t component);
void Finish();
bool SendUnpData();
};
#endif /* CBMDEVICEMCBMUNPACK_H_ */
/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceUnpack.cxx
*
* @since 2020-05-04
* @author P.-A. Loizeau
*/
#include "CbmDeviceUnpack.h"
#include "CbmBmonUnpackConfig.h"
#include "CbmFlesCanvasTools.h"
#include "CbmMQDefs.h"
#include "CbmMuchUnpackConfig.h"
#include "CbmPsdUnpackConfig.h"
#include "CbmRichUnpackConfig.h"
#include "CbmSetup.h"
#include "CbmStsUnpackConfig.h"
#include "CbmTofUnpackConfig.h"
#include "CbmTrdUnpackConfig.h"
#include "CbmTrdUnpackFaspConfig.h"
#include "StorableTimeslice.hpp"
#include "TimesliceMetaData.h"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairParGenericSet.h"
#include "TCanvas.h"
#include "TFile.h"
#include "TH1.h"
#include "TList.h"
#include "TNamed.h"
#include "BoostSerializer.h"
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/utility.hpp>
#include <array>
#include <iomanip>
#include <stdexcept>
#include <string>
#include <utility>
#include "RootSerializer.h"
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
using namespace std;
//Bool_t bMcbm2018MonitorTaskBmonResetHistos = kFALSE;
CbmDeviceUnpack::CbmDeviceUnpack() {}
void CbmDeviceUnpack::InitTask()
try {
/// Read options from executable
LOG(info) << "Init options for CbmDeviceUnpack.";
fsSetupName = fConfig->GetValue<std::string>("Setup");
fuRunId = fConfig->GetValue<uint32_t>("RunId");
fbUnpBmon = fConfig->GetValue<bool>("UnpBmon");
fbUnpSts = fConfig->GetValue<bool>("UnpSts");
fbUnpMuch = fConfig->GetValue<bool>("UnpMuch");
fbUnpTrd1D = fConfig->GetValue<bool>("UnpTrd1d");
fbUnpTrd2D = fConfig->GetValue<bool>("UnpTrd2d");
fbUnpTof = fConfig->GetValue<bool>("UnpTof");
fbUnpRich = fConfig->GetValue<bool>("UnpRich");
fbUnpPsd = fConfig->GetValue<bool>("UnpPsd");
fbIgnoreOverlapMs = fConfig->GetValue<bool>("IgnOverMs");
fbOutputFullTimeSorting = fConfig->GetValue<bool>("FullTimeSort");
fvsSetTimeOffs = fConfig->GetValue<std::vector<std::string>>("SetTimeOffs");
fsChannelNameDataInput = fConfig->GetValue<std::string>("TsNameIn");
fsChannelNameDataOutput = fConfig->GetValue<std::string>("TsNameOut");
fuPublishFreqTs = fConfig->GetValue<uint32_t>("PubFreqTs");
fdMinPublishTime = fConfig->GetValue<double_t>("PubTimeMin");
fdMaxPublishTime = fConfig->GetValue<double_t>("PubTimeMax");
fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
}
Bool_t CbmDeviceUnpack::InitContainers()
{
LOG(info) << "Init parameter containers for CbmDeviceUnpack.";
// ----- FIXME: Environment settings? or binary option?
TString srcDir = std::getenv("VMCWORKDIR"); // top source directory, standard C++ library
// TString srcDir = gSystem->Getenv("VMCWORKDIR"); // top source directory
// ----- CbmSetup -----------------------------------------------------
// TODO: support for multiple setups on Par Server? with request containing setup name?
CbmSetup* cbmsetup = CbmSetup::Instance();
FairMQMessagePtr req(NewSimpleMessage("setup"));
FairMQMessagePtr rep(NewMessage());
if (Send(req, "parameters") > 0) {
if (Receive(rep, "parameters") >= 0) {
if (0 != rep->GetSize()) {
CbmSetupStorable* exchangableSetup;
CbmMqTMessage tmsg(rep->GetData(), rep->GetSize());
exchangableSetup = dynamic_cast<CbmSetupStorable*>(tmsg.ReadObject(tmsg.GetClass()));
if (nullptr != exchangableSetup) {
/// Prevent clang format single line if
cbmsetup->LoadStoredSetup(exchangableSetup);
}
else {
LOG(error) << "Received corrupt reply. Setup not available";
throw InitTaskError("Setup not received from par-server.");
}
} // if( 0 != rep->GetSize() )
else {
LOG(error) << "Received empty reply. Setup not available";
throw InitTaskError("Setup not received from par-server.");
} // else of if( 0 != rep->GetSize() )
} // if( Receive( rep, "parameters" ) >= 0)
} // if( Send(req, "parameters") > 0 )
// ------------------------------------------------------------------------
/// Initialize the UnpackerConfigs objects and their "user options"
// ---- BMON ----
std::shared_ptr<CbmBmonUnpackConfig> bmonconfig = nullptr;
if (fbUnpBmon) {
bmonconfig = std::make_shared<CbmBmonUnpackConfig>("", fuRunId);
if (bmonconfig) {
// bmonconfig->SetDebugState();
bmonconfig->SetDoWriteOutput();
// bmonconfig->SetDoWriteOptOutA("CbmBmonErrors");
std::string parfilesbasepathBmon = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
bmonconfig->SetParFilesBasePath(parfilesbasepathBmon);
bmonconfig->SetParFileName("mBmonCriPar.par");
bmonconfig->SetSystemTimeOffset(-1220); // [ns] value to be updated
if (2160 <= fuRunId) {
bmonconfig->SetSystemTimeOffset(-80); // [ns] value to be updated
}
if (2350 <= fuRunId) {
bmonconfig->SetSystemTimeOffset(0); // [ns] value to be updated
}
/// Enable Monitor plots
// bmonconfig->SetMonitor(GetTofMonitor(outfilename, true)); // FIXME: Unsupported for now
}
}
// -------------
// ---- STS ----
std::shared_ptr<CbmStsUnpackConfig> stsconfig = nullptr;
TString stsSetupTag = "";
cbmsetup->GetGeoTag(ECbmModuleId::kSts, stsSetupTag);
if ("" != stsSetupTag && fbUnpSts) {
LOG(info) << "From received setup, using STS tag: " << stsSetupTag;
stsconfig = std::make_shared<CbmStsUnpackConfig>(std::string(fsSetupName), fuRunId);
if (stsconfig) {
// stsconfig->SetDebugState();
stsconfig->SetDoWriteOutput();
stsconfig->SetDoWriteOptOutA("StsDigiPulser");
std::string parfilesbasepathSts = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data());
if (2060 <= fuRunId) {
/// Starting to readout the U3 since 10/03/2022 Carbon run
parfilesbasepathSts = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
}
stsconfig->SetParFilesBasePath(parfilesbasepathSts);
/// Enable duplicates rejection, Ignores the ADC for duplicates check
stsconfig->SetDuplicatesRejection(true, true);
/// Enable Monitor plots
// stsconfig->SetMonitor(GetStsMonitor(outfilename, true)); // FIXME: Unsupported for now
stsconfig->SetSystemTimeOffset(-2221); // [ns] value to be updated
if (2160 <= fuRunId) {
stsconfig->SetSystemTimeOffset(-1075); // [ns] value to be updated
}
if (2350 <= fuRunId) {
stsconfig->SetSystemTimeOffset(-970); // [ns] value to be updated
}
stsconfig->SetMinAdcCut(1, 1);
stsconfig->SetMinAdcCut(2, 1);
stsconfig->SetMinAdcCut(3, 1);
stsconfig->SetMinAdcCut(4, 1);
stsconfig->MaskNoisyChannel(3, 56);
stsconfig->MaskNoisyChannel(3, 75);
stsconfig->MaskNoisyChannel(3, 79);
stsconfig->MaskNoisyChannel(3, 85);
stsconfig->MaskNoisyChannel(7, 123);
stsconfig->MaskNoisyChannel(7, 124);
stsconfig->MaskNoisyChannel(7, 125);
stsconfig->MaskNoisyChannel(7, 158);
stsconfig->MaskNoisyChannel(7, 159);
stsconfig->MaskNoisyChannel(7, 162);
stsconfig->MaskNoisyChannel(7, 715);
stsconfig->MaskNoisyChannel(9, 709);
stsconfig->MaskNoisyChannel(12, 119);
// Time Walk correction
std::map<uint32_t, CbmStsParModule> walkMap;
auto parAsic = new CbmStsParAsic(128, 31, 31., 1., 5., 800., 1000., 3.9789e-3);
// Module params: number of channels, number of channels per ASIC
auto parMod = new CbmStsParModule(2048, 128);
// default
double p0 = 0, p1 = 0, p2 = 0, p3 = 0;
parAsic->SetWalkCoef({p0, p1, p2, p3});
parMod->SetAllAsics(*parAsic);
walkMap[0x10107C02] = CbmStsParModule(*parMod); // Make a copy for storage
walkMap[0x101FFC02] = CbmStsParModule(*parMod); // Make a copy for storage
/// To be replaced by a storage in a new parameter class later
int sensor, asic;
std::ifstream asicTimeWalk_par(Form("%s/mStsAsicTimeWalk.par", parfilesbasepathSts.data()));
while (asicTimeWalk_par >> std::hex >> sensor >> std::dec >> asic >> p0 >> p1 >> p2 >> p3) {
std::cout << Form("Setting time-walk parametersfor: module %x, ASIC %u\n", sensor, asic);
parAsic->SetWalkCoef({p0, p1, p2, p3});
if (walkMap.find(sensor) == walkMap.end()) { walkMap[sensor] = CbmStsParModule(*parMod); }
walkMap[sensor].SetAsic(asic, *parAsic);
}
stsconfig->SetWalkMap(walkMap);
}
} // if ("" != stsSetupTag)
// -------------
// ---- MUCH ----
std::shared_ptr<CbmMuchUnpackConfig> muchconfig = nullptr;
TString muchSetupTag = "";
cbmsetup->GetGeoTag(ECbmModuleId::kMuch, muchSetupTag);
if ("" != muchSetupTag && fbUnpMuch) {
LOG(info) << "From received setup, using MUCH tag: " << muchSetupTag;
muchconfig = std::make_shared<CbmMuchUnpackConfig>(std::string(fsSetupName), fuRunId);
if (muchconfig) {
// muchconfig->SetDebugState();
muchconfig->SetDoWriteOutput();
muchconfig->SetDoWriteOptOutA("MuchDigiPulser");
std::string parfilesbasepathMuch = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
muchconfig->SetParFilesBasePath(parfilesbasepathMuch);
if (2060 <= fuRunId && fuRunId <= 2162) {
/// Starting to use CRI Based MUCH setup with 2GEM and 1 RPC since 09/03/2022 Carbon run
muchconfig->SetParFileName("mMuchParUpto26032022.par");
}
else if (2163 <= fuRunId && fuRunId <= 2291) {
/// First nickel runs
muchconfig->SetParFileName("mMuchParUpto03042022.par");
}
else if (2311 <= fuRunId && fuRunId <= 2315) {
///
muchconfig->SetParFileName("mMuchParUpto10042022.par");
}
else if (2316 <= fuRunId && fuRunId <= 2366) {
///
muchconfig->SetParFileName("mMuchParUpto23052022.par");
}
else if (2367 <= fuRunId && fuRunId <= 2397) {
/// Starting to use GEM 2 moved to CRI 0 on 24/05/2022
muchconfig->SetParFileName("mMuchParUpto26052022.par");
}
/// Enable duplicates rejection, Ignores the ADC for duplicates check
muchconfig->SetDuplicatesRejection(true, true);
/// Enable Monitor plots
//muchconfig->SetMonitor(GetMuchMonitor(outfilename, true));
muchconfig->SetSystemTimeOffset(-2221); // [ns] value to be updated
if (2160 <= fuRunId) {
muchconfig->SetSystemTimeOffset(-1020); // [ns] value to be updated
}
if (2350 <= fuRunId) {
muchconfig->SetSystemTimeOffset(-980); // [ns] value to be updated
}
// muchconfig->SetMinAdcCut(1, 1);
// muchconfig->MaskNoisyChannel(3, 56);
}
}
// -------------
// ---- TRD ----
std::shared_ptr<CbmTrdUnpackConfig> trd1Dconfig = nullptr;
TString trdsetuptag = "";
cbmsetup->GetGeoTag(ECbmModuleId::kTrd, trdsetuptag);
if ("" != trdsetuptag && fbUnpTrd1D) {
LOG(info) << "From received setup, using TRD tag: " << trdsetuptag;
// trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), fuRunId);
trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), 3);
if (trd1Dconfig) {
trd1Dconfig->SetDoWriteOutput();
// Activate the line below to write Trd1D digis to a separate "TrdSpadicDigi" branch. Can be used to separate between Fasp and Spadic digis
// trd1Dconfig->SetOutputBranchName("TrdSpadicDigi");
// trd1Dconfig->SetDoWriteOptOutA(CbmTrdRawMessageSpadic::GetBranchName());
// trd1Dconfig->SetDoWriteOptOutB("SpadicInfoMessages"); // SpadicInfoMessages
std::string parfilesbasepathTrd = Form("%s/parameters/trd", srcDir.Data());
trd1Dconfig->SetParFilesBasePath(parfilesbasepathTrd);
// trd1Dconfig->SetMonitor(GetTrdMonitor(outfilename)); // FIXME: Unsupported for now
// Get the spadic configuration true = avg baseline active / false plain sample 0
trd1Dconfig->SetSpadicObject(GetTrdSpadic(true));
trd1Dconfig->SetSystemTimeOffset(0); // [ns] value to be updated
if (2160 <= fuRunId) {
trd1Dconfig->SetSystemTimeOffset(1140); // [ns] value to be updated
}
if (2350 <= fuRunId) {
trd1Dconfig->SetSystemTimeOffset(1300); // [ns] value to be updated
}
}
} // if ("" != trdsetuptag)
// -------------
// ---- TRDFASP2D ----
std::shared_ptr<CbmTrdUnpackFaspConfig> trdfasp2dconfig = nullptr;
if ("" != trdsetuptag && fbUnpTrd2D) {
trdfasp2dconfig = std::make_shared<CbmTrdUnpackFaspConfig>(trdsetuptag.Data());
if (trdfasp2dconfig) {
// trdfasp2dconfig->SetDebugState();
trdfasp2dconfig->SetDoWriteOutput();
// Activate the line below to write Trd1D digis to a separate "TrdFaspDigi" branch. Can be used to separate between Fasp and Spadic digis
//trdfasp2dconfig->SetOutputBranchName("TrdFaspDigi");
// uint16_t crob_map[NCROBMOD];
// if (fuRunId <= 1588) {
// uint16_t crob_map21[] = {0x00f0, 0, 0, 0, 0};
// for (uint32_t i(0); i < NCROBMOD; i++)
// crob_map[i] = crob_map21[i];
// }
// else if (fuRunId >= 2335) {
// uint16_t crob_map22[] = {0xffc2, 0xffc5, 0xffc1, 0, 0};
// for (uint32_t i(0); i < NCROBMOD; i++)
// crob_map[i] = crob_map22[i];
// }
// trdfasp2dconfig->SetCrobMapping(5, crob_map);
std::string parfilesbasepathTrdfasp2d = Form("%s/parameters/trd", srcDir.Data());
trdfasp2dconfig->SetParFilesBasePath(parfilesbasepathTrdfasp2d);
trdfasp2dconfig->SetSystemTimeOffset(-1800); // [ns] value to be updated
if (2160 <= fuRunId) {
trdfasp2dconfig->SetSystemTimeOffset(-570); // [ns] value to be updated
}
if (2350 <= fuRunId) {
trdfasp2dconfig->SetSystemTimeOffset(-510); // [ns] value to be updated
}
}
} // if ("" != trdsetuptag)
// -------------
// ---- TOF ----
std::shared_ptr<CbmTofUnpackConfig> tofconfig = nullptr;
TString tofSetupTag = "";
cbmsetup->GetGeoTag(ECbmModuleId::kTof, tofSetupTag);
if ("" != tofSetupTag && fbUnpTof) {
LOG(info) << "From received setup, using TOF tag: " << tofSetupTag;
tofconfig = std::make_shared<CbmTofUnpackConfig>("", fuRunId);
if (tofconfig) {
// tofconfig->SetDebugState();
tofconfig->SetDoWriteOutput();
// tofconfig->SetDoWriteOptOutA("CbmTofErrors");
std::string parfilesbasepathTof = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data());
std::string parFileNameTof = "mTofCriPar.par";
if (2060 <= fuRunId) {
/// Additional modules added just before the 10/03/2022 Carbon run
parfilesbasepathTof = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
/// Setup changed multiple times between the 2022 carbon and uranium runs
if (fuRunId <= 2065) {
/// Carbon runs: 2060 - 2065
parFileNameTof = "mTofCriParCarbon.par";
}
else if (2150 <= fuRunId && fuRunId <= 2160) {
/// Iron runs: 2150 - 2160
parFileNameTof = "mTofCriParIron.par";
}
else if (2176 <= fuRunId && fuRunId <= 2310) {
/// Uranium runs: 2176 - 2310
parFileNameTof = "mTofCriParUranium.par";
}
else if (2335 <= fuRunId && fuRunId <= 2497) {
/// Nickel runs: 2335 - 2397
/// Gold runs: 2400 - 2497
parFileNameTof = "mTofCriParNickel.par";
}
else {
parFileNameTof = "mTofCriPar.par";
}
}
tofconfig->SetParFilesBasePath(parfilesbasepathTof);
tofconfig->SetParFileName(parFileNameTof);
tofconfig->SetSystemTimeOffset(-1220); // [ns] value to be updated
if (2160 <= fuRunId) {
tofconfig->SetSystemTimeOffset(0); // [ns] value to be updated
}
if (2350 <= fuRunId) {
tofconfig->SetSystemTimeOffset(45); // [ns] value to be updated
}
if (fuRunId <= 1659) {
/// Switch ON the -4 offset in epoch count (hack for Spring-Summer 2021)
tofconfig->SetFlagEpochCountHack2021();
}
}
} // if ("" != tofSetupTag)
// -------------
// ---- RICH ----
std::shared_ptr<CbmRichUnpackConfig> richconfig = nullptr;
TString richSetupTag = "";
cbmsetup->GetGeoTag(ECbmModuleId::kRich, richSetupTag);
if ("" != richSetupTag && fbUnpRich) {
LOG(info) << "From received setup, using RICH tag: " << richSetupTag;
richconfig = std::make_shared<CbmRichUnpackConfig>("", fuRunId);
if (richconfig) {
if (1904 < fuRunId) {
/// Switch to new unpacking algo starting from first combined cosmics run in 2022
richconfig->SetUnpackerVersion(CbmRichUnpackerVersion::v03);
}
richconfig->DoTotOffsetCorrection(); // correct ToT offset
richconfig->SetDebugState();
richconfig->SetDoWriteOutput();
std::string parfilesbasepathRich = Form("%s/macro/beamtime/mcbm2024/", srcDir.Data());
richconfig->SetParFilesBasePath(parfilesbasepathRich);
richconfig->SetSystemTimeOffset(256000 - 1200); // [ns] 1 MS and additional correction
if (1904 < fuRunId) richconfig->SetSystemTimeOffset(-1200);
if (2160 <= fuRunId) {
richconfig->SetSystemTimeOffset(50); // [ns] value to be updated
}
if (2350 <= fuRunId) {
richconfig->SetSystemTimeOffset(100); // [ns] value to be updated
}
if (1588 == fuRunId) richconfig->MaskDiRICH(0x7150);
}
} // if ("" != richSetupTag)
// -------------
// ---- PSD ----
std::shared_ptr<CbmPsdUnpackConfig> psdconfig = nullptr;
TString psdSetupTag = "";
cbmsetup->GetGeoTag(ECbmModuleId::kPsd, psdSetupTag);
if ("" != psdSetupTag && fbUnpPsd) {
LOG(info) << "From received setup, using PSD tag: " << psdSetupTag;
psdconfig = std::make_shared<CbmPsdUnpackConfig>("", fuRunId);
if (psdconfig) {
// psdconfig->SetDebugState();
psdconfig->SetDoWriteOutput();
// psdconfig->SetDoWriteOptOutA("CbmPsdDsp");
std::string parfilesbasepathPsd = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data());
psdconfig->SetParFilesBasePath(parfilesbasepathPsd);
psdconfig->SetSystemTimeOffset(0); // [ns] value to be updated
}
} // if ("" != psdSetupTag)
// -------------
/// Enable full time sorting instead of time sorting per FLIM link
if (stsconfig) SetUnpackConfig(stsconfig);
if (muchconfig) SetUnpackConfig(muchconfig);
if (trd1Dconfig) SetUnpackConfig(trd1Dconfig);
if (trdfasp2dconfig) SetUnpackConfig(trdfasp2dconfig);
if (tofconfig) SetUnpackConfig(tofconfig);
if (bmonconfig) SetUnpackConfig(bmonconfig);
if (richconfig) SetUnpackConfig(richconfig);
if (psdconfig) SetUnpackConfig(psdconfig);
/// Load time offsets
for (std::vector<std::string>::iterator itStrOffs = fvsSetTimeOffs.begin(); itStrOffs != fvsSetTimeOffs.end();
++itStrOffs) {
size_t charPosDel = (*itStrOffs).find(',');
if (std::string::npos == charPosDel) {
LOG(info) << "CbmDeviceUnpack::InitContainers => "
<< "Trying to set trigger window with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found " << (*itStrOffs) << " )";
} // if( std::string::npos == charPosDel )
/// Detector Enum Tag
std::string sSelDet = (*itStrOffs).substr(0, charPosDel);
/// Min number
charPosDel++;
int32_t iOffset = std::stoi((*itStrOffs).substr(charPosDel));
if ("kBmon" == sSelDet && fBmonConfig) { //
fBmonConfig->SetSystemTimeOffset(iOffset);
} // else if( "kBmon" == sSelDet )
else if ("kSTS" == sSelDet && fStsConfig) { //
fStsConfig->SetSystemTimeOffset(iOffset);
} // if( "kSTS" == sSelDet && fStsConfig)
else if ("kMUCH" == sSelDet && fMuchConfig) {
fMuchConfig->SetSystemTimeOffset(iOffset);
} // else if( "kMUCH" == sSelDet )
else if ("kTRD" == sSelDet && fTrd1DConfig) {
fTrd1DConfig->SetSystemTimeOffset(iOffset);
} // else if( "kTRD" == sSelDet && fTrd2DConfig )
else if ("kTRD2D" == sSelDet && fTrd2DConfig) {
fTrd2DConfig->SetSystemTimeOffset(iOffset);
} // else if( "kTRD" == sSelDet && fTrd2DConfig )
else if ("kTOF" == sSelDet && fTofConfig) {
fTofConfig->SetSystemTimeOffset(iOffset);
} // else if( "kTOF" == sSelDet && fTofConfig)
else if ("kRICH" == sSelDet && fRichConfig) {
fRichConfig->SetSystemTimeOffset(iOffset);
} // else if( "kRICH" == sSelDet && fRichConfig)
else if ("kPSD" == sSelDet && fPsdConfig) {
fPsdConfig->SetSystemTimeOffset(iOffset);
} // else if( "kPSD" == sSelDet )
else {
LOG(info) << "CbmDeviceUnpack::InitContainers => Trying to set time "
"offset for unsupported detector, ignored! "
<< (sSelDet);
continue;
} // else of detector enum detection
} // for( std::vector< std::string >::iterator itStrAdd = fvsAddDet.begin(); itStrAdd != fvsAddDet.end(); ++itStrAdd )
Bool_t initOK = kTRUE;
// --- Sts
if (fStsConfig) {
fStsConfig->InitOutput();
// RegisterOutputs( ioman, fStsConfig ); /// Framework bound work = kept in this Task
fStsConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
fStsConfig->SetAlgo();
initOK &= InitParameters(fStsConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fStsConfig->InitAlgo();
// initPerformanceMaps(fkFlesSts, "STS");
}
// --- Much
if (fMuchConfig) {
fMuchConfig->InitOutput();
// RegisterOutputs(ioman, fMuchConfig); /// Framework bound work = kept in this Task
fMuchConfig->SetAlgo();
initOK &= InitParameters(fMuchConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fMuchConfig->InitAlgo();
// initPerformanceMaps(fkFlesMuch, "MUCH");
}
// --- Trd
if (fTrd1DConfig) {
fTrd1DConfig->InitOutput();
// RegisterOutputs( ioman, fTrd1DConfig ); /// Framework bound work = kept in this Task
fTrd1DConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
fTrd1DConfig->SetAlgo();
initOK &= InitParameters(fTrd1DConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fTrd1DConfig->InitAlgo();
// initPerformanceMaps(fkFlesTrd, "TRD1D");
}
// --- TRD2D
if (fTrd2DConfig) {
if (fTrd1DConfig && (fTrd2DConfig->GetOutputBranchName() == fTrd1DConfig->GetOutputBranchName())) {
LOG(info) << fTrd2DConfig->GetName() << "::Init() ---------------------------------";
fTrd2DConfig->SetOutputVec(fTrd1DConfig->GetOutputVec());
}
else {
fTrd2DConfig->InitOutput();
// RegisterOutputs( ioman, fTrd2DConfig ); /// Framework bound work = kept in this Task
}
fTrd2DConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
fTrd2DConfig->SetAlgo();
initOK &= InitParameters(fTrd2DConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fTrd2DConfig->InitAlgo();
// initPerformanceMaps(fkFlesTrd2D, "TRD2D");
}
// This is an ugly work around, because the TRD and TRD2D want to access the same vector and there is no
// function to retrieve a writeable vector<obj> from the FairRootManager, especially before the branches
// are created, as far as I am aware.
// The second option workaround is in in Init() to look for the fasp config and create a separate branch
// for fasp created CbmTrdDigis PR 072021
// --- Tof
if (fTofConfig) {
fTofConfig->InitOutput();
// RegisterOutputs( ioman, fTofConfig ); /// Framework bound work = kept in this Task
fTofConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
fTofConfig->SetAlgo();
initOK &= InitParameters(fTofConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
LOG(info) << "TOF call InitAlgo()";
fTofConfig->InitAlgo();
// initPerformanceMaps(fkFlesTof, "TOF");
}
// --- Bmon
if (fBmonConfig) {
fBmonConfig->InitOutput();
// RegisterOutputs(ioman, fBmonConfig); /// Framework bound work = kept in this Task
fBmonConfig->SetAlgo();
fBmonConfig->LoadParFileName(); /// Needed to change the Parameter file name before it is used!!!
initOK &= InitParameters(fBmonConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fBmonConfig->InitAlgo();
// initPerformanceMaps(fkFlesBmon, "Bmon");
}
// --- Rich
if (fRichConfig) {
fRichConfig->InitOutput();
// RegisterOutputs( ioman, fRichConfig ); /// Framework bound work = kept in this Task
fRichConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
fRichConfig->SetAlgo();
initOK &= InitParameters(fRichConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fRichConfig->InitAlgo();
// initPerformanceMaps(fkFlesRich, "RICH");
}
// --- Psd
if (fPsdConfig) {
fPsdConfig->InitOutput();
// RegisterOutputs( ioman, fPsdConfig ); /// Framework bound work = kept in this Task
fPsdConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
fPsdConfig->SetAlgo();
initOK &= InitParameters(fPsdConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fPsdConfig->InitAlgo();
// initPerformanceMaps(fkFlesPsd, "PSD");
}
/// Event header object
fCbmTsEventHeader = new CbmTsEventHeader();
return initOK;
}
Bool_t
CbmDeviceUnpack::InitParameters(std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* reqparvec)
{
LOG(info) << "CbmDeviceUnpack::InitParameters";
if (!reqparvec) {
LOG(info) << "CbmDeviceUnpack::InitParameters - empty requirements vector no parameters initialized.";
return kTRUE;
}
// Now get the actual ascii files and init the containers with the asciiIo
for (auto& pair : *reqparvec) {
/*
auto filepath = pair.first;
auto parset = pair.second;
FairParAsciiFileIo asciiInput;
if (!filepath.empty()) {
if (asciiInput.open(filepath.data())) { parset->init(&asciiInput); }
}
* */
std::string paramName {pair.second->GetName()};
// NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
// Should only be used for small data because of the cost of an additional copy
// Here must come the proper Runid
std::string message = paramName + ",111";
LOG(info) << "Requesting parameter container " << paramName << ", sending message: " << message;
FairMQMessagePtr req(NewSimpleMessage(message));
FairMQMessagePtr rep(NewMessage());
FairParGenericSet* newObj = nullptr;
if (Send(req, "parameters") > 0) {
if (Receive(rep, "parameters") >= 0) {
if (0 != rep->GetSize()) {
CbmMqTMessage tmsg(rep->GetData(), rep->GetSize());
newObj = static_cast<FairParGenericSet*>(tmsg.ReadObject(tmsg.GetClass()));
LOG(info) << "Received unpack parameter from the server: " << newObj->GetName();
newObj->print();
} // if( 0 != rep->GetSize() )
else {
LOG(error) << "Received empty reply. Parameter not available";
return kFALSE;
} // else of if( 0 != rep->GetSize() )
} // if( Receive( rep, "parameters" ) >= 0)
} // if( Send(req, "parameters") > 0 )
pair.second.reset(newObj); /// Potentially unsafe reasignment of raw pointer to the shared pointer?
//delete newObj;
}
return kTRUE;
}
bool CbmDeviceUnpack::InitHistograms()
{
/// Histos creation and obtain pointer on them
/// Trigger histo creation on all associated algos
// ALGO: bool initOK = fMonitorAlgo->CreateHistograms();
bool initOK = true;
/// Obtain vector of pointers on each histo from the algo (+ optionally desired folder)
// ALGO: std::vector<std::pair<TNamed*, std::string>> vHistos = fMonitorAlgo->GetHistoVector();
std::vector<std::pair<TNamed*, std::string>> vHistos = {};
/// Obtain vector of pointers on each canvas from the algo (+ optionally desired folder)
// ALGO: std::vector<std::pair<TCanvas*, std::string>> vCanvases = fMonitorAlgo->GetCanvasVector();
std::vector<std::pair<TCanvas*, std::string>> vCanvases = {};
/// Add pointers to each histo in the histo array
/// Create histo config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Histo name, Folder >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto) {
// LOG(info) << "Registering " << vHistos[ uHisto ].first->GetName()
// << " in " << vHistos[ uHisto ].second.data()
// ;
fArrayHisto.Add(vHistos[uHisto].first);
std::pair<std::string, std::string> psHistoConfig(vHistos[uHisto].first->GetName(), vHistos[uHisto].second);
fvpsHistosFolder.push_back(psHistoConfig);
LOG(info) << "Config of hist " << psHistoConfig.first.data() << " in folder " << psHistoConfig.second.data();
} // for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto )
/// Create canvas config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Canvas name, config >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv) {
// LOG(info) << "Registering " << vCanvases[ uCanv ].first->GetName()
// << " in " << vCanvases[ uCanv ].second.data();
std::string sCanvName = (vCanvases[uCanv].first)->GetName();
std::string sCanvConf = GenerateCanvasConfigString(vCanvases[uCanv].first);
std::pair<std::string, std::string> psCanvConfig(sCanvName, sCanvConf);
fvpsCanvasConfig.push_back(psCanvConfig);
LOG(info) << "Config string of Canvas " << psCanvConfig.first.data() << " is " << psCanvConfig.second.data();
} // for( UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv )
return initOK;
}
// Method called by run loop and requesting new data from the TS source whenever
bool CbmDeviceUnpack::ConditionalRun()
{
/// First do Algo related Initialization steps if needed
if (0 == fulNumMessages) {
try {
InitContainers();
}
catch (InitTaskError& e) {
LOG(error) << e.what();
ChangeState(fair::mq::Transition::ErrorFound);
}
} // if( 0 == fulNumMessages)
if (0 == fulNumMessages) InitHistograms();
/// First request a new TS (full one)
std::string message = "full";
LOG(debug) << "Requesting new TS by sending message: full" << message;
FairMQMessagePtr req(NewSimpleMessage(message));
FairMQMessagePtr rep(NewMessage());
if (Send(req, fsChannelNameDataInput) <= 0) {
LOG(error) << "Failed to send the request! message was " << message;
return false;
} // if (Send(req, fsChannelNameDataInput) <= 0)
else if (Receive(rep, fsChannelNameDataInput) < 0) {
LOG(error) << "Failed to receive a reply to the request! message was " << message;
return false;
} // else if (Receive(rep, fsChannelNameDataInput) < 0)
else if (rep->GetSize() == 0) {
LOG(error) << "Received empty reply. Something went wrong with the timeslice generation! message was " << message;
return false;
} // else if (rep->GetSize() == 0)
fulNumMessages++;
LOG(debug) << "Received message number " << fulNumMessages << " with size " << rep->GetSize();
if (0 == fulNumMessages % 10000) LOG(info) << "Received " << fulNumMessages << " messages";
std::string msgStr(static_cast<char*>(rep->GetData()), rep->GetSize());
std::istringstream iss(msgStr);
boost::archive::binary_iarchive inputArchive(iss);
/// Create an empty TS and fill it with the incoming message
fles::StorableTimeslice ts {0};
inputArchive >> ts;
/// On first TS, extract the TS parameters from header (by definition stable over time)
if (-1.0 == fdTsCoreSizeInNs) {
fuNbCoreMsPerTs = ts.num_core_microslices();
fuNbOverMsPerTs = ts.num_microslices(0) - ts.num_core_microslices();
fdMsSizeInNs = (ts.descriptor(0, fuNbCoreMsPerTs).idx - ts.descriptor(0, 0).idx) / fuNbCoreMsPerTs;
fdTsCoreSizeInNs = fdMsSizeInNs * (fuNbCoreMsPerTs);
fdTsOverSizeInNs = fdMsSizeInNs * (fuNbOverMsPerTs);
fdTsFullSizeInNs = fdTsCoreSizeInNs + fdTsOverSizeInNs;
LOG(info) << "Timeslice parameters: each TS has " << fuNbCoreMsPerTs << " Core MS and " << fuNbOverMsPerTs
<< " Overlap MS, for a MS duration of " << fdMsSizeInNs << " ns, a core duration of " << fdTsCoreSizeInNs
<< " ns and a full duration of " << fdTsFullSizeInNs << " ns";
fTsMetaData = new TimesliceMetaData(ts.descriptor(0, 0).idx, fdTsCoreSizeInNs, fdTsOverSizeInNs, ts.index());
} // if( -1.0 == fdTsCoreSizeInNs )
else {
/// Update only the fields changing from TS to TS
fTsMetaData->SetStartTime(ts.descriptor(0, 0).idx);
fTsMetaData->SetIndex(ts.index());
}
/// Process the Timeslice
DoUnpack(ts, 0);
LOG(debug) << "Unpack: Sending TS index " << ts.index();
/// Send digi vectors to ouput
if (!SendUnpData()) return false;
LOG(debug) << "Unpack: Sent TS index " << ts.index();
// Reset the event header for a new timeslice
fCbmTsEventHeader->Reset();
// Reset the unpackers for a new timeslice, e.g. clear the output vectors
// ---- Bmon ----
if (fBmonConfig) fBmonConfig->Reset();
// ---- Sts ----
if (fStsConfig) fStsConfig->Reset();
// ----Much ----
if (fMuchConfig) fMuchConfig->Reset();
// ---- Trd ----
if (fTrd1DConfig) fTrd1DConfig->Reset();
// ---- Trd2D ----
if (fTrd2DConfig) fTrd2DConfig->Reset();
// ---- Tof ----
if (fTofConfig) fTofConfig->Reset();
// ---- Rich ----
if (fRichConfig) fRichConfig->Reset();
// ---- Psd ----
if (fPsdConfig) fPsdConfig->Reset();
/// Send histograms each 100 time slices. Should be each ~1s
/// Use also runtime checker to trigger sending after M s if
/// processing too slow or delay sending if processing too fast
std::chrono::system_clock::time_point currentTime = std::chrono::system_clock::now();
std::chrono::duration<double_t> elapsedSeconds = currentTime - fLastPublishTime;
if ((fdMaxPublishTime < elapsedSeconds.count())
|| (0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count())) {
if (!fbConfigSent) {
// Send the configuration only once per run!
fbConfigSent = SendHistoConfAndData();
} // if( !fbConfigSent )
else
SendHistograms();
fLastPublishTime = std::chrono::system_clock::now();
} // if( ( fdMaxPublishTime < elapsedSeconds.count() ) || ( 0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count() ) )
return true;
}
bool CbmDeviceUnpack::SendUnpData()
{
FairMQParts parts;
/// Prepare serialized versions of the TS Event header
FairMQMessagePtr messTsHeader(NewMessage());
// Serialize<RootSerializer>(*messTsHeader, fCbmTsEventHeader);
RootSerializer().Serialize(*messTsHeader, fCbmTsEventHeader);
parts.AddPart(std::move(messTsHeader));
// ---- Bmon ----
std::stringstream ossBmon;
boost::archive::binary_oarchive oaBmon(ossBmon);
if (fBmonConfig) { //
oaBmon << *(fBmonConfig->GetOutputVec());
}
else {
oaBmon << (std::vector<CbmBmonDigi>());
}
std::string* strMsgBmon = new std::string(ossBmon.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgBmon->c_str()), // data
strMsgBmon->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgBmon)); // object that manages the data
// ---- Sts ----
std::stringstream ossSts;
boost::archive::binary_oarchive oaSts(ossSts);
if (fStsConfig) { //
oaSts << *(fStsConfig->GetOutputVec());
}
else {
oaSts << (std::vector<CbmStsDigi>());
}
std::string* strMsgSts = new std::string(ossSts.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgSts->c_str()), // data
strMsgSts->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgSts)); // object that manages the data
// ---- Much ----
std::stringstream ossMuch;
boost::archive::binary_oarchive oaMuch(ossMuch);
if (fMuchConfig) { //
oaMuch << *(fMuchConfig->GetOutputVec());
}
else {
oaMuch << (std::vector<CbmMuchDigi>());
}
std::string* strMsgMuch = new std::string(ossMuch.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgMuch->c_str()), // data
strMsgMuch->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgMuch)); // object that manages the data
// ---- Trd ----
std::stringstream ossTrd;
boost::archive::binary_oarchive oaTrd(ossTrd);
if (fTrd1DConfig || fTrd2DConfig) { //
oaTrd << *(fTrd1DConfig ? fTrd1DConfig->GetOutputVec() : fTrd2DConfig->GetOutputVec());
}
else {
oaTrd << (std::vector<CbmTrdDigi>());
}
std::string* strMsgTrd = new std::string(ossTrd.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgTrd->c_str()), // data
strMsgTrd->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgTrd)); // object that manages the data
// ---- Tof ----
std::stringstream ossTof;
boost::archive::binary_oarchive oaTof(ossTof);
if (fTofConfig) { //
oaTof << *(fTofConfig->GetOutputVec());
}
else {
oaTof << (std::vector<CbmTofDigi>());
}
std::string* strMsgTof = new std::string(ossTof.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgTof->c_str()), // data
strMsgTof->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgTof)); // object that manages the data
// ---- Rich ----
std::stringstream ossRich;
boost::archive::binary_oarchive oaRich(ossRich);
if (fRichConfig) { //
oaRich << *(fRichConfig->GetOutputVec());
}
else {
oaRich << (std::vector<CbmRichDigi>());
}
std::string* strMsgRich = new std::string(ossRich.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgRich->c_str()), // data
strMsgRich->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgRich)); // object that manages the data
// ---- Psd ----
std::stringstream ossPsd;
boost::archive::binary_oarchive oaPsd(ossPsd);
if (fPsdConfig) { //
oaPsd << *(fPsdConfig->GetOutputVec());
}
else {
oaPsd << (std::vector<CbmPsdDigi>());
}
std::string* strMsgPsd = new std::string(ossPsd.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgPsd->c_str()), // data
strMsgPsd->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgPsd)); // object that manages the data
/// Prepare serialized versions of the TS Meta
/// FIXME: only for TS duration and overlap, should be sent to parameter service instead as stable values in run
/// Index and start time are already included in the TsHeader object!
FairMQMessagePtr messTsMeta(NewMessage());
// Serialize<RootSerializer>(*messTsMeta, fTsMetaData);
RootSerializer().Serialize(*messTsMeta, fTsMetaData);
parts.AddPart(std::move(messTsMeta));
if (Send(parts, fsChannelNameDataOutput) < 0) {
LOG(error) << "Problem sending data to " << fsChannelNameDataOutput;
return false;
}
return true;
}
bool CbmDeviceUnpack::SendHistoConfAndData()
{
/// Prepare multiparts message and header
std::pair<uint32_t, uint32_t> pairHeader(fvpsHistosFolder.size(), fvpsCanvasConfig.size());
FairMQMessagePtr messageHeader(NewMessage());
// Serialize<BoostSerializer<std::pair<uint32_t, uint32_t>>>(*messageHeader, pairHeader);
BoostSerializer<std::pair<uint32_t, uint32_t>>().Serialize(*messageHeader, pairHeader);
FairMQParts partsOut;
partsOut.AddPart(std::move(messageHeader));
for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto) {
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, fvpsHistosFolder[uHisto]);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist, fvpsHistosFolder[uHisto]);
partsOut.AddPart(std::move(messageHist));
} // for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto)
/// Catch case where no histos are registered!
/// => Add empty message
if (0 == fvpsHistosFolder.size()) {
FairMQMessagePtr messageHist(NewMessage());
partsOut.AddPart(std::move(messageHist));
}
for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv) {
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, fvpsCanvasConfig[uCanv]);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageCan, fvpsCanvasConfig[uCanv]);
partsOut.AddPart(std::move(messageCan));
} // for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv)
/// Catch case where no Canvases are registered!
/// => Add empty message
if (0 == fvpsCanvasConfig.size()) {
FairMQMessagePtr messageHist(NewMessage());
partsOut.AddPart(std::move(messageHist));
}
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr msgHistos(NewMessage());
// Serialize<RootSerializer>(*msgHistos, &fArrayHisto);
RootSerializer().Serialize(*msgHistos, &fArrayHisto);
partsOut.AddPart(std::move(msgHistos));
/// Send the multi-parts message to the common histogram messages queue
if (Send(partsOut, fsChannelNameHistosInput) < 0) {
LOG(error) << "CbmTsConsumerReqDevExample::SendHistoConfAndData => Problem sending data";
return false;
} // if( Send( partsOut, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
// ALGO: fMonitorAlgo->ResetHistograms(kFALSE);
return true;
}
bool CbmDeviceUnpack::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
// Serialize<RootSerializer>(*message, &fArrayHisto);
RootSerializer().Serialize(*message, &fArrayHisto);
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
LOG(error) << "Problem sending data";
return false;
} // if( Send( message, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
// ALGO: fMonitorAlgo->ResetHistograms(kFALSE);
return true;
}
CbmDeviceUnpack::~CbmDeviceUnpack()
{
if (fBmonConfig) fBmonConfig->GetUnpacker()->Finish();
if (fStsConfig) fStsConfig->GetUnpacker()->Finish();
if (fMuchConfig) fMuchConfig->GetUnpacker()->Finish();
if (fTrd1DConfig) fTrd1DConfig->GetUnpacker()->Finish();
if (fTrd2DConfig) fTrd2DConfig->GetUnpacker()->Finish();
if (fTofConfig) fTofConfig->GetUnpacker()->Finish();
if (fRichConfig) fRichConfig->GetUnpacker()->Finish();
if (fPsdConfig) fPsdConfig->GetUnpacker()->Finish();
}
Bool_t CbmDeviceUnpack::DoUnpack(const fles::Timeslice& ts, size_t /*component*/)
{
fulTsCounter++;
// Prepare timeslice
// const fles::Timeslice& timeslice = *ts;
fCbmTsEventHeader->SetTsIndex(ts.index());
fCbmTsEventHeader->SetTsStartTime(ts.start_time());
uint64_t nComponents = ts.num_components();
// if (fDoDebugPrints) LOG(info) << "Unpack: TS index " << ts.index() << " components " << nComponents;
LOG(debug) << "Unpack: TS index " << ts.index() << " components " << nComponents;
for (uint64_t component = 0; component < nComponents; component++) {
auto systemId = static_cast<std::uint16_t>(ts.descriptor(component, 0).sys_id);
switch (systemId) {
case fkFlesBmon: {
if (fBmonConfig) {
fCbmTsEventHeader->AddNDigisBmon(
unpack(systemId, &ts, component, fBmonConfig, fBmonConfig->GetOptOutAVec(), fBmonConfig->GetOptOutBVec()));
}
break;
}
case fkFlesSts: {
if (fStsConfig) {
fCbmTsEventHeader->AddNDigisSts(
unpack(systemId, &ts, component, fStsConfig, fStsConfig->GetOptOutAVec(), fStsConfig->GetOptOutBVec()));
}
break;
}
case fkFlesMuch: {
if (fMuchConfig) {
fCbmTsEventHeader->AddNDigisMuch(
unpack(systemId, &ts, component, fMuchConfig, fMuchConfig->GetOptOutAVec(), fMuchConfig->GetOptOutBVec()));
}
break;
}
case fkFlesTrd: {
if (fTrd1DConfig) {
fCbmTsEventHeader->AddNDigisTrd1D(unpack(systemId, &ts, component, fTrd1DConfig,
fTrd1DConfig->GetOptOutAVec(), fTrd1DConfig->GetOptOutBVec()));
}
break;
}
case fkFlesTrd2D: {
if (fTrd2DConfig) {
fCbmTsEventHeader->AddNDigisTrd2D(unpack(systemId, &ts, component, fTrd2DConfig,
fTrd2DConfig->GetOptOutAVec(), fTrd2DConfig->GetOptOutBVec()));
}
break;
}
case fkFlesTof: {
if (fTofConfig) {
fCbmTsEventHeader->AddNDigisTof(
unpack(systemId, &ts, component, fTofConfig, fTofConfig->GetOptOutAVec(), fTofConfig->GetOptOutBVec()));
}
break;
}
case fkFlesRich: {
if (fRichConfig) {
fCbmTsEventHeader->AddNDigisRich(
unpack(systemId, &ts, component, fRichConfig, fRichConfig->GetOptOutAVec(), fRichConfig->GetOptOutBVec()));
}
break;
}
case fkFlesPsd: {
if (fPsdConfig) {
fCbmTsEventHeader->AddNDigisPsd(
unpack(systemId, &ts, component, fPsdConfig, fPsdConfig->GetOptOutAVec(), fPsdConfig->GetOptOutBVec()));
}
break;
}
default: {
if (fDoDebugPrints) LOG(error) << "Unpack: Unknown system ID " << systemId << " for component " << component;
break;
}
}
}
if (fbOutputFullTimeSorting) {
/// Time sort the output vectors of all unpackers present
if (fBmonConfig && fBmonConfig->GetOutputVec()) { timesort(fBmonConfig->GetOutputVec()); }
if (fStsConfig && fStsConfig->GetOutputVec()) { timesort(fStsConfig->GetOutputVec()); }
if (fMuchConfig && fMuchConfig->GetOutputVec()) { timesort(fMuchConfig->GetOutputVec()); }
if (fTrd1DConfig && fTrd1DConfig->GetOutputVec()) { timesort(fTrd1DConfig->GetOutputVec()); }
if (fTrd2DConfig && fTrd2DConfig->GetOutputVec()) { timesort(fTrd2DConfig->GetOutputVec()); }
if (fTofConfig && fTofConfig->GetOutputVec()) { timesort(fTofConfig->GetOutputVec()); }
if (fRichConfig && fRichConfig->GetOutputVec()) { timesort(fRichConfig->GetOutputVec()); }
if (fPsdConfig && fPsdConfig->GetOutputVec()) { timesort(fPsdConfig->GetOutputVec()); }
/// Time sort the output vectors of all unpackers present
if (fBmonConfig && fBmonConfig->GetOptOutAVec()) { timesort(fBmonConfig->GetOptOutAVec()); }
if (fStsConfig && fStsConfig->GetOptOutAVec()) { timesort(fStsConfig->GetOptOutAVec()); }
if (fMuchConfig && fMuchConfig->GetOptOutAVec()) { timesort(fMuchConfig->GetOptOutAVec()); }
if (fTrd1DConfig && fTrd1DConfig->GetOptOutAVec()) { timesort(fTrd1DConfig->GetOptOutAVec()); }
if (fTrd2DConfig && fTrd2DConfig->GetOptOutAVec()) { timesort(fTrd2DConfig->GetOptOutAVec()); }
if (fTofConfig && fTofConfig->GetOptOutAVec()) { timesort(fTofConfig->GetOptOutAVec()); }
if (fRichConfig && fRichConfig->GetOptOutAVec()) { timesort(fRichConfig->GetOptOutAVec()); }
if (fPsdConfig && fPsdConfig->GetOptOutAVec()) { timesort(fPsdConfig->GetOptOutAVec()); }
}
if (0 == fulTsCounter % 10000) LOG(info) << "Processed " << fulTsCounter << " time slices";
return kTRUE;
}
/**
* @brief Get the Trd Spadic
* @return std::shared_ptr<CbmTrdSpadic>
*/
std::shared_ptr<CbmTrdSpadic> CbmDeviceUnpack::GetTrdSpadic(bool useAvgBaseline)
{
auto spadic = std::make_shared<CbmTrdSpadic>();
spadic->SetUseBaselineAverage(useAvgBaseline);
spadic->SetMaxAdcToEnergyCal(1.0);
return spadic;
}
void CbmDeviceUnpack::Finish() {}
/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceUnpack.h
*
* @since 2020-05-04
* @author P.-A. Loizeau
*/
#ifndef CBMDEVICEUNPACK_H_
#define CBMDEVICEUNPACK_H_
#include "CbmMqTMessage.h"
#include "CbmTsEventHeader.h"
#include "Timeslice.hpp"
#include "FairMQDevice.h"
#include "FairParGenericSet.h"
#include "Rtypes.h"
#include "TObjArray.h"
#include <chrono>
#include <map>
#include <vector>
class TList;
class CbmBmonUnpackConfig;
class CbmStsUnpackConfig;
class CbmMuchUnpackConfig;
class CbmTrdUnpackFaspConfig;
class CbmTrdUnpackConfig;
class CbmTofUnpackConfig;
class CbmRichUnpackConfig;
class CbmPsdUnpackConfig;
class TimesliceMetaData;
class CbmTrdSpadic;
class CbmDeviceUnpack : public FairMQDevice {
public:
CbmDeviceUnpack();
virtual ~CbmDeviceUnpack();
protected:
virtual void InitTask();
bool ConditionalRun();
bool HandleCommand(FairMQMessagePtr&, int);
/** @brief Set the Bmon Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmBmonUnpackConfig> config) { fBmonConfig = config; }
/** @brief Set the Sts Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmStsUnpackConfig> config) { fStsConfig = config; }
/** @brief Set the Much Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmMuchUnpackConfig> config) { fMuchConfig = config; }
/** @brief Set the Trd Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmTrdUnpackConfig> config) { fTrd1DConfig = config; }
/** @brief Set the Trd2D Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmTrdUnpackFaspConfig> config) { fTrd2DConfig = config; }
/** @brief Set the Tof Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmTofUnpackConfig> config) { fTofConfig = config; }
/** @brief Set the Rich Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmRichUnpackConfig> config) { fRichConfig = config; }
/** @brief Set the Psd Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmPsdUnpackConfig> config) { fPsdConfig = config; }
private:
/// Constants
static constexpr std::uint16_t fkFlesBmon = static_cast<std::uint16_t>(fles::Subsystem::BMON);
static constexpr std::uint16_t fkFlesMvd = static_cast<std::uint16_t>(fles::Subsystem::MVD);
static constexpr std::uint16_t fkFlesSts = static_cast<std::uint16_t>(fles::Subsystem::STS);
static constexpr std::uint16_t fkFlesMuch = static_cast<std::uint16_t>(fles::Subsystem::MUCH);
static constexpr std::uint16_t fkFlesTrd = static_cast<std::uint16_t>(fles::Subsystem::TRD);
static constexpr std::uint16_t fkFlesTrd2D = static_cast<std::uint16_t>(fles::Subsystem::TRD2D);
static constexpr std::uint16_t fkFlesTof = static_cast<std::uint16_t>(fles::Subsystem::TOF);
static constexpr std::uint16_t fkFlesRich = static_cast<std::uint16_t>(fles::Subsystem::RICH);
static constexpr std::uint16_t fkFlesPsd = static_cast<std::uint16_t>(fles::Subsystem::PSD);
/// Control flags
Bool_t fbIgnoreOverlapMs = false; //! Ignore Overlap Ms: all fuOverlapMsNb MS at the end of timeslice
Bool_t fbComponentsAddedToList = kFALSE;
/** @brief Flag if extended debug output is to be printed or not*/
bool fDoDebugPrints = false; //!
/** @brief Flag if performance profiling should be activated or not.*/
bool fDoPerfProf = false; //!
/** @brief Flag to Enable/disable a full time sorting. If off, time sorting happens per link/FLIM source */
bool fbOutputFullTimeSorting = false;
/// User settings parameters
std::string fsSetupName = "mcbm_beam_2021_07_surveyed";
uint32_t fuRunId = 1588;
/// ---> for selective unpacking
bool fbUnpBmon = false;
bool fbUnpSts = true;
bool fbUnpMuch = false;
bool fbUnpTrd1D = true;
bool fbUnpTrd2D = true;
bool fbUnpTof = true;
bool fbUnpRich = true;
bool fbUnpPsd = true;
/// message queues
std::string fsChannelNameDataInput = "ts-request";
std::string fsChannelNameDataOutput = "unpts_0";
std::string fsChannelNameCommands = "commands";
std::string fsChannelNameHistosInput = "histogram-in";
/// Histograms management
uint32_t fuPublishFreqTs = 100;
double_t fdMinPublishTime = 0.5;
double_t fdMaxPublishTime = 5.0;
/// Parameters management
// TList* fParCList = nullptr;
Bool_t InitParameters(std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* reqparvec);
/// Statistics & first TS rejection
uint64_t fulNumMessages = 0;
uint64_t fulTsCounter = 0;
std::chrono::system_clock::time_point fLastPublishTime = std::chrono::system_clock::now();
/** @brief Map to store a name for the unpackers and the processed amount of digis, key = fkFlesId*/
std::map<std::uint16_t, std::pair<std::string, size_t>> fNameMap = {}; //!
/** @brief Map to store the cpu and wall time, key = fkFlesId*/
std::map<std::uint16_t, std::pair<double, double>> fTimeMap = {}; //!
/** @brief Map to store the in and out data amount, key = fkFlesId*/
std::map<std::uint16_t, std::pair<double, double>> fDataSizeMap = {}; //!
/// Configuration of the unpackers. Provides the configured algorithm
std::shared_ptr<CbmBmonUnpackConfig> fBmonConfig = nullptr;
std::shared_ptr<CbmStsUnpackConfig> fStsConfig = nullptr;
std::shared_ptr<CbmMuchUnpackConfig> fMuchConfig = nullptr;
std::shared_ptr<CbmTrdUnpackFaspConfig> fTrd2DConfig = nullptr;
std::shared_ptr<CbmTrdUnpackConfig> fTrd1DConfig = nullptr;
std::shared_ptr<CbmTofUnpackConfig> fTofConfig = nullptr;
std::shared_ptr<CbmRichUnpackConfig> fRichConfig = nullptr;
std::shared_ptr<CbmPsdUnpackConfig> fPsdConfig = nullptr;
/// Pointer to the Timeslice header conatining start time and index
CbmTsEventHeader* fCbmTsEventHeader = nullptr;
/// Time offsets
std::vector<std::string> fvsSetTimeOffs = {};
/// TS MetaData storage: stable so should be moved somehow to parameters handling (not transmitted with each TS
size_t fuNbCoreMsPerTs = 0; //!
size_t fuNbOverMsPerTs = 0; //!
Double_t fdMsSizeInNs = 0; //! Size of a single MS, [nanoseconds]
Double_t fdTsCoreSizeInNs = -1.0; //! Total size of the core MS in a TS, [nanoseconds]
Double_t fdTsOverSizeInNs = -1.0; //! Total size of the overlap MS in a TS, [nanoseconds]
Double_t fdTsFullSizeInNs = -1.0; //! Total size of all MS in a TS, [nanoseconds]
TimesliceMetaData* fTsMetaData;
/// Array of histograms to send to the histogram server
TObjArray fArrayHisto = {};
/// Vector of string pairs with ( HistoName, FolderPath ) to send to the histogram server
std::vector<std::pair<std::string, std::string>> fvpsHistosFolder = {};
/// Vector of string pairs with ( CanvasName, CanvasConfig ) to send to the histogram server
/// Format of Can config is "NbPadX(U);NbPadY(U);ConfigPad1(s);....;ConfigPadXY(s)"
/// Format of Pad config is "GrixX(b),GridY(b),LogX(b),LogY(b),LogZ(b),HistoName(s),DrawOptions(s)"
std::vector<std::pair<std::string, std::string>> fvpsCanvasConfig = {};
/// Flag indicating whether the histograms and canvases configurations were already published
bool fbConfigSent = false;
Bool_t InitContainers();
bool InitHistograms();
Bool_t DoUnpack(const fles::Timeslice& ts, size_t component);
void Finish();
bool SendUnpData();
bool SendHistoConfAndData();
bool SendHistograms();
std::shared_ptr<CbmTrdSpadic> GetTrdSpadic(bool useAvgBaseline);
/** @brief Sort a vector timewise vector type has to provide GetTime() */
template<typename TVecobj>
typename std::enable_if<std::is_same<TVecobj, std::nullptr_t>::value == true, void>::type
timesort(std::vector<TVecobj>* /*vec = nullptr*/)
{
LOG(debug) << "CbmDeviceUnpack::timesort() got an object that has no member function GetTime(). Hence, we can and "
"will not timesort it!";
}
template<typename TVecobj>
typename std::enable_if<!std::is_member_function_pointer<decltype(&TVecobj::GetTime)>::value, void>::type
timesort(std::vector<TVecobj>* /*vec = nullptr*/)
{
LOG(debug) << "CbmDeviceUnpack::timesort() " << TVecobj::Class_Name()
<< "is an object that has no member function GetTime(). Hence, we can and "
"will not timesort it!";
}
template<typename TVecobj>
typename std::enable_if<std::is_member_function_pointer<decltype(&TVecobj::GetTime)>::value, void>::type
timesort(std::vector<TVecobj>* vec = nullptr)
{
if (vec == nullptr) return;
std::sort(vec->begin(), vec->end(),
[](const TVecobj& a, const TVecobj& b) -> bool { return a.GetTime() < b.GetTime(); });
}
/**
* @brief Template for the unpacking call of a given algorithm.
*
* @tparam TAlgo Algorithm to be called
* @tparam TOutput Output element types
* @tparam TOptoutputs Optional output element types
* @param ts Timeslice
* @param icomp Component number
* @param algo Algorithm to be used for this component
* @param outtargetvec Target vector for the output elements
* @param optoutputvecs Target vectors for optional outputs
* @return std::pair<ndigis, std::pair<cputime, walltime>>
*/
template<class TConfig, class TOptOutA = std::nullptr_t, class TOptOutB = std::nullptr_t>
size_t unpack(const std::uint16_t subsysid, const fles::Timeslice* ts, std::uint16_t icomp, TConfig config,
std::vector<TOptOutA>* optouttargetvecA = nullptr, std::vector<TOptOutB>* optouttargetvecB = nullptr)
{
auto wallstarttime = std::chrono::high_resolution_clock::now();
std::clock_t cpustarttime = std::clock();
auto algo = config->GetUnpacker();
std::vector<TOptOutA> optoutAvec = {};
std::vector<TOptOutB> optoutBvec = {};
if (optouttargetvecA) { algo->SetOptOutAVec(&optoutAvec); }
if (optouttargetvecB) { algo->SetOptOutBVec(&optoutBvec); }
// Set the start time of the current TS for this algorithm
algo->SetTsStartTime(ts->start_time());
// Run the actual unpacking
auto digivec = algo->Unpack(ts, icomp);
// Check if we want to write the output to somewhere (in pure online monitoring mode for example this can/would/should be skipped)
if (config->GetOutputVec()) {
// Lets do some time-sorting if we are not doing it later
if (!fbOutputFullTimeSorting) timesort(&digivec);
// Transfer the data from the timeslice vector to the target branch vector
// Digis/default output retrieved as offered by the algorithm
for (auto digi : digivec)
config->GetOutputVec()->emplace_back(digi);
}
if (optouttargetvecA) {
// Lets do some timesorting
if (!fbOutputFullTimeSorting) timesort(&optoutAvec);
// Transfer the data from the timeslice vector to the target branch vector
for (auto optoutA : optoutAvec)
optouttargetvecA->emplace_back(optoutA);
}
if (optouttargetvecB) {
// Second opt output is not time sorted to allow non GetTime data container.
// Lets do some timesorting
timesort(&optoutAvec);
// Transfer the data from the timeslice vector to the target branch vector
for (auto optoutB : optoutBvec)
optouttargetvecB->emplace_back(optoutB);
}
std::clock_t cpuendtime = std::clock();
auto wallendtime = std::chrono::high_resolution_clock::now();
// Cpu time in [mus]
auto cputime = 1e6 * (cpuendtime - cpustarttime) / CLOCKS_PER_SEC;
algo->AddCpuTime(cputime);
// Real time in [mus]
auto walltime = std::chrono::duration<double, std::micro>(wallendtime - wallstarttime).count();
algo->AddWallTime(walltime);
// Check some numbers from this timeslice
size_t nDigis = digivec.size();
LOG(debug) << "Component " << icomp << " connected to config " << config->GetName() << " n-Digis " << nDigis
<< " processed in walltime(cputime) = " << walltime << "(" << cputime << cputime << ") micro s"
<< "this timeslice.";
if (fDoPerfProf) {
auto timeit = fTimeMap.find(subsysid);
timeit->second.first += cputime;
timeit->second.second += walltime;
auto datait = fDataSizeMap.find(subsysid);
datait->second.first += ts->size_component(icomp) / 1.0e6;
datait->second.second += nDigis * algo->GetOutputObjSize() / 1.0e6;
fNameMap.find(subsysid)->second.second += nDigis;
}
return nDigis;
}
};
#endif /* CBMDEVICEMCBMUNPACK_H_ */
Low priority
- Pub-Sub Queue from Sink to intermediate devices (unpackers, Event builders, ?calibrators?, ...) to signal that last TS was received and dumped and Transition
`Active -> Ready -> Stop -> End` can be done (e.g. through a Finish method)
- Empty/custom TsEventHeader and event vector when dumping missing TS in Sink (vector maybe already OK)
/* Copyright (C) 2022 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
#include "CbmDeviceBmonMonitor.h"
#include <iomanip>
#include <string>
#include "runFairMQDevice.h"
namespace bpo = boost::program_options;
using namespace std;
void addCustomOptions(bpo::options_description& options)
{
options.add_options()("Setup", bpo::value<std::string>()->default_value("mcbm_beam_2021_07_surveyed"),
"Name/tag of the geomatry setup");
options.add_options()("RunId", bpo::value<uint32_t>()->default_value(1588), "Run ID");
options.add_options()("UnpBmon", bpo::value<bool>()->default_value(false), "Enable Bmon unpacking if true");
options.add_options()("IgnOverMs", bpo::value<bool>()->default_value(true), "Ignore overlap MS if true");
options.add_options()("FullTimeSort", bpo::value<bool>()->default_value(true),
"Full time sorting per detector before sending output array");
options.add_options()("SetTimeOffs", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
"Set time offset in ns for selected detector, use string matching "
"ECbmModuleId,dOffs e.g. kTof,-35.2");
options.add_options()("TsNameIn", bpo::value<std::string>()->default_value("ts-request"),
"MQ channel name for raw TS data");
options.add_options()("TsNameOut", bpo::value<std::string>()->default_value("unpts_0"),
"MQ channel name for unpacked TS data");
options.add_options()("PubFreqTs", bpo::value<uint32_t>()->default_value(0), "Histo publishing frequency in TS");
options.add_options()("PubTimeMin", bpo::value<double_t>()->default_value(1.0),
"Minimal time between two publishing");
options.add_options()("PubTimeMax", bpo::value<double_t>()->default_value(10.0),
"Maximal time between two publishing");
options.add_options()("ChNameIn", bpo::value<std::string>()->default_value("histogram-in"),
"MQ channel name for histos");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new CbmDeviceBmonMonitor(); }
/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Dominik Smith [committer] */
#include "CbmDeviceBuildDigiEvents.h"
#include <iomanip>
#include <string>
#include "runFairMQDevice.h"
namespace bpo = boost::program_options;
using namespace std;
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()("EvtOverMode", bpo::value<std::string>()->default_value("NoOverlap"),
"Set the event overlap mode, use string matching an EOverlapMode ");
options.add_options()("RefDet", bpo::value<std::string>()->default_value("kBmon"),
"Set the reference (seed) detector, use string matching an ECbmModuleId ");
options.add_options()("AddDet", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
"Add a detector for digis selection, use string matching an ECbmModuleId ");
options.add_options()("DelDet", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
"Remove a detector for digis selection, use string matching an "
"ECbmModuleId ");
options.add_options()("SetTrigWin", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
"Set trigger window for selected detector, use string matching "
"ECbmModuleId,dWinBeg,dWinEnd e.g. kSts,-10.5,100.0");
options.add_options()("SetTrigMinNb", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
"Set minimum number of digis for selected detector, use string matching "
"ECbmModuleId,uMinNb e.g. kTof,10");
options.add_options()("SetTrigMaxNb", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
"Set maximum number of digis for selected detector, use string matching "
"ECbmModuleId,uMaxNb e.g. kTof,10");
options.add_options()("SetTrigMinLayersNb", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
"Set minimum number of fired layers for selected detector, use string matching "
"ECbmModuleId,uMinLayersNb e.g. kTof,3");
options.add_options()("SetHistMaxDigiNb", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
"Set max nb of digi in histograms for selected detector, use string matching "
"ECbmModuleId,dMaxDigiNb e.g. kTof,1000");
options.add_options()("DoNotSend", bpo::value<bool>()->default_value(false), "Disable the sending of data if true");
options.add_options()("DigiEventOutput", bpo::value<bool>()->default_value(false),
"Enable output of CbmDigiEvents instead of raw data + CbmEvents if true");
options.add_options()("TsNameIn", bpo::value<std::string>()->default_value("unpts_0"),
"MQ channel name for unpacked TS data");
options.add_options()("EvtNameOut", bpo::value<std::string>()->default_value("events"),
"MQ channel name for built events");
options.add_options()("ChNameIn", bpo::value<std::string>()->default_value("histogram-in"),
"MQ channel name for histos");
options.add_options()("ChNameHistCfg", bpo::value<std::string>()->default_value("histo-conf"),
"MQ channel name for histos config");
options.add_options()("ChNameCanvCfg", bpo::value<std::string>()->default_value("canvas-conf"),
"MQ channel name for canvases config");
options.add_options()("PubFreqTs", bpo::value<uint32_t>()->default_value(100), "Histo publishing frequency in TS");
options.add_options()("PubTimeMin", bpo::value<double_t>()->default_value(1.0),
"Minimal time between two publishing");
options.add_options()("PubTimeMax", bpo::value<double_t>()->default_value(10.0),
"Maximal time between two publishing");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new CbmDeviceBuildDigiEvents(); }
/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Dominik Smith [committer] */
#include "CbmDeviceBuildRawEvents.h"
#include <iomanip>
#include <string>
#include "runFairMQDevice.h"
namespace bpo = boost::program_options;
using namespace std;
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()("EvtOverMode", bpo::value<std::string>()->default_value("NoOverlap"),
"Set the event overlap mode, use string matching an EOverlapMode ");
options.add_options()("RefDet", bpo::value<std::string>()->default_value("kBmon"),
"Set the reference (seed) detector, use string matching an ECbmModuleId ");
options.add_options()("AddDet", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
"Add a detector for digis selection, use string matching an ECbmModuleId ");
options.add_options()("DelDet", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
"Remove a detector for digis selection, use string matching an "
"ECbmModuleId ");
options.add_options()("SetTrigWin", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
"Set trigger window for selected detector, use string matching "
"ECbmModuleId,dWinBeg,dWinEnd e.g. kSts,-10.5,100.0");
options.add_options()("SetTrigMinNb", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
"Set minimum number of digis for selected detector, use string matching "
"ECbmModuleId,uMinNb e.g. kTof,10");
options.add_options()("TsNameIn", bpo::value<std::string>()->default_value("unpts_0"),
"MQ channel name for unpacked TS data");
options.add_options()("EvtNameOut", bpo::value<std::string>()->default_value("events"),
"MQ channel name for built events");
options.add_options()("ChNameIn", bpo::value<std::string>()->default_value("histogram-in"),
"MQ channel name for histos");
options.add_options()("ChNameHistCfg", bpo::value<std::string>()->default_value("histo-conf"),
"MQ channel name for histos config");
options.add_options()("ChNameCanvCfg", bpo::value<std::string>()->default_value("canvas-conf"),
"MQ channel name for canvases config");
options.add_options()("PubFreqTs", bpo::value<uint32_t>()->default_value(100), "Histo publishing frequency in TS");
options.add_options()("PubTimeMin", bpo::value<double_t>()->default_value(1.0),
"Minimal time between two publishing");
options.add_options()("PubTimeMax", bpo::value<double_t>()->default_value(10.0),
"Maximal time between two publishing");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new CbmDeviceBuildRawEvents(); }
/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
#include "CbmDeviceDigiEventSink.h"
#include <iomanip>
#include <string>
#include "runFairMQDevice.h"
namespace bpo = boost::program_options;
using namespace std;
void addCustomOptions(bpo::options_description& options)
{
options.add_options()("StoreFullTs", bpo::value<bool>()->default_value(false),
"Store digis vectors with full TS in addition to selected events if true");
options.add_options()("OutFileName", bpo::value<std::string>()->default_value("mcbm_digis_events.root"),
"Name (full or relative path) of the output .root file ");
options.add_options()("EvtNameIn", bpo::value<std::string>()->default_value("events"),
"MQ channel name for built events");
options.add_options()("BypassConsecutiveTs", bpo::value<bool>()->default_value(false),
"Do not wait for having consecutive TS in buffer before writing to file if true");
options.add_options()("WriteMissingTs", bpo::value<bool>()->default_value(false),
"Write empty TS to file for the missing ones if true (irrelevant if bypass ON)");
options.add_options()("DisableCompression", bpo::value<bool>()->default_value(false),
"Disable the root file compression if true");
options.add_options()("TreeFileMaxSize", bpo::value<int64_t>()->default_value(10000000000LL),
"Set the maximum output tree size (~file size) in bytes");
options.add_options()("DigiEventInput", bpo::value<bool>()->default_value(false),
"Enable the input of CbmDigiEvents instead of raw data + CbmEvents if true");
options.add_options()("ExclusiveTrdExtract", bpo::value<bool>()->default_value(true),
"Enable loop based extraction of TRD digis to handle different 1D/2D sel windows if true");
options.add_options()("FillHistos", bpo::value<bool>()->default_value(false),
"Fill histograms and send them to histo server if true");
options.add_options()("PubFreqTs", bpo::value<uint32_t>()->default_value(100), "Histo publishing frequency in TS");
options.add_options()("PubTimeMin", bpo::value<double_t>()->default_value(1.0),
"Minimal time between two publishing");
options.add_options()("PubTimeMax", bpo::value<double_t>()->default_value(10.0),
"Maximal time between two publishing");
options.add_options()("HistosSuffix", bpo::value<std::string>()->default_value(""),
"Suffix added to folders, histos and canvases names, e.g. for multiple nodes usages");
options.add_options()("ChNameIn", bpo::value<std::string>()->default_value("histogram-in"),
"MQ channel name for histos");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new CbmDeviceDigiEventSink(); }
/* Copyright (C) 2020 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
#include "CbmDeviceMcbmEventSink.h"
#include <iomanip>
#include <string>
#include "runFairMQDevice.h"
namespace bpo = boost::program_options;
using namespace std;
void addCustomOptions(bpo::options_description& options)
{
options.add_options()("OutFileName", bpo::value<std::string>()->default_value("mcbm_digis_events.root"),
"Name (full or relative path) of the output .root file ");
options.add_options()("EvtNameIn", bpo::value<std::string>()->default_value("events"),
"MQ channel name for built events");
options.add_options()("FillHistos", bpo::value<bool>()->default_value(false),
"Fill histograms and send them to histo server if true");
options.add_options()("ChNameIn", bpo::value<std::string>()->default_value("histogram-in"),
"MQ channel name for histos");
options.add_options()("ChNameHistCfg", bpo::value<std::string>()->default_value("histo-conf"),
"MQ channel name for histos config");
options.add_options()("ChNameCanvCfg", bpo::value<std::string>()->default_value("canvas-conf"),
"MQ channel name for canvases config");
options.add_options()("PubFreqTs", bpo::value<uint32_t>()->default_value(100), "Histo publishing frequency in TS");
options.add_options()("PubTimeMin", bpo::value<double_t>()->default_value(1.0),
"Minimal time between two publishing");
options.add_options()("PubTimeMax", bpo::value<double_t>()->default_value(10.0),
"Maximal time between two publishing");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new CbmDeviceMcbmEventSink(); }