From e0c33adeeec55d17f0eff51a4cbc34d2251221f9 Mon Sep 17 00:00:00 2001 From: P-A Loizeau <p.-a.loizeau@gsi.de> Date: Thu, 2 Jul 2020 16:21:01 +0200 Subject: [PATCH] MQ: add example of the unpacking and event building chain for mCBM 2020 - Unpacker device running an instance of the unpacker algo of each of the participating detectors - Event builder device running an instance of CbmMcbm2019TimeWinEventBuilderAlgo - Event Sink acting as a parrallel stream aligner and merger + as a disk sink - Start script for a chain with a single MultiTsa source, parallel branches of Unpacker + EventBuilder, a single EventSink and an histogram server - Pulser monitor device (untested) --- MQ/CMakeLists.txt | 2 + MQ/mcbm/CMakeLists.txt | 160 ++++ MQ/mcbm/CbmDeviceMcbmEventBuilderWin.cxx | 703 ++++++++++++++++++ MQ/mcbm/CbmDeviceMcbmEventBuilderWin.h | 146 ++++ MQ/mcbm/CbmDeviceMcbmEventSink.cxx | 806 +++++++++++++++++++++ MQ/mcbm/CbmDeviceMcbmEventSink.h | 172 +++++ MQ/mcbm/CbmDeviceMcbmMonitorPulser.cxx | 408 +++++++++++ MQ/mcbm/CbmDeviceMcbmMonitorPulser.h | 276 +++++++ MQ/mcbm/CbmDeviceMcbmUnpack.cxx | 584 +++++++++++++++ MQ/mcbm/CbmDeviceMcbmUnpack.h | 113 +++ MQ/mcbm/runMcbmEventSink.cxx | 35 + MQ/mcbm/runMcbmEvtBuilderWin.cxx | 49 ++ MQ/mcbm/runMcbmMonitorPulser.cxx | 39 + MQ/mcbm/runMcbmUnpack.cxx | 25 + MQ/mcbm/startMQMcbmEvtBuilderWin2020.sh.in | 264 +++++++ MQ/mcbm/startMQMcbmPulserMonitor2020.sh.in | 160 ++++ 16 files changed, 3942 insertions(+) create mode 100644 MQ/mcbm/CMakeLists.txt create mode 100644 MQ/mcbm/CbmDeviceMcbmEventBuilderWin.cxx create mode 100644 MQ/mcbm/CbmDeviceMcbmEventBuilderWin.h create mode 100644 MQ/mcbm/CbmDeviceMcbmEventSink.cxx create mode 100644 MQ/mcbm/CbmDeviceMcbmEventSink.h create mode 100644 MQ/mcbm/CbmDeviceMcbmMonitorPulser.cxx create mode 100644 MQ/mcbm/CbmDeviceMcbmMonitorPulser.h create mode 100644 MQ/mcbm/CbmDeviceMcbmUnpack.cxx create mode 100644 MQ/mcbm/CbmDeviceMcbmUnpack.h create mode 100644 MQ/mcbm/runMcbmEventSink.cxx create mode 100644 MQ/mcbm/runMcbmEvtBuilderWin.cxx create mode 100644 MQ/mcbm/runMcbmMonitorPulser.cxx create mode 100644 MQ/mcbm/runMcbmUnpack.cxx create mode 100755 MQ/mcbm/startMQMcbmEvtBuilderWin2020.sh.in create mode 100755 MQ/mcbm/startMQMcbmPulserMonitor2020.sh.in diff --git a/MQ/CMakeLists.txt b/MQ/CMakeLists.txt index bb0aa9247f..3bc8ce8b40 100644 --- a/MQ/CMakeLists.txt +++ b/MQ/CMakeLists.txt @@ -10,6 +10,8 @@ add_subdirectory(sink) add_subdirectory(monitor) add_subdirectory(histoServer) +add_subdirectory(mcbm) + #add_subdirectory(sts) #add_subdirectory(test) diff --git a/MQ/mcbm/CMakeLists.txt b/MQ/mcbm/CMakeLists.txt new file mode 100644 index 0000000000..ec45173159 --- /dev/null +++ b/MQ/mcbm/CMakeLists.txt @@ -0,0 +1,160 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startMQMcbmPulserMonitor2020.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startMQMcbmPulserMonitor2020.sh) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startMQMcbmEvtBuilderWin2020.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startMQMcbmEvtBuilderWin2020.sh) + +set(INCLUDE_DIRECTORIES + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/MQ/base + ${CBMROOT_SOURCE_DIR}/fles/mcbm2018/unpacker + ${CBMROOT_SOURCE_DIR}/fles/mcbm2018/tasks + ${CBMROOT_SOURCE_DIR}/fles/mcbm2018/parameter + ${CBMROOT_SOURCE_DIR}/fles/mcbm2018/dataformat + ${CBMROOT_SOURCE_DIR}/fles/mcbm2018/commonMQ + ${CBMROOT_SOURCE_DIR}/fles/flestools + ${CBMDATA_DIR} + ${CBMDATA_DIR}/global + ${CBMDATA_DIR}/raw + ${CBMDATA_DIR}/sts + ${CBMDATA_DIR}/much + ${CBMDATA_DIR}/rich + ${CBMDATA_DIR}/tof + ${CBMDATA_DIR}/psd + ${CBMDATA_DIR}/trd + ${CBMDATA_DIR}/mvd # Feint to avoid crash of DigiManager due to missing source pointer + ${CBMBASE_DIR} + + ${CBMDETECTORBASE_DIR}/trd # required for parameter handling of the trd + ${CBMDETECTORBASE_DIR}/psd # required for fitting tools of the psd +) + +Set(SYSTEM_INCLUDE_DIRECTORIES + ${SYSTEM_INCLUDE_DIRECTORIES} + ${ZeroMQ_INCLUDE_DIR} + ${Boost_INCLUDE_DIR} + ${FAIRROOT_INCLUDE_DIR} + ${FAIRMQ_INCLUDE_DIR} + ${FAIRMQ_INCLUDE_DIR}/options + + ${IPC_INCLUDE_DIRECTORY} + ${CBMROOT_SOURCE_DIR}/external/cppzmq +) + +include_directories(${INCLUDE_DIRECTORIES}) +include_directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES}) + +set(LINK_DIRECTORIES + ${ROOT_LIBRARY_DIR} + ${FAIRROOT_LIBRARY_DIR} + ${FAIRMQ_LIBRARY_DIR} + ${Boost_LIBRARY_DIRS} +) + +link_directories(${LINK_DIRECTORIES}) + +set(EXECUTABLE_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}/MQ/mcbm") + +Set(BOOST_LIBS + ${Boost_SYSTEM_LIBRARY} + ${Boost_SERIALIZATION_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_LOG_LIBRARY} +) +If(UNIX AND NOT APPLE) + List(APPEND BOOST_LIBS pthread) +EndIf() + +set(FAIR_LIBS + FairMQ +) + +If(FAIRLOGGER_FOUND) + set(FAIR_LIBS + ${FAIR_LIBS} + FairLogger + ) +EndIf() + +set(EXE_NAME McbmUnpack) +set(SRCS CbmDeviceMcbmUnpack.cxx runMcbmUnpack.cxx) + +set(DEPENDENCIES + ${DEPENDENCIES} + ${FAIR_LIBS} + ${BOOST_LIBS} + fles_ipc + CbmFlibMcbm2018 + CbmFlibFlesTools + CbmBase + CbmData + Core + RIO + Net + Hist + RHTTP +) +#GENERATE_LIBRARY() +GENERATE_EXECUTABLE() + +set(EXE_NAME McbmMonitorPulser) +set(SRCS CbmDeviceMcbmMonitorPulser.cxx runMcbmMonitorPulser.cxx) + +set(DEPENDENCIES + ${DEPENDENCIES} + ${FAIR_LIBS} + ${BOOST_LIBS} + fles_ipc + CbmFlibMcbm2018 + CbmFlibFlesTools + CbmBase + CbmData + Core + RIO + Net + Hist + RHTTP +) +#GENERATE_LIBRARY() +GENERATE_EXECUTABLE() + +set(EXE_NAME McbmEventBuilderWin) +set(SRCS CbmDeviceMcbmEventBuilderWin.cxx runMcbmEvtBuilderWin.cxx) + +set(DEPENDENCIES + ${DEPENDENCIES} + ${FAIR_LIBS} + ${BOOST_LIBS} + fles_ipc + CbmFlibMcbm2018 + CbmFlibFlesTools + CbmBase + CbmData + Core + RIO + Net + Hist + RHTTP +) +#GENERATE_LIBRARY() +GENERATE_EXECUTABLE() + +set(EXE_NAME McbmEventSink) +set(SRCS CbmDeviceMcbmEventSink.cxx runMcbmEventSink.cxx) + +set(DEPENDENCIES + ${DEPENDENCIES} + ${FAIR_LIBS} + ${BOOST_LIBS} + fles_ipc + CbmFlibMcbm2018 + CbmFlibFlesTools + CbmBase + CbmData + Core + RIO + Tree + Net + Hist + RHTTP +) +#GENERATE_LIBRARY() +GENERATE_EXECUTABLE() + diff --git a/MQ/mcbm/CbmDeviceMcbmEventBuilderWin.cxx b/MQ/mcbm/CbmDeviceMcbmEventBuilderWin.cxx new file mode 100644 index 0000000000..963fed8ec9 --- /dev/null +++ b/MQ/mcbm/CbmDeviceMcbmEventBuilderWin.cxx @@ -0,0 +1,703 @@ +/** + * CbmDeviceMcbmEventBuilderWin.cxx + * + * @since 2020-05-24 + * @author P.-A. Loizeau + */ + +#include "CbmDeviceMcbmEventBuilderWin.h" + + +/// CBM headers +#include "CbmMQDefs.h" + +#include "CbmEvent.h" +#include "TimesliceMetaData.h" +#include "CbmFlesCanvasTools.h" +#include "CbmMvdDigi.h" +#include "CbmMatch.h" + +/// FAIRROOT headers +#include "FairRunOnline.h" +#include "FairMQLogger.h" +#include "FairMQProgOptions.h" // device->fConfig +#include "FairParGenericSet.h" +#include "RootSerializer.h" +#include "BoostSerializer.h" + +/// FAIRSOFT headers (geant, boost, ...) +#include "TNamed.h" +#include "TList.h" +#include "TCanvas.h" +#include "TFile.h" +#include "TH1.h" +#include <boost/serialization/utility.hpp> +#include <boost/archive/binary_iarchive.hpp> + +/// C/C++ headers +#include <string> +#include <iomanip> +#include <array> + +#include <stdexcept> +struct InitTaskError : std::runtime_error { using std::runtime_error::runtime_error; }; + +using namespace std; + +//Bool_t bMcbm2018MonitorTaskT0ResetHistos = 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(); + + /// 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 + ECbmModuleId refDet = ( "kT0" == fsRefDet ? ECbmModuleId::kT0 : + ( "kSts" == fsRefDet ? ECbmModuleId::kSts : + ( "kMuch" == fsRefDet ? ECbmModuleId::kMuch : + ( "kTrd" == fsRefDet ? ECbmModuleId::kTrd : + ( "kTof" == fsRefDet ? ECbmModuleId::kTof : + ( "kRich" == fsRefDet ? ECbmModuleId::kRich : + ( "kPsd" == fsRefDet ? ECbmModuleId::kPsd : + ECbmModuleId::kNotExist + ) ) ) ) ) ) ); + + fpAlgo->SetReferenceDetector( refDet ); + /// Extract detector to add if any + for( std::vector< std::string >::iterator itStrAdd = fvsAddDet.begin(); itStrAdd != fvsAddDet.end(); ++itStrAdd ) + { + ECbmModuleId addDet = ( "kT0" == *itStrAdd ? ECbmModuleId::kT0 : + ( "kSts" == *itStrAdd ? ECbmModuleId::kSts : + ( "kMuch" == *itStrAdd ? ECbmModuleId::kMuch : + ( "kTrd" == *itStrAdd ? ECbmModuleId::kTrd : + ( "kTof" == *itStrAdd ? ECbmModuleId::kTof : + ( "kRich" == *itStrAdd ? ECbmModuleId::kRich : + ( "kPsd" == *itStrAdd ? ECbmModuleId::kPsd : + ECbmModuleId::kNotExist + ) ) ) ) ) ) ); + if( ECbmModuleId::kNotExist != addDet ) + { + fpAlgo->AddDetector( addDet ); + } // if( ECbmModuleId::kNotExist != addDet ) + else + { + LOG( info ) << "CbmDeviceMcbmEventBuilderWin::InitTask => Trying to add unsupported detector, ignored! " + << (*itStrAdd); + continue; + } // else of if( ECbmModuleId::kNotExist != addDet + } // for( std::vector< std::string >::iterator itStrAdd = fvsAddDet.begin(); itStrAdd != fvsAddDet.end(); ++itStrAdd ) + /// Extract detector to add if any + for( std::vector< std::string >::iterator itStrRem = fvsDelDet.begin(); itStrRem != fvsDelDet.end(); ++itStrRem ) + { + ECbmModuleId remDet = ( "kT0" == *itStrRem ? ECbmModuleId::kT0 : + ( "kSts" == *itStrRem ? ECbmModuleId::kSts : + ( "kMuch" == *itStrRem ? ECbmModuleId::kMuch : + ( "kTrd" == *itStrRem ? ECbmModuleId::kTrd : + ( "kTof" == *itStrRem ? ECbmModuleId::kTof : + ( "kRich" == *itStrRem ? ECbmModuleId::kRich : + ( "kPsd" == *itStrRem ? ECbmModuleId::kPsd : + ECbmModuleId::kNotExist + ) ) ) ) ) ) ); + if( ECbmModuleId::kNotExist != remDet ) + { + fpAlgo->RemoveDetector( remDet ); + } // if( ECbmModuleId::kNotExist != remDet ) + else + { + LOG( info ) << "CbmDeviceMcbmEventBuilderWin::InitTask => Trying to remove unsupported detector, ignored! " + << (*itStrRem); + continue; + } // else of if( ECbmModuleId::kNotExist != 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 = ( "kT0" == sSelDet ? ECbmModuleId::kT0 : + ( "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 = ( "kT0" == sSelDet ? ECbmModuleId::kT0 : + ( "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 ) + + /// Create input vectors + fvDigiT0 = 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( "T0Digi", fvDigiT0, 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 ); + + /// 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 ); + + /// 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 ); + /// FIXME: Not if this is the proper way to insert the data + new( (*fTimeSliceMetaDataArray)[ fTimeSliceMetaDataArray->GetEntriesFast() +// ] ) TimesliceMetaData( *fTsMetaData ) ; + ] ) TimesliceMetaData( std::move(*fTsMetaData) ) ; + ++uPartIdx; + + /// T0 + std::string msgStrT0( static_cast< char * >( parts.At( uPartIdx )->GetData() ), + ( parts.At( uPartIdx ) )->GetSize() ); + std::istringstream issT0( msgStrT0 ); + boost::archive::binary_iarchive inputArchiveT0( issT0 ); + inputArchiveT0 >> *fvDigiT0; + ++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; + + /// T0F + 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 + fvDigiT0->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 ); + + /// 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 ); + + /// 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 + fvDigiT0->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() +{ +} diff --git a/MQ/mcbm/CbmDeviceMcbmEventBuilderWin.h b/MQ/mcbm/CbmDeviceMcbmEventBuilderWin.h new file mode 100644 index 0000000000..7fff99b881 --- /dev/null +++ b/MQ/mcbm/CbmDeviceMcbmEventBuilderWin.h @@ -0,0 +1,146 @@ +/** + * CbmDeviceMcbmEventBuilderWin.h + * + * @since 2020-05-24 + * @author P.-A. Loizeau + */ + +#ifndef CBMDEVICEMCBMEVTBUILDERWIN_H_ +#define CBMDEVICEMCBMEVTBUILDERWIN_H_ + +/// CBM headers +#include "CbmMcbm2019TimeWinEventBuilderAlgo.h" +#include "CbmStsDigi.h" +#include "CbmMuchBeamTimeDigi.h" +#include "CbmRichDigi.h" +#include "CbmTrdDigi.h" +#include "CbmTofDigi.h" +#include "CbmPsdDigi.h" + +/// FAIRROOT headers +#include "FairMQDevice.h" + +/// FAIRSOFT headers (geant, boost, ...) +#include "TMessage.h" +#include "Rtypes.h" +#include "TObjArray.h" + +/// C/C++ headers +#include <vector> +#include <map> +#include <chrono> + +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 = "kT0"; + 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 > * fvDigiT0 = 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(); +}; + +// special class to expose protected TMessage constructor +class CbmMQTMessage : public TMessage +{ + public: + CbmMQTMessage(void* buf, Int_t len) + : TMessage(buf, len) + { + ResetBit(kIsOwner); + } +}; + + +#endif /* CBMDEVICEMCBMEVTBUILDERWIN_H_ */ diff --git a/MQ/mcbm/CbmDeviceMcbmEventSink.cxx b/MQ/mcbm/CbmDeviceMcbmEventSink.cxx new file mode 100644 index 0000000000..1aeed9d887 --- /dev/null +++ b/MQ/mcbm/CbmDeviceMcbmEventSink.cxx @@ -0,0 +1,806 @@ +/** + * CbmDeviceMcbmEventSink.cxx + * + * @since 2020-05-24 + * @author P.-A. Loizeau + */ + +#include "CbmDeviceMcbmEventSink.h" + + +/// CBM headers +#include "CbmMQDefs.h" + +#include "CbmEvent.h" +#include "TimesliceMetaData.h" +#include "CbmFlesCanvasTools.h" + +/// FAIRROOT headers +#include "FairRunOnline.h" +#include "FairRootManager.h" +#include "FairRootFileSink.h" +#include "FairMQLogger.h" +#include "FairMQProgOptions.h" // device->fConfig +#include "FairParGenericSet.h" +#include "RootSerializer.h" +#include "BoostSerializer.h" + +/// FAIRSOFT headers (geant, boost, ...) +#include "TNamed.h" +#include "TList.h" +#include "TCanvas.h" +#include "TFile.h" +#include "TH1.h" +#include <boost/serialization/utility.hpp> +#include <boost/archive/binary_iarchive.hpp> + +/// C/C++ headers +#include <string> +#include <iomanip> +#include <array> +#include <thread> // this_thread::sleep_for + +#include <stdexcept> +struct InitTaskError : std::runtime_error { using std::runtime_error::runtime_error; }; + +using namespace std; + +//Bool_t bMcbm2018MonitorTaskT0ResetHistos = 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 + fvDigiT0 = 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( "T0Digi", fvDigiT0, 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 ); + + /// 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 ); + + /// 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 ); + 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(), + std::move( 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 + /// T0 + fvDigiT0->insert( fvDigiT0->end(), unpTs.fvDigiT0.begin(), unpTs.fvDigiT0.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() ); + /// T0F + 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 + /// T0 + (*fvDigiT0) = std::move( unpTs.fvDigiT0 ); + /// STS + (*fvDigiSts) = std::move( unpTs.fvDigiSts ); + /// MUCH + (*fvDigiMuch) = std::move( unpTs.fvDigiMuch ); + /// TRD + (*fvDigiTrd) = std::move( unpTs.fvDigiTrd ); + /// T0F + (*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 + fvDigiT0->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 ); + + /// 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 + fvDigiT0->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") ) + + /// T0 + std::string msgStrT0( static_cast< char * >( parts.At( uPartIdx )->GetData() ), + ( parts.At( uPartIdx ) )->GetSize() ); + std::istringstream issT0( msgStrT0 ); + boost::archive::binary_iarchive inputArchiveT0( issT0 ); + inputArchiveT0 >> fvDigiT0; + ++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; + + /// T0F + 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") ) +} diff --git a/MQ/mcbm/CbmDeviceMcbmEventSink.h b/MQ/mcbm/CbmDeviceMcbmEventSink.h new file mode 100644 index 0000000000..f1a195b516 --- /dev/null +++ b/MQ/mcbm/CbmDeviceMcbmEventSink.h @@ -0,0 +1,172 @@ +/** + * CbmDeviceMcbmEventSink.h + * + * @since 2020-05-04 + * @author P.-A. Loizeau + */ + +#ifndef CBMDEVICEMCBMEVTSINK_H_ +#define CBMDEVICEMCBMEVTSINK_H_ + +/// CBM headers +#include "CbmStsDigi.h" +#include "CbmMuchBeamTimeDigi.h" +#include "CbmRichDigi.h" +#include "CbmTrdDigi.h" +#include "CbmTofDigi.h" +#include "CbmPsdDigi.h" +#include "CbmEvent.h" +#include "TimesliceMetaData.h" + +/// FAIRROOT headers +#include "FairMQDevice.h" + +/// FAIRSOFT headers (geant, boost, ...) +#include "TMessage.h" +#include "Rtypes.h" +#include "TObjArray.h" +#include "TClonesArray.h" + +/// C/C++ headers +#include <vector> +#include <map> +#include <chrono> + +class TFile; +class TList; +class TClonesArray; +//class TimesliceMetaData; +class FairRunOnline; +class FairRootManager; + +class CbmUnpackedTimeslice +{ + /// TODO: rename to CbmTsWithEvents + public: + CbmUnpackedTimeslice( FairMQParts & parts ); + + TimesliceMetaData fTsMetaData; + std::vector< CbmTofDigi > fvDigiT0; + 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 > * fvDigiT0 = 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 ; + TFile * fpOutRootFile = 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(); +}; + +// special class to expose protected TMessage constructor +class CbmMQTMessage : public TMessage +{ + public: + CbmMQTMessage(void* buf, Int_t len) + : TMessage(buf, len) + { + ResetBit(kIsOwner); + } +}; + + +#endif /* CBMDEVICEMCBMEVTSINK_H_ */ diff --git a/MQ/mcbm/CbmDeviceMcbmMonitorPulser.cxx b/MQ/mcbm/CbmDeviceMcbmMonitorPulser.cxx new file mode 100644 index 0000000000..fe4052e0c5 --- /dev/null +++ b/MQ/mcbm/CbmDeviceMcbmMonitorPulser.cxx @@ -0,0 +1,408 @@ +/** + * CbmDeviceMcbmMonitorPulser.cxx + * + * @since 2020-05-04 + * @author P.-A Loizeau + */ + +#include "CbmDeviceMcbmMonitorPulser.h" + +#include "TimesliceMetaData.h" +#include "CbmMQDefs.h" + +//#include "CbmMcbm2018MonitorAlgoTof.h" +#include "CbmFlesCanvasTools.h" + +#include "StorableTimeslice.hpp" + +#include "FairMQLogger.h" +#include "FairMQProgOptions.h" // device->fConfig +#include "FairParGenericSet.h" +#include "RootSerializer.h" +#include "BoostSerializer.h" + +#include "TNamed.h" +#include "TList.h" +#include "TCanvas.h" +#include "TFile.h" +#include "TH1.h" + +#include <string> +#include <iomanip> +#include <array> + +#include <boost/serialization/utility.hpp> +#include <boost/archive/binary_iarchive.hpp> + +#include <stdexcept> +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 ); + + /// 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 ); + + /// 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 ); + ++uPartIdx; + + std::string msgStrT0( static_cast< char * >( parts.At( uPartIdx )->GetData() ), + ( parts.At( uPartIdx ) )->GetSize() ); + std::istringstream issT0( msgStrT0 ); + boost::archive::binary_iarchive inputArchiveT0( issT0 ); + inputArchiveT0 >> fvDigiT0; + ++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; + fvDigiT0.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 ); + + // test code to check if deserialization works +/* + TObject* tempObject = nullptr; + Deserialize<RootDeserializer>(*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() +{ +} diff --git a/MQ/mcbm/CbmDeviceMcbmMonitorPulser.h b/MQ/mcbm/CbmDeviceMcbmMonitorPulser.h new file mode 100644 index 0000000000..8eb3ec00ac --- /dev/null +++ b/MQ/mcbm/CbmDeviceMcbmMonitorPulser.h @@ -0,0 +1,276 @@ +/** + * CbmDeviceMcbmMonitorPulser.h + * + * @since 2020-05-04 + * @author P.-A Loizeau + */ + +#ifndef CBMDEVICEMCBMMONITORPULSER_H_ +#define CBMDEVICEMCBMMONITORPULSER_H_ + +#include "CbmStsDigi.h" +#include "CbmMuchBeamTimeDigi.h" +#include "CbmRichDigi.h" +#include "CbmTrdDigi.h" +#include "CbmTofDigi.h" +#include "CbmPsdDigi.h" + +#include "FairMQDevice.h" + +#include "TMessage.h" +#include "Rtypes.h" +#include "TObjArray.h" + +#include <vector> +#include <map> +#include <chrono> + +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 > fvDigiT0 = {}; + 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 fPrevTimeT0 = 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 T0 hits + /// => Time-order means the time window for following one can only be in a later digi + Int_t fPrevT0FirstDigiSts = 0; + Int_t fPrevT0FirstDigiMuch = 0; + Int_t fPrevT0FirstDigiTrd = 0; + Int_t fPrevT0FirstDigiTof = 0; + Int_t fPrevT0FirstDigiRich = 0; + Int_t fPrevT0FirstDigiPsd = 0; + + /// User settings: Data correction parameters + /// Charge cut + UInt_t fuMinTotPulserT0 = 182; + UInt_t fuMaxTotPulserT0 = 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* fT0StsDiff = nullptr; + TH1* fT0MuchDiff = nullptr; + TH1* fT0TrdDiff = nullptr; + TH1* fT0TofDiff = nullptr; + TH1* fT0RichDiff = nullptr; + TH1* fT0PsdDiff = nullptr; + TH2* fT0PsdDiffCharge = nullptr; + + TH2* fT0StsDiffEvo = nullptr; + TH2* fT0MuchDiffEvo = nullptr; + TH2* fT0TrdDiffEvo = nullptr; + TH2* fT0TofDiffEvo = nullptr; + TH2* fT0RichDiffEvo = nullptr; + TH2* fT0PsdDiffEvo = nullptr; + + TH2* fT0StsDiffEvoLong = nullptr; + TH2* fT0MuchDiffEvoLong = nullptr; + TH2* fT0TrdDiffEvoLong = nullptr; + TH2* fT0TofDiffEvoLong = nullptr; + TH2* fT0RichDiffEvoLong = nullptr; + TH2* fT0PsdDiffEvoLong = nullptr; + + Double_t fdStartTime = -1; + TProfile* fT0StsMeanEvo = nullptr; + TProfile* fT0MuchMeanEvo = nullptr; + TProfile* fT0TrdMeanEvo = nullptr; + TProfile* fT0TofMeanEvo = nullptr; + TProfile* fT0RichMeanEvo = nullptr; + TProfile* fT0PsdMeanEvo = nullptr; + + TH1* fT0T0Diff = nullptr; + TH1* fStsStsDiff = nullptr; + TH1* fMuchMuchDiff = nullptr; + TH1* fTrdTrdDiff = nullptr; + TH1* fTofTofDiff = nullptr; + TH1* fRichRichDiff = nullptr; + TH1* fPsdPsdDiff = nullptr; + + TH2* fT0StsNb = nullptr; + TH2* fT0MuchNb = nullptr; + TH2* fT0TrdNb = nullptr; + TH2* fT0TofNb = nullptr; + TH2* fT0RichNb = nullptr; + TH2* fT0PsdNb = nullptr; + + Int_t fiT0Nb = 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* fT0Address = nullptr; + TH1* fT0Channel = nullptr; + + TH2* fT0StsDpbDiff = nullptr; + TH2* fT0StsDpbDiffEvo[kuMaxNbStsDpbs]; + TH1* fStsDpbCntsEvo[kuMaxNbStsDpbs]; + + TH2* fT0MuchRocDiff = nullptr; + TH2* fT0MuchAsicDiff = nullptr; + TH2* fT0MuchAsicDiffEvo[kuMaxNbMuchAsics]; + + TH2* fDigisPerAsicEvo = nullptr; + Double_t fdLastMuchDigi[kuMaxNbMuchAsics][ kuNbChanSMX ]; + Double_t fdLastMuchDigiPulser[ kuMaxNbMuchAsics ][ kuNbChanSMX ]; + TH2* fSameChanDigisDistEvo = nullptr; + + Double_t fdLastT0DigiPulser = 0; + + TH2* fDigiTimeEvoT0 = nullptr; + TH2* fDigiTimeEvoSts = nullptr; + TH2* fDigiTimeEvoMuch = nullptr; + TH2* fDigiTimeEvoTof = nullptr; +/*********************** SHOULD GO IN ALGO ****************************/ +}; + +// special class to expose protected TMessage constructor +class CbmMQTMessage : public TMessage +{ + public: + CbmMQTMessage(void* buf, Int_t len) + : TMessage(buf, len) + { + ResetBit(kIsOwner); + } +}; + + +#endif /* CBMDEVICEMCBMMONITORPULSER_H_ */ diff --git a/MQ/mcbm/CbmDeviceMcbmUnpack.cxx b/MQ/mcbm/CbmDeviceMcbmUnpack.cxx new file mode 100644 index 0000000000..5a01f20552 --- /dev/null +++ b/MQ/mcbm/CbmDeviceMcbmUnpack.cxx @@ -0,0 +1,584 @@ +/** + * CbmDeviceMcbmUnpack.cxx + * + * @since 2020-05-04 + * @author P.-A. Loizeau + */ + +#include "CbmDeviceMcbmUnpack.h" +#include "CbmMQDefs.h" + +#include "TimesliceMetaData.h" +#include "CbmMcbm2018UnpackerAlgoSts.h" +#include "CbmMcbm2018UnpackerAlgoMuch.h" +#include "CbmMcbm2018UnpackerAlgoTrdR.h" +#include "CbmMcbm2018UnpackerAlgoTof.h" +#include "CbmMcbm2018UnpackerAlgoRich.h" +#include "CbmMcbm2018UnpackerAlgoPsd.h" +#include "CbmFlesCanvasTools.h" + +#include "StorableTimeslice.hpp" + +#include "FairMQLogger.h" +#include "FairMQProgOptions.h" // device->fConfig +#include "FairParGenericSet.h" +#include "RootSerializer.h" +#include "BoostSerializer.h" + +#include "TNamed.h" +#include "TList.h" +#include "TCanvas.h" +#include "TFile.h" +#include "TH1.h" + +#include <string> +#include <iomanip> +#include <array> + +#include <boost/serialization/utility.hpp> +#include <boost/archive/binary_iarchive.hpp> + +#include <stdexcept> +struct InitTaskError : std::runtime_error { using std::runtime_error::runtime_error; }; + +using namespace std; + +Bool_t bMcbm2018MonitorTaskT0ResetHistos = 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 fuDigiMaskedIdT0 !!!! + 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 ); + + 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 T0 + std::vector< CbmTofDigi > & vDigiTofT0 = fUnpAlgoTof->GetVector(); + std::vector< CbmTofDigi > vDigiTof = {}; + std::vector< CbmTofDigi > vDigiT0 = {}; + + for( auto digi: vDigiTofT0 ) + { + if( fuDigiMaskedIdT0 == ( digi.GetAddress() & fuDigiMaskId ) ) + { + /// Insert data in T0 output container + vDigiT0.emplace_back( digi ); + } // if( fuDigiMaskedIdT0 == ( digi.GetAddress() & fuDigiMaskId ) ) + else + { + /// Insert data in TOF output container + vDigiTof.emplace_back( digi ); + } // else of if( fuDigiMaskedIdT0 == ( 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 ossT0; + boost::archive::binary_oarchive oaT0(ossT0); + oaT0 << vDigiT0; + std::string* strMsgT0 = new std::string(ossT0.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 * >( strMsgT0->c_str() ), // data + strMsgT0->length(), // size + []( void* , void* object ){ delete static_cast< std::string * >( object ); }, + strMsgT0 + ) + ); // 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 kusSysIdT0: + { + fUnpAlgoTof ->AddMsComponentToList(uCompIdx, kusSysIdT0); + break; + } // case kusSysIdT0 + 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 kTRUE; + } // if( kFALSE == fUnpAlgoSts->ProcessTs( ts ) ) + + if( kFALSE == fUnpAlgoMuch->ProcessTs( ts ) ) + { + LOG(error) << "Failed processing TS " << ts.index() + << " in MUCH unpacker algorithm class"; + return kTRUE; + } // if( kFALSE == fUnpAlgoMuch->ProcessTs( ts ) ) + + if( kFALSE == fUnpAlgoTrd->ProcessTs( ts ) ) + { + LOG(error) << "Failed processing TS " << ts.index() + << " in TRD unpacker algorithm class"; + return kTRUE; + } // if( kFALSE == fUnpAlgoTrd->ProcessTs( ts ) ) + + if( kFALSE == fUnpAlgoTof->ProcessTs( ts ) ) + { + LOG(error) << "Failed processing TS " << ts.index() + << " in TOF unpacker algorithm class"; + return kTRUE; + } // if( kFALSE == fUnpAlgoTof->ProcessTs( ts ) ) + + if( kFALSE == fUnpAlgoRich->ProcessTs( ts ) ) + { + LOG(error) << "Failed processing TS " << ts.index() + << " in RICH unpacker algorithm class"; + return kTRUE; + } // if( kFALSE == fUnpAlgoRich->ProcessTs( ts ) ) + + if( kFALSE == fUnpAlgoPsd->ProcessTs( ts ) ) + { + LOG(error) << "Failed processing TS " << ts.index() + << " in PSD unpacker algorithm class"; + return kTRUE; + } // if( kFALSE == fUnpAlgoPsd->ProcessTs( ts ) ) + + + if( 0 == fulTsCounter % 10000 ) + LOG(info) << "Processed " << fulTsCounter << " time slices"; + + return kTRUE; +} + +void CbmDeviceMcbmUnpack::Finish() +{ +} diff --git a/MQ/mcbm/CbmDeviceMcbmUnpack.h b/MQ/mcbm/CbmDeviceMcbmUnpack.h new file mode 100644 index 0000000000..a8f360db45 --- /dev/null +++ b/MQ/mcbm/CbmDeviceMcbmUnpack.h @@ -0,0 +1,113 @@ +/** + * CbmDeviceMcbmUnpack.h + * + * @since 2020-05-04 + * @author P.-A. Loizeau + */ + +#ifndef CBMDEVICEMCBMUNPACK_H_ +#define CBMDEVICEMCBMUNPACK_H_ + +#include "FairMQDevice.h" + +#include "Timeslice.hpp" + +#include "TMessage.h" +#include "Rtypes.h" +#include "TObjArray.h" + +#include <vector> +#include <map> + +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 kusSysIdT0 = 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 fuDigiMaskedIdT0 = 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(); +}; + +// special class to expose protected TMessage constructor +class CbmMQTMessage : public TMessage +{ + public: + CbmMQTMessage(void* buf, Int_t len) + : TMessage(buf, len) + { + ResetBit(kIsOwner); + } +}; + + +#endif /* CBMDEVICEMCBMUNPACK_H_ */ diff --git a/MQ/mcbm/runMcbmEventSink.cxx b/MQ/mcbm/runMcbmEventSink.cxx new file mode 100644 index 0000000000..c844137d8c --- /dev/null +++ b/MQ/mcbm/runMcbmEventSink.cxx @@ -0,0 +1,35 @@ +#include "runFairMQDevice.h" +#include "CbmDeviceMcbmEventSink.h" + +#include <string> +#include <iomanip> + +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(); +} diff --git a/MQ/mcbm/runMcbmEvtBuilderWin.cxx b/MQ/mcbm/runMcbmEvtBuilderWin.cxx new file mode 100644 index 0000000000..328d879b02 --- /dev/null +++ b/MQ/mcbm/runMcbmEvtBuilderWin.cxx @@ -0,0 +1,49 @@ +#include "runFairMQDevice.h" +#include "CbmDeviceMcbmEventBuilderWin.h" + +#include <string> +#include <iomanip> + +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( "kT0" ), + "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 CbmDeviceMcbmEventBuilderWin(); +} diff --git a/MQ/mcbm/runMcbmMonitorPulser.cxx b/MQ/mcbm/runMcbmMonitorPulser.cxx new file mode 100644 index 0000000000..d1ca3fb514 --- /dev/null +++ b/MQ/mcbm/runMcbmMonitorPulser.cxx @@ -0,0 +1,39 @@ +#include "runFairMQDevice.h" +#include "CbmDeviceMcbmMonitorPulser.h" + +#include <string> +#include <iomanip> + +namespace bpo = boost::program_options; +using namespace std; + +void addCustomOptions(bpo::options_description& options) +{ + options.add_options() ("DebugMoni", bpo::value< bool >()->default_value( false ), + "Debug Monitor Mode"); + options.add_options() ("HistEvoSz", bpo::value< uint32_t >()->default_value( 1800 ), + "Size of evolution histos in seconds"); + options.add_options() ("PulsTotMin", bpo::value< uint32_t >()->default_value( 185 ), + "Minimal TOT for pulser cut"); + options.add_options() ("PulsTotMax", bpo::value< uint32_t >()->default_value( 195 ), + "Maximal TOT for pulser cut"); + 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() ( "TsNameIn", bpo::value< std::string >()->default_value( "unpts_0" ), + "MQ channel name for TS data"); + 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"); +} + +FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) +{ + return new CbmDeviceMcbmMonitorPulser(); +} diff --git a/MQ/mcbm/runMcbmUnpack.cxx b/MQ/mcbm/runMcbmUnpack.cxx new file mode 100644 index 0000000000..c2fa51f483 --- /dev/null +++ b/MQ/mcbm/runMcbmUnpack.cxx @@ -0,0 +1,25 @@ +#include "runFairMQDevice.h" +#include "CbmDeviceMcbmUnpack.h" + +#include <string> +#include <iomanip> + +namespace bpo = boost::program_options; +using namespace std; + +void addCustomOptions(bpo::options_description& options) +{ + options.add_options() ("IgnOverMs", bpo::value< bool >()->default_value( true ), + "Ignore overlap MS if true"); + 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( "fullts" ), + "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"); +} + +FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) +{ + return new CbmDeviceMcbmUnpack(); +} diff --git a/MQ/mcbm/startMQMcbmEvtBuilderWin2020.sh.in b/MQ/mcbm/startMQMcbmEvtBuilderWin2020.sh.in new file mode 100755 index 0000000000..561c5e7ba9 --- /dev/null +++ b/MQ/mcbm/startMQMcbmEvtBuilderWin2020.sh.in @@ -0,0 +1,264 @@ +#!/bin/bash +$SIMPATH/bin/fairmq-shmmonitor --cleanup + +if [ $# -ge 1 ]; then + _nbmoni=$1 + ((_pubfreqts = $_nbmoni*100 )) + _pubminsec=1.0 + _pubmaxsec=10.0 + + if [ $# -ge 4 ]; then + _filename="" + _dirname="" + _hostname=$4 + + if [ $# -ge 5 ]; then + _pubfreqts=$5 + + if [ $# -ge 6 ]; then + _pubminsec=$6 + + if [ $# -ge 7 ]; then + _pubmaxsec=$7 + fi + fi + fi + elif [ $# -ge 2 ]; then + _filename=$2 + _hostname="" + if [ $# -eq 3 ]; then + _dirname=$3 + else + _dirname="" + fi + else + echo 'Starting connection to local stream' + echo ' for other usages, please supply at least a filename.' + echo 'Possible usages are:' + echo 'startMQMcbmPulserMonitor2020.sh' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <full filename pattern list>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <filename pattern> <folder_path>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s> <Max Hist pub. in s>' + _filename="" + _dirname="" + _hostname="localhost" + fi +else + echo 'Starting connection to local stream with 1 monitor process' + echo ' for other usages, please supply at least a filename.' + echo 'Possible usages are:' + echo 'startMQMcbmPulserMonitor2020.sh' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <full filename pattern list>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <filename pattern> <folder_path>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s> <Max Hist pub. in s>' + _filename="" + _dirname="" + _hostname="localhost" + _nbmoni=1 + _pubfreqts=100 + _pubminsec=1.0 + _pubmaxsec=10.0 +fi + +_parfileSts=/scratch/cbmroot_macro/macro/beamtime/mcbm2020/mStsPar.par +_parfileMuch=/scratch/cbmroot_macro/macro/beamtime/mcbm2020/mMuchPar.par +_parfileTrdAsic=/scratch/cbmroot_macro/parameters/trd/trd_v18q_mcbm.asic.par +_parfileTrdDigi=/scratch/cbmroot_macro/parameters/trd/trd_v18q_mcbm.digi.par +_parfileTrdGas=/scratch/cbmroot_macro/parameters/trd/trd_v18q_mcbm.gas.par +_parfileTrdGain=/scratch/cbmroot_macro/parameters/trd/trd_v18q_mcbm.gain.par +_parfileTof=/scratch/cbmroot_macro/macro/beamtime/mcbm2020/mTofPar.par +_parfileRich=/scratch/cbmroot_macro/macro/beamtime/mcbm2020/mRichPar.par +_parfilePsd=/scratch/cbmroot_macro/macro/beamtime/mcbm2020/mPsdPar.par + +LOGFILETAG=`hostname` +LOGFILETAG+="_" +LOGFILETAG+=`date +%Y_%m_%d_%H_%M_%S` +LOGFILETAG+=".log" + +(( _paraBuffSz=100 )) +(( _singBuffSz=_paraBuffSz*_nbmoni )) + +echo "Buffer size for parallel devices $_paraBuffSz" +echo "Buffer size for singleton devices $_singBuffSz" + +SAMPLER="MultiTsaSampler" +SAMPLER+=" --id sampler1" +#SAMPLER+=" --max-timeslices 0" +#SAMPLER+=" --max-timeslices 10" +#SAMPLER+=" --max-timeslices 100" +SAMPLER+=" --max-timeslices 300" +#SAMPLER+=" --max-timeslices 1000" +SAMPLER+=" --severity info" +#SAMPLER+=" --flib-port 10" +if [ "$_hostname" != "" ]; then + SAMPLER+=" --flib-host $_hostname" +elif [ "$_filename" != "" ]; then + SAMPLER+=" --filename $_filename" + if [ "$_dirname" != "" ]; then + SAMPLER+=" --dirname $_dirname" + fi +fi +SAMPLER+=" --high-water-mark 1000" +SAMPLER+=" --no-split-ts 1" +SAMPLER+=" --ChNameMissTs missedts" +SAMPLER+=" --ChNameCmds commands" +SAMPLER+=" --channel-config name=fullts,type=push,method=bind,address=tcp://127.0.0.1:11555" +#SAMPLER+=" --channel-config name=fullts,type=push,method=bind,address=tcp://127.0.0.1:11555,sndBufSize=$_singBuffSz,rcvBuffSize=$_paraBuffSz" +#SAMPLER+=" --transport shmem" +SAMPLER+=" --transport zeromq" +#SAMPLER+=" --transport nanomsg" +SAMPLER+=" --channel-config name=missedts,type=pub,method=bind,address=tcp://127.0.0.1:11006" +SAMPLER+=" --channel-config name=commands,type=pub,method=bind,address=tcp://127.0.0.1:11007" +# Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX +# with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log +SAMPLER_LOG="sampler1_$LOGFILETAG" +xterm -l -lf $SAMPLER_LOG -geometry 80x23+0+0 -hold -e @CMAKE_BINARY_DIR@/bin/MQ/source/$SAMPLER & + +echo $SAMPLER + +_iMoni=0 +while (( _iMoni < _nbmoni )); do + (( _yOffset=200*_iMoni )) + (( _iMoni += 1 )) + (( _iPort = 11680 + _iMoni )) + + UNPACKER="McbmUnpack" + UNPACKER+=" --id unp$_iMoni" + UNPACKER+=" --severity info" + UNPACKER+=" --IgnOverMs 1" + UNPACKER+=" --SetTimeOffs kSTS,-985" + UNPACKER+=" --SetTimeOffs kMUCH,-885" + UNPACKER+=" --SetTimeOffs kTRD,-25" + UNPACKER+=" --SetTimeOffs kTOF,25" + UNPACKER+=" --SetTimeOffs kRICH,-310" + UNPACKER+=" --SetTimeOffs kPSD,-240" + UNPACKER+=" --TsNameOut unpts$_iMoni" + UNPACKER+=" --channel-config name=fullts,type=pull,method=connect,address=tcp://127.0.0.1:11555" + #UNPACKER+=" --transport shmem" + UNPACKER+=" --transport zeromq" + #UNPACKER+=" --transport nanomsg" +# UNPACKER+=" --channel-config name=parameters,type=req,method=connect,transport=zeromq,address=tcp://127.0.0.1:11005" + UNPACKER+=" --channel-config name=parameters,type=req,method=connect,transport=zeromq,address=tcp://127.0.0.1:11005,rateLogging=0" + UNPACKER+=" --channel-config name=unpts$_iMoni,type=push,method=bind,transport=zeromq,address=tcp://127.0.0.1:$_iPort" +# UNPACKER+=" --channel-config name=unpts$_iMoni,type=push,method=bind,transport=zeromq,address=tcp://127.0.0.1:$_iPort,sndBufSize=$_paraBuffSz,rcvBuffSize=$_paraBuffSz" +# UNPACKER+=" --channel-config name=commands,type=sub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11007" + #UNPACKER+=" --channel-config name=histogram-in,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11666" + #UNPACKER+=" --channel-config name=histo-conf,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11667,rateLogging=0" + #UNPACKER+=" --channel-config name=canvas-conf,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11668,rateLogging=0" + # Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX + # with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log + UNPACKER_LOG="unp$_iMoni" + UNPACKER_LOG+="_$LOGFILETAG" + VALGRIND_UNP="valgrind -v --error-limit=no --suppressions=$ROOTSYS/share/root/etc/valgrind-root.supp --leak-check=full --show-reachable=yes --log-file=valgrind_unp_log.txt" + VALGHEAP_UNP="valgrind -v --tool=massif --massif-out-file=valgrind_unp_massif.out" + xterm -l -lf $UNPACKER_LOG -geometry 80x23+400+$_yOffset -hold -e @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$UNPACKER & +# xterm -l -lf $UNPACKER_LOG -geometry 80x23+400+$_yOffset -hold -e $VALGRIND_UNP @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$UNPACKER & +# xterm -l -lf $UNPACKER_LOG -geometry 80x23+400+$_yOffset -hold -e $VALGHEAP_UNP @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$UNPACKER & + + EVTBUILDER="McbmEventBuilderWin" + EVTBUILDER+=" --id build$_iMoni" + EVTBUILDER+=" --severity info" + EVTBUILDER+=" --PubFreqTs $_pubfreqts" + EVTBUILDER+=" --PubTimeMin $_pubminsec" + EVTBUILDER+=" --PubTimeMax $_pubmaxsec" + EVTBUILDER+=" --FillHistos true" + EVTBUILDER+=" --IgnTsOver false" + EVTBUILDER+=" --EvtOverMode NoOverlap" + EVTBUILDER+=" --SetTrigWin kT0,-1,10" # To get T0 Digis (seed + close-by digis) in the event + EVTBUILDER+=" --SetTrigWin kSts,-50,100" + EVTBUILDER+=" --SetTrigWin kMuch,-150,50" + EVTBUILDER+=" --SetTrigWin kTrd,-250,100" + EVTBUILDER+=" --SetTrigWin kTof,-150,10" + EVTBUILDER+=" --SetTrigWin kRich,-150,20" + EVTBUILDER+=" --SetTrigWin kPsd,-50,10" + EVTBUILDER+=" --SetTrigMinNb kT0,1" + EVTBUILDER+=" --SetTrigMinNb kSts,0" + EVTBUILDER+=" --SetTrigMinNb kMuch,0" + EVTBUILDER+=" --SetTrigMinNb kTrd,0" + EVTBUILDER+=" --SetTrigMinNb kTof,10" + EVTBUILDER+=" --SetTrigMinNb kRich,0" + EVTBUILDER+=" --SetTrigMinNb kPsd,0" + EVTBUILDER+=" --TsNameIn unpts$_iMoni" + EVTBUILDER+=" --EvtNameOut events" + EVTBUILDER+=" --channel-config name=unpts$_iMoni,type=pull,method=connect,transport=zeromq,address=tcp://127.0.0.1:$_iPort" + #EVTBUILDER+=" --transport shmem" + EVTBUILDER+=" --transport zeromq" + #EVTBUILDER+=" --transport nanomsg" + EVTBUILDER+=" --channel-config name=events,type=push,method=connect,transport=zeromq,address=tcp://127.0.0.1:11556" +# EVTBUILDER+=" --channel-config name=commands,type=sub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11007" + EVTBUILDER+=" --channel-config name=parameters,type=req,method=connect,transport=zeromq,address=tcp://127.0.0.1:11005,rateLogging=0" + EVTBUILDER+=" --channel-config name=histogram-in,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11666" + EVTBUILDER+=" --channel-config name=histo-conf,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11667,rateLogging=0" + EVTBUILDER+=" --channel-config name=canvas-conf,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11668,rateLogging=0" + # Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX + # with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log + EVTBUILDER_LOG="build$_iMoni" + EVTBUILDER_LOG+="_$LOGFILETAG" + VALGRIND_EVT="valgrind -v --error-limit=no --suppressions=$ROOTSYS/share/root/etc/valgrind-root.supp --leak-check=full --show-reachable=yes --log-file=valgrind_evt_log.txt" + VALGHEAP_EVT="valgrind --tool=massif --massif-out-file=valgrind_evt_massif.out" + xterm -l -lf $EVTBUILDER_LOG -geometry 80x23+800+$_yOffset -hold -e @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$EVTBUILDER & +# xterm -l -lf $EVTBUILDER_LOG -geometry 80x23+800+$_yOffset -hold -e $VALGRIND_EVT @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$EVTBUILDER & +# xterm -l -lf $EVTBUILDER_LOG -geometry 80x23+800+$_yOffset -hold -e $VALGHEAP_EVT @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$EVTBUILDER & + +done + +EVTSINK="McbmEventSink" +EVTSINK+=" --id evtsink1" +EVTSINK+=" --severity info" +EVTSINK+=" --OutFileName mcbm_digis_events.root" +EVTSINK+=" --FillHistos false" +EVTSINK+=" --PubFreqTs $_pubfreqts" +EVTSINK+=" --PubTimeMin $_pubminsec" +EVTSINK+=" --PubTimeMax $_pubmaxsec" +EVTSINK+=" --EvtNameIn events" +EVTSINK+=" --channel-config name=events,type=pull,method=bind,transport=zeromq,address=tcp://127.0.0.1:11556" +#EVTSINK+=" --channel-config name=events,type=pull,method=bind,transport=zeromq,address=tcp://127.0.0.1:11556,sndBufSize=$_paraBuffSz,rcvBuffSize=$_unpBufSz" +EVTSINK+=" --channel-config name=missedts,type=sub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11006" +EVTSINK+=" --channel-config name=commands,type=sub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11007" +EVTSINK+=" --channel-config name=histogram-in,type=sub,method=bind,transport=zeromq,address=tcp://127.0.0.1:11666" +EVTSINK+=" --channel-config name=histo-conf,type=sub,method=bind,transport=zeromq,address=tcp://127.0.0.1:11667,rateLogging=0" +EVTSINK+=" --channel-config name=canvas-conf,type=sub,method=bind,transport=zeromq,address=tcp://127.0.0.1:11668,rateLogging=0" +# Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX +# with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log +EVTSINK_LOG="evtsink1_$LOGFILETAG" +VALGRIND_SINK="valgrind -v --error-limit=no --suppressions=$ROOTSYS/share/root/etc/valgrind-root.supp --leak-check=full --show-reachable=yes --log-file=valgrind_sink_log.txt" +VALGHEAP_SINK="valgrind -v --tool=massif --massif-out-file=valgrind_sink_massif.out" +VALGCPU_SINK="valgrind -v --tool=callgrind" +#xterm -l -lf $EVTSINK_LOG -geometry 80x23+1200+0 -hold -e @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$EVTSINK & +#xterm -l -lf $EVTSINK_LOG -geometry 80x23+1200+0 -hold -e $VALGRIND_SINK @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$EVTSINK & +#xterm -l -lf $EVTSINK_LOG -geometry 80x23+1200+0 -hold -e $VALGHEAP_SINK @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$EVTSINK & +xterm -l -lf $EVTSINK_LOG -geometry 80x23+1200+0 -hold -e $VALGCPU_SINK @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$EVTSINK & + +PARAMETERSERVER="parmq-server" +PARAMETERSERVER+=" --id parmq-server" +PARAMETERSERVER+=" --severity info" +PARAMETERSERVER+=" --channel-name parameters" +#PARAMETERSERVER+=" --channel-config name=parameters,type=rep,method=bind,transport=zeromq,address=tcp://127.0.0.1:11005" +PARAMETERSERVER+=" --channel-config name=parameters,type=rep,method=bind,transport=zeromq,address=tcp://127.0.0.1:11005,rateLogging=0" +PARAMETERSERVER+=" --first-input-name $_parfileSts;$_parfileMuch;$_parfileTrdAsic;$_parfileTrdDigi;$_parfileTrdGas;$_parfileTrdGain;$_parfileTof;$_parfileRich;$_parfilePsd" +PARAMETERSERVER+=" --first-input-type ASCII" +PARAMETERSERVER+=" --libs-to-load=libCbmFlibMcbm2018" # doesn't work due to runtime problem +# Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX +# with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log +PARAMSRV_LOG="parmq_$LOGFILETAG" +xterm -l -lf $PARAMSRV_LOG -geometry 80x23+1600+0 -hold -e @CMAKE_BINARY_DIR@/bin/MQ/parmq/$PARAMETERSERVER & + +HISTSERVER="MqHistoServer" +HISTSERVER+=" --id server1" +HISTSERVER+=" --severity info" +HISTSERVER+=" --histport 8081" +HISTSERVER+=" --channel-config name=histogram-in,type=sub,method=bind,transport=zeromq,address=tcp://127.0.0.1:11666" +HISTSERVER+=" --channel-config name=histo-conf,type=sub,method=bind,transport=zeromq,address=tcp://127.0.0.1:11667,rateLogging=0" +HISTSERVER+=" --channel-config name=canvas-conf,type=sub,method=bind,transport=zeromq,address=tcp://127.0.0.1:11668,rateLogging=0" +# Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX +# with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log +HISTSRV_LOG="server1_$LOGFILETAG" +xterm -l -lf $HISTSRV_LOG -geometry 80x23+2000+0 -hold -e @CMAKE_BINARY_DIR@/bin/MQ/histogramServer/$HISTSERVER & diff --git a/MQ/mcbm/startMQMcbmPulserMonitor2020.sh.in b/MQ/mcbm/startMQMcbmPulserMonitor2020.sh.in new file mode 100755 index 0000000000..6bab6e5f25 --- /dev/null +++ b/MQ/mcbm/startMQMcbmPulserMonitor2020.sh.in @@ -0,0 +1,160 @@ +#!/bin/bash +$SIMPATH/bin/fairmq-shmmonitor --cleanup + +if [ $# -ge 1 ]; then + _nbmoni=$1 + ((_pubfreqts = $_nbmoni*100 )) + _pubminsec=1.0 + _pubmaxsec=10.0 + + if [ $# -ge 4 ]; then + _filename="" + _dirname="" + _hostname=$4 + + if [ $# -ge 5 ]; then + _pubfreqts=$5 + + if [ $# -ge 6 ]; then + _pubminsec=$6 + + if [ $# -ge 7 ]; then + _pubmaxsec=$7 + fi + fi + fi + elif [ $# -ge 2 ]; then + _filename=$2 + _hostname="" + if [ $# -eq 3 ]; then + _dirname=$3 + else + _dirname="" + fi + else + echo 'Starting connection to local stream' + echo ' for other usages, please supply at least a filename.' + echo 'Possible usages are:' + echo 'startMQMcbmPulserMonitor2020.sh' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <full filename pattern list>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <filename pattern> <folder_path>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s> <Max Hist pub. in s>' + _filename="" + _dirname="" + _hostname="localhost" + fi +else + echo 'Starting connection to local stream with 1 monitor process' + echo ' for other usages, please supply at least a filename.' + echo 'Possible usages are:' + echo 'startMQMcbmPulserMonitor2020.sh' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <full filename pattern list>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <filename pattern> <folder_path>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s>' + echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s> <Max Hist pub. in s>' + _filename="" + _dirname="" + _hostname="localhost" + _nbmoni=1 + _pubfreqts=100 + _pubminsec=1.0 + _pubmaxsec=10.0 +fi + +_parfileSts=/scratch/cbmroot_macro/macro/beamtime/mcbm2020/mStsPar.par +_parfileMuch=/scratch/cbmroot_macro/macro/beamtime/mcbm2020/mMuchPar.par +_parfileTrdAsic=/scratch/cbmroot_macro/parameters/trd/trd_v18q_mcbm.asic.par +_parfileTrdDigi=/scratch/cbmroot_macro/parameters/trd/trd_v18q_mcbm.digi.par +_parfileTrdGas=/scratch/cbmroot_macro/parameters/trd/trd_v18q_mcbm.gas.par +_parfileTrdGain=/scratch/cbmroot_macro/parameters/trd/trd_v18q_mcbm.gain.par +_parfileTof=/scratch/cbmroot_macro/macro/beamtime/mcbm2020/mTofPar.par +_parfileRich=/scratch/cbmroot_macro/macro/beamtime/mcbm2020/mRichPar.par +_parfilePsd=/scratch/cbmroot_macro/macro/beamtime/mcbm2020/mPsdPar.par + +SAMPLER="MultiTsaSampler" +SAMPLER+=" --id sampler1" +SAMPLER+=" --max-timeslices 0" +SAMPLER+=" --severity info" +#SAMPLER+=" --flib-port 10" +if [ "$_hostname" != "" ]; then + SAMPLER+=" --flib-host $_hostname" +elif [ "$_filename" != "" ]; then + SAMPLER+=" --filename $_filename" + if [ "$_dirname" != "" ]; then + SAMPLER+=" --dirname $_dirname" + fi +fi +SAMPLER+=" --high-water-mark 1000" +SAMPLER+=" --no-split-ts 1" +SAMPLER+=" --channel-config name=fullts,type=push,method=bind,address=tcp://127.0.0.1:11555" +#SAMPLER+=" --transport shmem" +SAMPLER+=" --transport zeromq" +#SAMPLER+=" --transport nanomsg" +xterm -l -geometry 80x23+0+0 -hold -e @CMAKE_BINARY_DIR@/bin/MQ/source/$SAMPLER & + +_iMoni=0 +while (( _iMoni < _nbmoni )); do + (( _yOffset=200*_iMoni )) + (( _iMoni += 1 )) + (( _iPort = 11680 + _iMoni )) + + UNPACKER="McbmUnpack" + UNPACKER+=" --id unp$_iMoni" + UNPACKER+=" --severity info" + UNPACKER+=" --IgnOverMs 1" + UNPACKER+=" --TsNameOut unpts$_iMoni" + UNPACKER+=" --channel-config name=fullts,type=pull,method=connect,address=tcp://127.0.0.1:11555" + #UNPACKER+=" --transport shmem" + UNPACKER+=" --transport zeromq" + #UNPACKER+=" --transport nanomsg" +# UNPACKER+=" --channel-config name=parameters,type=req,method=connect,transport=zeromq,address=tcp://127.0.0.1:11005" + UNPACKER+=" --channel-config name=parameters,type=req,method=connect,transport=zeromq,address=tcp://127.0.0.1:11005,rateLogging=0" + UNPACKER+=" --channel-config name=unpts$_iMoni,type=pub,method=bind,transport=zeromq,address=tcp://127.0.0.1:$_iPort" + #UNPACKER+=" --channel-config name=histogram-in,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11666" + #UNPACKER+=" --channel-config name=histo-conf,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11667,rateLogging=0" + #UNPACKER+=" --channel-config name=canvas-conf,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11668,rateLogging=0" + xterm -l -geometry 80x23+400+$_yOffset -hold -e @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$UNPACKER & + + MONITOR="McbmMonitorPulser" + MONITOR+=" --id mon$_iMoni" + MONITOR+=" --severity info" + MONITOR+=" --PubFreqTs $_pubfreqts" + MONITOR+=" --PubTimeMin $_pubminsec" + MONITOR+=" --PubTimeMax $_pubmaxsec" + MONITOR+=" --TsNameIn unpts$_iMoni" + MONITOR+=" --channel-config name=unpts$_iMoni,type=sub,method=connect,transport=zeromq,address=tcp://127.0.0.1:$_iPort" + #MONITOR+=" --transport shmem" + MONITOR+=" --transport zeromq" + #MONITOR+=" --transport nanomsg" + MONITOR+=" --channel-config name=parameters,type=req,method=connect,transport=zeromq,address=tcp://127.0.0.1:11005,rateLogging=0" + MONITOR+=" --channel-config name=histogram-in,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11666" + MONITOR+=" --channel-config name=histo-conf,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11667,rateLogging=0" + MONITOR+=" --channel-config name=canvas-conf,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11668,rateLogging=0" + xterm -l -geometry 80x23+800+$_yOffset -hold -e @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$MONITOR & +done + +PARAMETERSERVER="parmq-server" +PARAMETERSERVER+=" --id parmq-server" +PARAMETERSERVER+=" --severity info" +PARAMETERSERVER+=" --channel-name parameters" +#PARAMETERSERVER+=" --channel-config name=parameters,type=rep,method=bind,transport=zeromq,address=tcp://127.0.0.1:11005" +PARAMETERSERVER+=" --channel-config name=parameters,type=rep,method=bind,transport=zeromq,address=tcp://127.0.0.1:11005,rateLogging=0" +PARAMETERSERVER+=" --first-input-name $_parfileSts;$_parfileMuch;$_parfileTrdAsic;$_parfileTrdDigi;$_parfileTrdGas;$_parfileTrdGain;$_parfileTof;$_parfileRich;$_parfilePsd" +PARAMETERSERVER+=" --first-input-type ASCII" +PARAMETERSERVER+=" --libs-to-load=libCbmFlibMcbm2018" # doesn't work due to runtime problem +xterm -geometry 80x23+1200+0 -hold -e @CMAKE_BINARY_DIR@/bin/MQ/parmq/$PARAMETERSERVER & + +HISTSERVER="MqHistoServer" +HISTSERVER+=" --id server1" +HISTSERVER+=" --histport 8081" +HISTSERVER+=" --channel-config name=histogram-in,type=sub,method=bind,transport=zeromq,address=tcp://127.0.0.1:11666" +HISTSERVER+=" --channel-config name=histo-conf,type=sub,method=bind,transport=zeromq,address=tcp://127.0.0.1:11667,rateLogging=0" +HISTSERVER+=" --channel-config name=canvas-conf,type=sub,method=bind,transport=zeromq,address=tcp://127.0.0.1:11668,rateLogging=0" +xterm -geometry 80x23+1400+0 -hold -e @CMAKE_BINARY_DIR@/bin/MQ/histogramServer/$HISTSERVER & -- GitLab