Skip to content
Snippets Groups Projects

Compare revisions

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

Source

Select target project
No results found

Target

Select target project
  • le.koch/cbmroot
  • patrick.pfistner_AT_kit.edu/cbmroot
  • lena.rossel_AT_stud.uni-frankfurt.de/cbmroot
  • i.deppner/cbmroot
  • fweig/cbmroot
  • karpushkin_AT_inr.ru/cbmroot
  • v.akishina/cbmroot
  • rishat.sultanov_AT_cern.ch/cbmroot
  • l_fabe01_AT_uni-muenster.de/cbmroot
  • pwg-c2f/cbmroot
  • j.decuveland/cbmroot
  • a.toia/cbmroot
  • i.vassiliev/cbmroot
  • n.herrmann/cbmroot
  • o.lubynets/cbmroot
  • se.gorbunov/cbmroot
  • cornelius.riesen_AT_physik.uni-giessen.de/cbmroot
  • zhangqn17_AT_mails.tsinghua.edu.cn/cbmroot
  • bartosz.sobol/cbmroot
  • ajit.kumar/cbmroot
  • computing/cbmroot
  • a.agarwal_AT_vecc.gov.in/cbmroot
  • osingh/cbmroot
  • wielanek_AT_if.pw.edu.pl/cbmroot
  • malgorzata.karabowicz.stud_AT_pw.edu.pl/cbmroot
  • m.shiroya/cbmroot
  • s.roy/cbmroot
  • p.-a.loizeau/cbmroot
  • a.weber/cbmroot
  • ma.beyer/cbmroot
  • d.klein/cbmroot
  • d.smith/cbmroot
  • mvdsoft/cbmroot
  • d.spicker/cbmroot
  • y.h.leung/cbmroot
  • m.deveaux/cbmroot
  • mkunold/cbmroot
  • h.darwish/cbmroot
  • f_fido01_AT_uni-muenster.de/cbmroot
  • g.kozlov/cbmroot
  • d.emschermann/cbmroot
  • evgeny.lavrik/cbmroot
  • v.friese/cbmroot
  • f.uhlig/cbmroot
  • ebechtel_AT_ikf.uni-frankfurt.de/cbmroot
  • a.senger/cbmroot
  • praisig/cbmroot
  • s.lebedev/cbmroot
  • redelbach_AT_compeng.uni-frankfurt.de/cbmroot
  • p.subramani/cbmroot
  • a_meye37_AT_uni-muenster.de/cbmroot
  • om/cbmroot
  • o.golosov/cbmroot
  • l.chlad/cbmroot
  • a.bercuci/cbmroot
  • d.ramirez/cbmroot
  • v.singhal/cbmroot
  • h.schiller/cbmroot
  • apuntke/cbmroot
  • f.zorn/cbmroot
  • rubio_AT_physi.uni-heidelberg.de/cbmroot
  • p.chudoba/cbmroot
  • apuntke/mcbmroot
  • r.karabowicz/cbmroot
64 results
Show changes
Showing
with 5219 additions and 391 deletions
#!/bin/bash
# Copyright (C) 2020 PI-UHd,GSI
# SPDX-License-Identifier: GPL-3.0-only
# First commited by Norbert Herrmann
$FAIRROOTPATH/bin/shmmonitor --cleanup
if [ -z "$1" ]; then
_runname="MCBM_cosmic_`date +%F`_`date +%T`"
else
_runname=$1
fi
if [ -z "$2" ]; then
_version=0
else
_version=$2
fi
if [ -z "$3" ]; then
_node="node8"
else
_node=$3
fi
_reqmod=0
_reqtint=50
_ntimeslices=-1
#_ntimeslices=100
_iUnp=1
_batch=1
_pulmode=0
_pulmulmin=18
_pultotmin=80
_pultotmax=500
_puldetref=12 # TSR=022
#_puldetref=16 # TSR=032
#_puldetref=17 # TSR=032
_tofftof=0.
#_tofftof=-30.
if [[ $_reqmod -eq 1 ]]; then
_iUnp=1
fi
_dirname=${VMCWORKDIR}/macro/beamtime/mcbm2021/input/$_runname/
#_outdir=${VMCWORKDIR}/macro/beamtime/hd2020/data/
_outdir=${VMCWORKDIR}/macro/beamtime/mcbm2021/data/
#_datapath=~/KRONOS/CBM/cbmroot/git/cbmroot
_filename=$_runname*.tsa
#_filename=${VMCWORKDIR}/macro/beamtime/hd2020/input/$_runname/*.tsa
#_outdir=$_datapath/macro/beamtime/mcbm2018/data/
#_filename="./tsaData/_pn05_*.tsa;./tsaData/_pn06_*.tsa;./tsaData/_pn07_*.tsa"
_digifile=$_runname.$_reqtint.$_reqmod.$_pulmode.$_version.$_node.root
# ASCII files
_mapfile=${VMCWORKDIR}/macro/beamtime/mcbm2021/mTofCriPar.par
_digibdffile=${VMCWORKDIR}/parameters/tof/tof_v21f_mcbm.digibdf.par
#_digiparfile=${VMCWORKDIR}/parameters/tof/tof_v21c_mcbm.digi.par
# ROOT files
#_geofile=${VMCWORKDIR}/macro/beamtime/mcbm2021/tof_mcbm_beam_2021_07.par.root
#_geofile=${VMCWORKDIR}/macro/beamtime/mcbm2021/tof_mcbm_beam_2021_07_surveyed.par.root
_geofile=${VMCWORKDIR}/macro/beamtime/mcbm2021/tof_mcbm_beam_2021_08.par.root
rm -v nohup.out
rm -v *log
rm all_*
PARAMETERSERVER="parmq-server"
echo pkill $PARAMETERSERVER
pkill -9 $PARAMETERSERVER
sleep 1
PARAMETERSERVER+=" --id parmq-server"
PARAMETERSERVER+=" --channel-name parameters"
PARAMETERSERVER+=" --channel-config name=parameters,type=rep,method=bind,rateLogging=0,transport=zeromq,address=tcp://127.0.0.1:5005"
#PARAMETERSERVER+=" --libs-to-load libCbmTof;libCbmFlibMcbm2018"
#PARAMETERSERVER+=" --first-input-name $_mapfile;$_digiparfile;$_digibdffile"
PARAMETERSERVER+=" --first-input-name $_mapfile;$_digibdffile"
PARAMETERSERVER+=" --first-input-type ASCII"
PARAMETERSERVER+=" --second-input-name $_geofile"
PARAMETERSERVER+=" --second-input-type ROOT"
#PARAMETERSERVER+=" --severity INFO"
PARAMETERSERVER+=" --severity DEBUG"
#PARAMETERSERVER+=" --file-severity INFO"
if [[ $_batch = 1 ]]; then
PARAMETERSERVER+=" --control static"
PARAMETERSERVER+=" --log-to-file ParServ.out"
nohup ${VMCWORKDIR}/build/bin/MQ/parmq/$PARAMETERSERVER &
else
xterm -geometry 80x23+0+340 -hold -e ${VMCWORKDIR}/build/bin/MQ/parmq/$PARAMETERSERVER &
#xterm -geometry 80x23+500+0 -hold -e /home/cbm/starsoft/fairroot_v18.0.6-fairsoft_may18p1_root6/bin/$PARAMETERSERVER &
fi
SAMPLER="TsaMultiSamplerTof"
SAMPLER+=" --id sampler1"
SAMPLER+=" --max-timeslices $_ntimeslices"
#SAMPLER+=" --max-timeslices 1000000"
#SAMPLER+=" --flib-port 5556"
#SAMPLER+=" --flib-host $_node"
SAMPLER+=" --dirname $_dirname"
SAMPLER+=" --filename $_filename"
SAMPLER+=" --channel-config name=tofcomponent,type=push,method=bind,rateLogging=0,transport=zeromq,address=tcp://*:5655"
SAMPLER+=" --channel-config name=syscmd,type=pub,method=bind,rateLogging=0,transport=zeromq,address=tcp://*:5666"
#SAMPLER+=" --transport shmem"
#SAMPLER+=" --transport zeromq"
#SAMPLER+=" --transport nanomsg"
#SAMPLER+=" --severity WARN"
SAMPLER+=" --severity INFO"
SAMPLER+=" --file-severity INFO"
#SAMPLER+=" --severity DEBUG"
SAMPLER+=" --SelectComponents 0"
if [[ $_batch = 1 ]]; then
SAMPLER+=" --log-to-file Sampl.out"
SAMPLER+=" --control static"
nohup ${VMCWORKDIR}/build/bin/MQ/source/$SAMPLER &
else
xterm -geometry 80x23+0+0 -hold -e ${VMCWORKDIR}/build/bin/MQ/source/$SAMPLER &
fi
while (( _iUnp > 0 )); do
UNPACKER="UnpackTofCri"
UNPACKER+=" --id unpack$_iUnp"
UNPACKER+=" --channel-config name=tofcomponent,type=pull,method=connect,rateLogging=0,transport=zeromq,address=tcp://127.0.0.1:5655"
UNPACKER+=" --channel-config name=parameters,type=req,method=connect,rateLogging=0,transport=zeromq,address=tcp://127.0.0.1:5005"
UNPACKER+=" --channel-config name=tofdigis,type=push,method=connect,rateLogging=0,transport=zeromq,address=tcp://127.0.0.1:5656"
UNPACKER+=" --channel-config name=syscmd,type=sub,method=connect,rateLogging=0,transport=zeromq,address=tcp://127.0.0.1:5666"
#UNPACKER+=" --transport shmem"
#UNPACKER+=" --severity DEBUG"
#UNPACKER+=" --severity INFO"
UNPACKER+=" --file-severity info"
UNPACKER+=" --SelectComponents 0"
UNPACKER+=" --ReqMode $_reqmod"
UNPACKER+=" --ReqTint $_reqtint"
UNPACKER+=" --PulserMode $_pulmode"
UNPACKER+=" --PulMulMin $_pulmulmin"
UNPACKER+=" --PulTotMin $_pultotmin"
UNPACKER+=" --PulTotMax $_pultotmax"
UNPACKER+=" --ToffTof $_tofftof"
UNPACKER+=" --RefModType -1"
UNPACKER+=" --RefModId 0"
UNPACKER+=" --RefCtrType 0"
UNPACKER+=" --RefCtrId 0"
if [[ $_batch = 1 ]]; then
UNPACKER+=" --control static"
UNPACKER+=" --log-to-file Unp$_iUnp.out"
nohup ${VMCWORKDIR}/build/bin/MQ/unpacker/$UNPACKER &
else
xterm -geometry 110x23+520+0 -hold -e ${VMCWORKDIR}/build/bin/MQ/unpacker/$UNPACKER &
fi
(( _iUnp -= 1 ))
done
HITBUILDER="HitBuilderTof"
HITBUILDER+=" --id hitbuilder1"
HITBUILDER+=" --channel-config name=tofdigis,type=pull,method=bind,rateLogging=0,transport=zeromq,address=tcp://*:5656"
HITBUILDER+=" --channel-config name=parameters,type=req,method=connect,rateLogging=0,transport=zeromq,address=tcp://127.0.0.1:5005"
HITBUILDER+=" --channel-config name=syscmd,type=sub,method=connect,rateLogging=0,transport=zeromq,address=tcp://127.0.0.1:5666"
#HITBUILDER+=" --channel-config name=tofhits,type=push,method=bind,transport=shmem,address=tcp://127.0.0.1:5557"
#HITBUILDER+=" --channel-config name=tofcalib,type=push,method=bind,transport=shmem,address=tcp://127.0.0.1:5558"
#HITBUILDER+=" --transport shmem"
#HITBUILDER+=" --severity DEBUG"
HITBUILDER+=" --severity INFO"
HITBUILDER+=" --file-severity INFO"
#HITBUILDER+=" --severity WARN"
HITBUILDER+=" --OutRootFile $_outdir$_digifile"
#HITBUILDER+=" --MaxEvent 10000000"
#HITBUILDER+=" --RunId 1581312162" # v20a
#HITBUILDER+=" --RunId 1597162455" # v20b
#HITBUILDER+=" --RunId 1621902311" # tof_mcbm_beam_2021_02.par.root
#HITBUILDER+=" --RunId 1629444189" # tof_mcbm_beam_2021_07.par.root
#HITBUILDER+=" --RunId 1639163969" # tof_mcbm_beam_2021_07_surveyed.par.root
HITBUILDER+=" --RunId 1647348218" # tof_mcbm_beam_2021_08.par.root
HITBUILDER+=" --PulserMode $_pulmode"
HITBUILDER+=" --PulMulMin $_pulmulmin"
HITBUILDER+=" --PulTotMin $_pultotmin"
HITBUILDER+=" --PulTotMax $_pultotmax"
HITBUILDER+=" --PulDetRef $_puldetref"
HITBUILDER+=" --ReqTint $_reqtint"
#HITBUILDER+=" --ReqBeam 20486" # diamond -> 0x00005006
HITBUILDER+=" --BRefType -1" # -1 = no beam counter
HITBUILDER+=" --BRefSm 0"
HITBUILDER+=" --BRefDet -1" # -1 = use ModMask
HITBUILDER+=" --DutType 0"
HITBUILDER+=" --DutSm 1"
HITBUILDER+=" --DutRpc 2"
HITBUILDER+=" --SelType 0"
HITBUILDER+=" --SelSm 2"
HITBUILDER+=" --SelRpc 2"
HITBUILDER+=" --Sel2Type 2"
HITBUILDER+=" --Sel2Sm 0"
HITBUILDER+=" --Sel2Rpc 2"
if [[ $_batch = 1 ]]; then
HITBUILDER+=" --control static"
HITBUILDER+=" --log-to-file HitBuild.out"
nohup ${VMCWORKDIR}/build/bin/MQ/hitbuilder/$HITBUILDER &
else
xterm -geometry 120x23+1400+0 -hold -e ${VMCWORKDIR}/build/bin/MQ/hitbuilder/$HITBUILDER &
fi
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)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startMQBuildRawEvents.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startMQBuildRawEvents.sh)
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)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startMQBuildRawEvents.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startMQBuildRawEvents.sh)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startBuildRawEvents2021.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startBuildRawEvents2021.sh)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startBuildRawEventsCosmics2021.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startBuildRawEventsCosmics2021.sh)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startBuildRawEvents2022.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startBuildRawEvents2022.sh)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startBmonMoni2022.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startBmonMoni2022.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
${CBMROOT_SOURCE_DIR}/reco/eventbuilder/digis
${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
${VMC_INCLUDE_DIRS}
${FAIRLOGGER_INCLUDE_DIR}
${IPC_INCLUDE_DIRECTORY}
${CBMROOT_SOURCE_DIR}/external/cppzmq
)
include_directories(${INCLUDE_DIRECTORIES})
include_directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES})
set(LINK_DIRECTORIES
${KFParticle_LIB_DIR}
${FAIRMQ_LIBRARY_DIR}
${FAIRROOT_LIBRARY_DIR}
${ROOT_LIBRARY_DIR}
${Boost_LIBRARY_DIRS}
)
link_directories(${LINK_DIRECTORIES})
${CMAKE_CURRENT_SOURCE_DIR}
)
# Set the install path within the build directory
set(EXECUTABLE_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}/MQ/mcbm")
# Set the install path within the installation directory
set(BIN_DESTINATION bin/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_LIBS}
)
set(PUBLIC_DEPS
CbmData
CbmFlibMcbm2018
CbmMQBase
FairRoot::ParBase
ROOT::Core
Boost::program_options
L1
)
If(FAIRLOGGER_FOUND)
set(FAIR_LIBS
${FAIR_LIBS}
FairLogger
)
EndIf()
set(PRIVATE_DEPS
CbmFlibFlesTools
CbmBmonReco
CbmMuchReco
CbmPsdReco
CbmRecoSts
CbmRichReco
CbmSimSteer
CbmTofReco
CbmTrdReco
CbmEventBuilder
FairRoot::Base
ROOT::Gpad
ROOT::Hist
ROOT::RIO
)
set(INTERFACE_DEPS
FairMQ::FairMQ
external::fles_ipc
)
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(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_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(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
set(EXE_NAME BuildRawEvents)
set(SRCS CbmDeviceBuildRawEvents.cxx runBuildRawEvents.cxx)
set(DEPENDENCIES
${DEPENDENCIES}
${FAIR_LIBS}
${BOOST_LIBS}
fles_ipc
KFParticle
CbmFlibMcbm2018
CbmFlibFlesTools
CbmEventBuilder
KF
L1
CbmBase
CbmData
CbmTofBase
CbmSimBase
Core
RIO
Net
Hist
RHTTP
)
#GENERATE_LIBRARY()
GENERATE_EXECUTABLE()
set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_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(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES "${PRIVATE_DEPS};FairRoot::Online")
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_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()
set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES "${PRIVATE_DEPS};FairRoot::Online")
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
set(EXE_NAME MqUnpack)
set(SRCS CbmDeviceUnpack.cxx runUnpack.cxx)
set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
set(EXE_NAME BuildDigiEvents)
set(SRCS CbmDeviceBuildDigiEvents.cxx runBuildDigiEvents.cxx)
set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
set(EXE_NAME DigiEventSink)
set(SRCS CbmDeviceDigiEventSink.cxx runDigiEventSink.cxx)
set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES "${PRIVATE_DEPS};FairRoot::Online")
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
set(EXE_NAME BmonMonitor)
set(SRCS CbmDeviceBmonMonitor.cxx runBmonMonitor.cxx)
set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
# Set the correct variables for the installation
set(VMCWORKDIR ${CMAKE_INSTALL_PREFIX}/share/cbmroot)
set(MY_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_CURRENT_SOURCE_DIR ${VMCWORKDIR}/input)
set(TMPDIR "${CMAKE_BINARY_DIR}")
set(CMAKE_BINARY_DIR ${CMAKE_INSTALL_PREFIX})
# Configure file for installation directory
configure_file(${MY_SOURCE_DIR}/startMQMcbmPulserMonitor2020.sh.in ${TMPDIR}/bin/MQ/topologies/install/startMQMcbmPulserMonitor2020.sh)
configure_file(${MY_SOURCE_DIR}/startMQMcbmEvtBuilderWin2020.sh.in ${TMPDIR}/bin/MQ/topologies/install/startMQMcbmEvtBuilderWin2020.sh)
configure_file(${MY_SOURCE_DIR}/startMQBuildRawEvents.sh.in ${TMPDIR}/bin/MQ/topologies/install/startMQBuildRawEvents.sh)
configure_file(${MY_SOURCE_DIR}/startBuildRawEvents2021.sh.in ${TMPDIR}/bin/MQ/topologies/install/startBuildRawEvents2021.sh)
configure_file(${MY_SOURCE_DIR}/startBuildRawEventsCosmics2021.sh.in ${TMPDIR}/bin/MQ/topologies/install/startBuildRawEventsCosmics2021.sh)
configure_file(${MY_SOURCE_DIR}/startBmonMoni2022.sh.in ${TMPDIR}/bin/MQ/topologies/install/startBmonMoni2022.sh)
install(PROGRAMS ${TMPDIR}/bin/MQ/topologies/install/startMQMcbmPulserMonitor2020.sh
${TMPDIR}/bin/MQ/topologies/install/startMQMcbmEvtBuilderWin2020.sh
${TMPDIR}/bin/MQ/topologies/install/startMQBuildRawEvents.sh
${TMPDIR}/bin/MQ/topologies/install/startBuildRawEvents2021.sh
${TMPDIR}/bin/MQ/topologies/install/startBuildRawEventsCosmics2021.sh
DESTINATION ${CMAKE_INSTALL_PREFIX}/bin/MQ/topologies
)
/* Copyright (C) 2022 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceBmonMonitor.cxx
*
* @since 2022-05-23
* @author P.-A. Loizeau
*/
#include "CbmDeviceBmonMonitor.h"
#include "CbmBmonUnpackConfig.h"
#include "CbmFlesCanvasTools.h"
#include "CbmMQDefs.h"
#include "CbmMuchUnpackConfig.h"
#include "CbmPsdUnpackConfig.h"
#include "CbmRichUnpackConfig.h"
#include "CbmSetup.h"
#include "CbmStsUnpackConfig.h"
#include "CbmTofUnpackConfig.h"
#include "CbmTofUnpackMonitor.h"
#include "CbmTrdUnpackConfig.h"
#include "CbmTrdUnpackFaspConfig.h"
#include "StorableTimeslice.hpp"
#include "TimesliceMetaData.h"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairParGenericSet.h"
#include "TCanvas.h"
#include "TFile.h"
#include "TH1.h"
#include "TList.h"
#include "TNamed.h"
#include "BoostSerializer.h"
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/utility.hpp>
#include <array>
#include <iomanip>
#include <stdexcept>
#include <string>
#include <utility>
#include "RootSerializer.h"
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
using namespace std;
//Bool_t bMcbm2018MonitorTaskBmonResetHistos = kFALSE;
CbmDeviceBmonMonitor::CbmDeviceBmonMonitor() {}
void CbmDeviceBmonMonitor::InitTask()
try {
/// Read options from executable
LOG(info) << "Init options for CbmDeviceBmonMonitor.";
fsSetupName = fConfig->GetValue<std::string>("Setup");
fuRunId = fConfig->GetValue<uint32_t>("RunId");
fbUnpBmon = fConfig->GetValue<bool>("UnpBmon");
fbIgnoreOverlapMs = fConfig->GetValue<bool>("IgnOverMs");
fbOutputFullTimeSorting = fConfig->GetValue<bool>("FullTimeSort");
fvsSetTimeOffs = fConfig->GetValue<std::vector<std::string>>("SetTimeOffs");
fsChannelNameDataInput = fConfig->GetValue<std::string>("TsNameIn");
fsChannelNameDataOutput = fConfig->GetValue<std::string>("TsNameOut");
fuPublishFreqTs = fConfig->GetValue<uint32_t>("PubFreqTs");
fdMinPublishTime = fConfig->GetValue<double_t>("PubTimeMin");
fdMaxPublishTime = fConfig->GetValue<double_t>("PubTimeMax");
fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
}
Bool_t CbmDeviceBmonMonitor::InitContainers()
{
LOG(info) << "Init parameter containers for CbmDeviceBmonMonitor.";
// ----- FIXME: Environment settings? or binary option?
TString srcDir = std::getenv("VMCWORKDIR"); // top source directory, standard C++ library
// TString srcDir = gSystem->Getenv("VMCWORKDIR"); // top source directory
// ----- CbmSetup -----------------------------------------------------
// TODO: support for multiple setups on Par Server? with request containing setup name?
CbmSetup* cbmsetup = CbmSetup::Instance();
FairMQMessagePtr req(NewSimpleMessage("setup"));
FairMQMessagePtr rep(NewMessage());
if (Send(req, "parameters") > 0) {
if (Receive(rep, "parameters") >= 0) {
if (0 != rep->GetSize()) {
CbmSetupStorable* exchangableSetup;
CbmMqTMessage tmsg(rep->GetData(), rep->GetSize());
exchangableSetup = dynamic_cast<CbmSetupStorable*>(tmsg.ReadObject(tmsg.GetClass()));
if (nullptr != exchangableSetup) {
/// Prevent clang format single line if
cbmsetup->LoadStoredSetup(exchangableSetup);
}
else {
LOG(error) << "Received corrupt reply. Setup not available";
throw InitTaskError("Setup not received from par-server.");
}
} // if( 0 != rep->GetSize() )
else {
LOG(error) << "Received empty reply. Setup not available";
throw InitTaskError("Setup not received from par-server.");
} // else of if( 0 != rep->GetSize() )
} // if( Receive( rep, "parameters" ) >= 0)
} // if( Send(req, "parameters") > 0 )
// ------------------------------------------------------------------------
/// Initialize the UnpackerConfigs objects and their "user options"
// ---- BMON ----
std::shared_ptr<CbmBmonUnpackConfig> bmonconfig = nullptr;
if (fbUnpBmon) {
bmonconfig = std::make_shared<CbmBmonUnpackConfig>("", fuRunId);
if (bmonconfig) {
// bmonconfig->SetDebugState();
bmonconfig->SetDoWriteOutput();
// bmonconfig->SetDoWriteOptOutA("CbmBmonErrors");
std::string parfilesbasepathBmon = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
bmonconfig->SetParFilesBasePath(parfilesbasepathBmon);
bmonconfig->SetParFileName("mBmonCriPar.par");
bmonconfig->SetSystemTimeOffset(-1220); // [ns] value to be updated
/// Enable Monitor plots
auto monitor = std::make_shared<CbmTofUnpackMonitor>();
monitor->SetBmonMode(true);
monitor->SetInternalHttpMode(false);
if (2337 <= fuRunId) {
monitor->SetSpillThreshold(250);
monitor->SetSpillThresholdNonPulser(100);
}
bmonconfig->SetMonitor(monitor);
}
}
// -------------
/// Enable full time sorting instead of time sorting per FLIM link
if (bmonconfig) SetUnpackConfig(bmonconfig);
/// 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) << "CbmDeviceBmonMonitor::InitContainers => "
<< "Trying to set trigger window with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found " << (*itStrOffs) << " )";
} // if( std::string::npos == charPosDel )
/// Detector Enum Tag
std::string sSelDet = (*itStrOffs).substr(0, charPosDel);
/// Min number
charPosDel++;
int32_t iOffset = std::stoi((*itStrOffs).substr(charPosDel));
if ("kBmon" == sSelDet && fBmonConfig) { //
fBmonConfig->SetSystemTimeOffset(iOffset);
} // else if( "kBmon" == sSelDet )
else {
LOG(info) << "CbmDeviceBmonMonitor::InitContainers => Trying to set time "
"offset for unsupported detector, ignored! "
<< (sSelDet);
continue;
} // else of detector enum detection
} // for( std::vector< std::string >::iterator itStrAdd = fvsAddDet.begin(); itStrAdd != fvsAddDet.end(); ++itStrAdd )
Bool_t initOK = kTRUE;
// --- Bmon
if (fBmonConfig) {
fBmonConfig->InitOutput();
// RegisterOutputs(ioman, fBmonConfig); /// Framework bound work = kept in this Task
fBmonConfig->SetAlgo();
fBmonConfig->LoadParFileName(); /// Needed to change the Parameter file name before it is used!!!
initOK &= InitParameters(fBmonConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fBmonConfig->InitAlgo();
// initPerformanceMaps(fkFlesBmon, "Bmon");
}
/// Event header object
fCbmTsEventHeader = new CbmTsEventHeader();
return initOK;
}
Bool_t
CbmDeviceBmonMonitor::InitParameters(std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* reqparvec)
{
LOG(info) << "CbmDeviceBmonMonitor::InitParameters";
if (!reqparvec) {
LOG(info) << "CbmDeviceBmonMonitor::InitParameters - empty requirements vector no parameters initialized.";
return kTRUE;
}
// Now get the actual ascii files and init the containers with the asciiIo
for (auto& pair : *reqparvec) {
/*
auto filepath = pair.first;
auto parset = pair.second;
FairParAsciiFileIo asciiInput;
if (!filepath.empty()) {
if (asciiInput.open(filepath.data())) { parset->init(&asciiInput); }
}
* */
std::string paramName {pair.second->GetName()};
// NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
// Should only be used for small data because of the cost of an additional copy
// Here must come the proper Runid
std::string message = paramName + ",111";
LOG(info) << "Requesting parameter container " << paramName << ", sending message: " << message;
FairMQMessagePtr req(NewSimpleMessage(message));
FairMQMessagePtr rep(NewMessage());
FairParGenericSet* newObj = nullptr;
if (Send(req, "parameters") > 0) {
if (Receive(rep, "parameters") >= 0) {
if (0 != rep->GetSize()) {
CbmMqTMessage tmsg(rep->GetData(), rep->GetSize());
newObj = static_cast<FairParGenericSet*>(tmsg.ReadObject(tmsg.GetClass()));
LOG(info) << "Received unpack parameter from the server: " << newObj->GetName();
newObj->print();
} // if( 0 != rep->GetSize() )
else {
LOG(error) << "Received empty reply. Parameter not available";
return kFALSE;
} // else of if( 0 != rep->GetSize() )
} // if( Receive( rep, "parameters" ) >= 0)
} // if( Send(req, "parameters") > 0 )
pair.second.reset(newObj); /// Potentially unsafe reasignment of raw pointer to the shared pointer?
//delete newObj;
}
return kTRUE;
}
bool CbmDeviceBmonMonitor::InitHistograms()
{
/// Histos creation and obtain pointer on them
/// Trigger histo creation on all associated algos
// ALGO: bool initOK = fMonitorAlgo->CreateHistograms();
bool initOK = true;
/// Obtain vector of pointers on each histo from the algo (+ optionally desired folder)
// ALGO: std::vector<std::pair<TNamed*, std::string>> vHistos = fMonitorAlgo->GetHistoVector();
std::vector<std::pair<TNamed*, std::string>> vHistos = fBmonConfig->GetMonitor()->GetHistoVector();
/// Obtain vector of pointers on each canvas from the algo (+ optionally desired folder)
// ALGO: std::vector<std::pair<TCanvas*, std::string>> vCanvases = fMonitorAlgo->GetCanvasVector();
std::vector<std::pair<TCanvas*, std::string>> vCanvases = fBmonConfig->GetMonitor()->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);
LOG(info) << "Config of hist " << psHistoConfig.first.data() << " in folder " << psHistoConfig.second.data();
} // for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto )
/// Create canvas config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Canvas name, config >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv) {
// LOG(info) << "Registering " << vCanvases[ uCanv ].first->GetName()
// << " in " << vCanvases[ uCanv ].second.data();
std::string sCanvName = (vCanvases[uCanv].first)->GetName();
std::string sCanvConf = GenerateCanvasConfigString(vCanvases[uCanv].first);
std::pair<std::string, std::string> psCanvConfig(sCanvName, sCanvConf);
fvpsCanvasConfig.push_back(psCanvConfig);
LOG(info) << "Config string of Canvas " << psCanvConfig.first.data() << " is " << psCanvConfig.second.data();
} // for( UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv )
return initOK;
}
// Method called by run loop and requesting new data from the TS source whenever
bool CbmDeviceBmonMonitor::ConditionalRun()
{
/// First do Algo related Initialization steps if needed
if (0 == fulNumMessages) {
try {
InitContainers();
}
catch (InitTaskError& e) {
LOG(error) << e.what();
ChangeState(fair::mq::Transition::ErrorFound);
}
} // if( 0 == fulNumMessages)
if (0 == fulNumMessages) InitHistograms();
/// If first TS of this device, ask for the start time (lead to skip of 1 TS for 1st request)
if (!fbStartTimeSet) {
/// Request the start time
std::string message = "SendFirstTimesliceIndex";
LOG(debug) << "Requesting start time by sending message: SendFirstTimesliceIndex" << message;
FairMQMessagePtr req(NewSimpleMessage(message));
FairMQMessagePtr rep(NewMessage());
if (Send(req, fsChannelNameDataInput) <= 0) {
LOG(error) << "Failed to send the request! message was " << message;
return false;
} // if (Send(req, fsChannelNameDataInput) <= 0)
else if (Receive(rep, fsChannelNameDataInput) < 0) {
LOG(error) << "Failed to receive a reply to the request! message was " << message;
return false;
} // else if (Receive(rep, fsChannelNameDataInput) < 0)
else if (rep->GetSize() == 0) {
LOG(error) << "Received empty reply. Something went wrong with the timeslice generation! message was " << message;
return false;
} // else if (rep->GetSize() == 0)
std::string sReply;
std::string msgStrRep(static_cast<char*>(rep->GetData()), rep->GetSize());
std::istringstream issRep(msgStrRep);
boost::archive::binary_iarchive inputArchiveRep(issRep);
inputArchiveRep >> sReply;
fBmonConfig->GetMonitor()->SetHistosStartTime((1e-9) * static_cast<double>(std::stoul(sReply)));
fbStartTimeSet = true;
}
/// First request a new TS (full one)
std::string message = "full";
LOG(debug) << "Requesting new TS by sending message: full" << message;
FairMQMessagePtr req(NewSimpleMessage(message));
FairMQMessagePtr rep(NewMessage());
if (Send(req, fsChannelNameDataInput) <= 0) {
LOG(error) << "Failed to send the request! message was " << message;
return false;
} // if (Send(req, fsChannelNameDataInput) <= 0)
else if (Receive(rep, fsChannelNameDataInput) < 0) {
LOG(error) << "Failed to receive a reply to the request! message was " << message;
return false;
} // else if (Receive(rep, fsChannelNameDataInput) < 0)
else if (rep->GetSize() == 0) {
LOG(error) << "Received empty reply. Something went wrong with the timeslice generation! message was " << message;
return false;
} // else if (rep->GetSize() == 0)
fulNumMessages++;
LOG(debug) << "Received message number " << fulNumMessages << " with size " << rep->GetSize();
if (0 == fulNumMessages % 10000) LOG(info) << "Received " << fulNumMessages << " messages";
std::string msgStr(static_cast<char*>(rep->GetData()), rep->GetSize());
std::istringstream iss(msgStr);
boost::archive::binary_iarchive inputArchive(iss);
/// Create an empty TS and fill it with the incoming message
fles::StorableTimeslice ts {0};
inputArchive >> ts;
/// On first TS, extract the TS parameters from header (by definition stable over time)
if (-1.0 == fdTsCoreSizeInNs) {
fuNbCoreMsPerTs = ts.num_core_microslices();
fuNbOverMsPerTs = ts.num_microslices(0) - ts.num_core_microslices();
fdMsSizeInNs = (ts.descriptor(0, fuNbCoreMsPerTs).idx - ts.descriptor(0, 0).idx) / fuNbCoreMsPerTs;
fdTsCoreSizeInNs = fdMsSizeInNs * (fuNbCoreMsPerTs);
fdTsOverSizeInNs = fdMsSizeInNs * (fuNbOverMsPerTs);
fdTsFullSizeInNs = fdTsCoreSizeInNs + fdTsOverSizeInNs;
LOG(info) << "Timeslice parameters: each TS has " << fuNbCoreMsPerTs << " Core MS and " << fuNbOverMsPerTs
<< " Overlap MS, for a MS duration of " << fdMsSizeInNs << " ns, a core duration of " << fdTsCoreSizeInNs
<< " ns and a full duration of " << fdTsFullSizeInNs << " ns";
fTsMetaData = new TimesliceMetaData(ts.descriptor(0, 0).idx, fdTsCoreSizeInNs, fdTsOverSizeInNs, ts.index());
} // if( -1.0 == fdTsCoreSizeInNs )
else {
/// Update only the fields changing from TS to TS
fTsMetaData->SetStartTime(ts.descriptor(0, 0).idx);
fTsMetaData->SetIndex(ts.index());
}
/// Process the Timeslice
DoUnpack(ts, 0);
// Reset the event header for a new timeslice
fCbmTsEventHeader->Reset();
// Reset the unpackers for a new timeslice, e.g. clear the output vectors
// ---- Bmon ----
if (fBmonConfig) fBmonConfig->Reset();
/// Send histograms each 100 time slices. Should be each ~1s
/// Use also runtime checker to trigger sending after M s if
/// processing too slow or delay sending if processing too fast
std::chrono::system_clock::time_point currentTime = std::chrono::system_clock::now();
std::chrono::duration<double_t> elapsedSeconds = currentTime - fLastPublishTime;
if ((fdMaxPublishTime < elapsedSeconds.count())
|| (0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count())) {
if (!fbConfigSent) {
// Send the configuration only once per run!
fbConfigSent = SendHistoConfAndData();
} // if( !fbConfigSent )
else
SendHistograms();
fLastPublishTime = std::chrono::system_clock::now();
} // if( ( fdMaxPublishTime < elapsedSeconds.count() ) || ( 0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count() ) )
return true;
}
bool CbmDeviceBmonMonitor::SendUnpData()
{
FairMQParts parts;
/// Prepare serialized versions of the TS Event header
FairMQMessagePtr messTsHeader(NewMessage());
// Serialize<RootSerializer>(*messTsHeader, fCbmTsEventHeader);
RootSerializer().Serialize(*messTsHeader, fCbmTsEventHeader);
parts.AddPart(std::move(messTsHeader));
// ---- Bmon ----
std::stringstream ossBmon;
boost::archive::binary_oarchive oaBmon(ossBmon);
if (fBmonConfig) { //
oaBmon << *(fBmonConfig->GetOutputVec());
}
else {
oaBmon << (std::vector<CbmTofDigi>());
}
std::string* strMsgBmon = new std::string(ossBmon.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgBmon->c_str()), // data
strMsgBmon->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgBmon)); // object that manages the data
/// Prepare serialized versions of the TS Meta
/// FIXME: only for TS duration and overlap, should be sent to parameter service instead as stable values in run
/// Index and start time are already included in the TsHeader object!
FairMQMessagePtr messTsMeta(NewMessage());
// Serialize<RootSerializer>(*messTsMeta, fTsMetaData);
RootSerializer().Serialize(*messTsMeta, fTsMetaData);
parts.AddPart(std::move(messTsMeta));
if (Send(parts, fsChannelNameDataOutput) < 0) {
LOG(error) << "Problem sending data to " << fsChannelNameDataOutput;
return false;
}
return true;
}
bool CbmDeviceBmonMonitor::SendHistoConfAndData()
{
/// Prepare multiparts message and header
std::pair<uint32_t, uint32_t> pairHeader(fvpsHistosFolder.size(), fvpsCanvasConfig.size());
FairMQMessagePtr messageHeader(NewMessage());
// Serialize<BoostSerializer<std::pair<uint32_t, uint32_t>>>(*messageHeader, pairHeader);
BoostSerializer<std::pair<uint32_t, uint32_t>>().Serialize(*messageHeader, pairHeader);
FairMQParts partsOut;
partsOut.AddPart(std::move(messageHeader));
for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto) {
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, fvpsHistosFolder[uHisto]);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist, fvpsHistosFolder[uHisto]);
partsOut.AddPart(std::move(messageHist));
} // for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto)
/// Catch case where no histos are registered!
/// => Add empty message
if (0 == fvpsHistosFolder.size()) {
FairMQMessagePtr messageHist(NewMessage());
partsOut.AddPart(std::move(messageHist));
}
for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv) {
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, fvpsCanvasConfig[uCanv]);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageCan, fvpsCanvasConfig[uCanv]);
partsOut.AddPart(std::move(messageCan));
} // for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv)
/// Catch case where no Canvases are registered!
/// => Add empty message
if (0 == fvpsCanvasConfig.size()) {
FairMQMessagePtr messageHist(NewMessage());
partsOut.AddPart(std::move(messageHist));
}
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr msgHistos(NewMessage());
// Serialize<RootSerializer>(*msgHistos, &fArrayHisto);
RootSerializer().Serialize(*msgHistos, &fArrayHisto);
partsOut.AddPart(std::move(msgHistos));
/// Send the multi-parts message to the common histogram messages queue
if (Send(partsOut, fsChannelNameHistosInput) < 0) {
LOG(error) << "CbmTsConsumerReqDevExample::SendHistoConfAndData => Problem sending data";
return false;
} // if( Send( partsOut, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
// ALGO: fMonitorAlgo->ResetHistograms(kFALSE);
fBmonConfig->GetMonitor()->ResetHistograms();
fBmonConfig->GetMonitor()->ResetBmonHistograms(kFALSE);
return true;
}
bool CbmDeviceBmonMonitor::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
// Serialize<RootSerializer>(*message, &fArrayHisto);
RootSerializer().Serialize(*message, &fArrayHisto);
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
LOG(error) << "Problem sending data";
return false;
} // if( Send( message, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
// ALGO: fMonitorAlgo->ResetHistograms(kFALSE);
return true;
}
CbmDeviceBmonMonitor::~CbmDeviceBmonMonitor()
{
if (fBmonConfig) fBmonConfig->GetUnpacker()->Finish();
}
Bool_t CbmDeviceBmonMonitor::DoUnpack(const fles::Timeslice& ts, size_t /*component*/)
{
fulTsCounter++;
// Prepare timeslice
// const fles::Timeslice& timeslice = *ts;
fCbmTsEventHeader->SetTsIndex(ts.index());
fCbmTsEventHeader->SetTsStartTime(ts.start_time());
uint64_t nComponents = ts.num_components();
// if (fDoDebugPrints) LOG(info) << "Unpack: TS index " << ts.index() << " components " << nComponents;
LOG(debug) << "Unpack: TS index " << ts.index() << " components " << nComponents;
for (uint64_t component = 0; component < nComponents; component++) {
auto systemId = static_cast<std::uint16_t>(ts.descriptor(component, 0).sys_id);
switch (systemId) {
case fkFlesBmon: {
if (fBmonConfig) {
fCbmTsEventHeader->AddNDigisBmon(
unpack(systemId, &ts, component, fBmonConfig, fBmonConfig->GetOptOutAVec(), fBmonConfig->GetOptOutBVec()));
}
break;
}
default: {
if (fDoDebugPrints) LOG(error) << "Unpack: Unknown system ID " << systemId << " for component " << component;
break;
}
}
}
if (0 == fulTsCounter % 10000) LOG(info) << "Processed " << fulTsCounter << " time slices";
return kTRUE;
}
/**
* @brief Get the Trd Spadic
* @return std::shared_ptr<CbmTrdSpadic>
*/
std::shared_ptr<CbmTrdSpadic> CbmDeviceBmonMonitor::GetTrdSpadic(bool useAvgBaseline)
{
auto spadic = std::make_shared<CbmTrdSpadic>();
spadic->SetUseBaselineAverage(useAvgBaseline);
spadic->SetMaxAdcToEnergyCal(1.0);
return spadic;
}
void CbmDeviceBmonMonitor::Finish() {}
/* Copyright (C) 2022 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceBmonMonitor.h
*
* @since 2022-05-23
* @author P.-A. Loizeau
*/
#ifndef CBMDEVICEBMONMONI_H_
#define CBMDEVICEBMONMONI_H_
#include "CbmMqTMessage.h"
#include "CbmTsEventHeader.h"
#include "Timeslice.hpp"
#include "FairMQDevice.h"
#include "FairParGenericSet.h"
#include "Rtypes.h"
#include "TObjArray.h"
#include <chrono>
#include <map>
#include <vector>
class TList;
class CbmBmonUnpackConfig;
class TimesliceMetaData;
class CbmTrdSpadic;
class CbmDeviceBmonMonitor : public FairMQDevice {
public:
CbmDeviceBmonMonitor();
virtual ~CbmDeviceBmonMonitor();
protected:
virtual void InitTask();
bool ConditionalRun();
bool HandleCommand(FairMQMessagePtr&, int);
/** @brief Set the Bmon Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmBmonUnpackConfig> config) { fBmonConfig = config; }
private:
/// Constants
static constexpr std::uint16_t fkFlesBmon = static_cast<std::uint16_t>(fles::Subsystem::BMON);
/// Control flags
Bool_t fbIgnoreOverlapMs = false; //! Ignore Overlap Ms: all fuOverlapMsNb MS at the end of timeslice
Bool_t fbComponentsAddedToList = kFALSE;
bool fbStartTimeSet = false;
/** @brief Flag if extended debug output is to be printed or not*/
bool fDoDebugPrints = false; //!
/** @brief Flag if performance profiling should be activated or not.*/
bool fDoPerfProf = false; //!
/** @brief Flag to Enable/disable a full time sorting. If off, time sorting happens per link/FLIM source */
bool fbOutputFullTimeSorting = false;
/// User settings parameters
std::string fsSetupName = "mcbm_beam_2021_07_surveyed";
uint32_t fuRunId = 1588;
/// ---> for selective unpacking
bool fbUnpBmon = true;
/// message queues
std::string fsChannelNameDataInput = "ts-request";
std::string fsChannelNameDataOutput = "unpts_0";
std::string fsChannelNameCommands = "commands";
std::string fsChannelNameHistosInput = "histogram-in";
/// Histograms management
uint32_t fuPublishFreqTs = 100;
double_t fdMinPublishTime = 0.5;
double_t fdMaxPublishTime = 5.0;
/// Parameters management
// TList* fParCList = nullptr;
Bool_t InitParameters(std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* reqparvec);
/// Statistics & first TS rejection
uint64_t fulNumMessages = 0;
uint64_t fulTsCounter = 0;
std::chrono::system_clock::time_point fLastPublishTime = std::chrono::system_clock::now();
/** @brief Map to store a name for the unpackers and the processed amount of digis, key = fkFlesId*/
std::map<std::uint16_t, std::pair<std::string, size_t>> fNameMap = {}; //!
/** @brief Map to store the cpu and wall time, key = fkFlesId*/
std::map<std::uint16_t, std::pair<double, double>> fTimeMap = {}; //!
/** @brief Map to store the in and out data amount, key = fkFlesId*/
std::map<std::uint16_t, std::pair<double, double>> fDataSizeMap = {}; //!
/// Configuration of the unpackers. Provides the configured algorithm
std::shared_ptr<CbmBmonUnpackConfig> fBmonConfig = nullptr;
/// Pointer to the Timeslice header conatining start time and index
CbmTsEventHeader* fCbmTsEventHeader = nullptr;
/// Time offsets
std::vector<std::string> fvsSetTimeOffs = {};
/// TS MetaData storage: stable so should be moved somehow to parameters handling (not transmitted with each TS
size_t fuNbCoreMsPerTs = 0; //!
size_t fuNbOverMsPerTs = 0; //!
Double_t fdMsSizeInNs = 0; //! Size of a single MS, [nanoseconds]
Double_t fdTsCoreSizeInNs = -1.0; //! Total size of the core MS in a TS, [nanoseconds]
Double_t fdTsOverSizeInNs = -1.0; //! Total size of the overlap MS in a TS, [nanoseconds]
Double_t fdTsFullSizeInNs = -1.0; //! Total size of all MS in a TS, [nanoseconds]
TimesliceMetaData* fTsMetaData;
/// Array of histograms to send to the histogram server
TObjArray fArrayHisto = {};
/// Vector of string pairs with ( HistoName, FolderPath ) to send to the histogram server
std::vector<std::pair<std::string, std::string>> fvpsHistosFolder = {};
/// Vector of string pairs with ( CanvasName, CanvasConfig ) to send to the histogram server
/// Format of Can config is "NbPadX(U);NbPadY(U);ConfigPad1(s);....;ConfigPadXY(s)"
/// Format of Pad config is "GrixX(b),GridY(b),LogX(b),LogY(b),LogZ(b),HistoName(s),DrawOptions(s)"
std::vector<std::pair<std::string, std::string>> fvpsCanvasConfig = {};
/// Flag indicating whether the histograms and canvases configurations were already published
bool fbConfigSent = false;
Bool_t InitContainers();
bool InitHistograms();
Bool_t DoUnpack(const fles::Timeslice& ts, size_t component);
void Finish();
bool SendUnpData();
bool SendHistoConfAndData();
bool SendHistograms();
std::shared_ptr<CbmTrdSpadic> GetTrdSpadic(bool useAvgBaseline);
/** @brief Sort a vector timewise vector type has to provide GetTime() */
template<typename TVecobj>
typename std::enable_if<std::is_same<TVecobj, std::nullptr_t>::value == true, void>::type
timesort(std::vector<TVecobj>* /*vec = nullptr*/)
{
LOG(debug)
<< "CbmDeviceBmonMonitor::timesort() got an object that has no member function GetTime(). Hence, we can and "
"will not timesort it!";
}
template<typename TVecobj>
typename std::enable_if<!std::is_member_function_pointer<decltype(&TVecobj::GetTime)>::value, void>::type
timesort(std::vector<TVecobj>* /*vec = nullptr*/)
{
LOG(debug) << "CbmDeviceBmonMonitor::timesort() " << TVecobj::Class_Name()
<< "is an object that has no member function GetTime(). Hence, we can and "
"will not timesort it!";
}
template<typename TVecobj>
typename std::enable_if<std::is_member_function_pointer<decltype(&TVecobj::GetTime)>::value, void>::type
timesort(std::vector<TVecobj>* vec = nullptr)
{
if (vec == nullptr) return;
std::sort(vec->begin(), vec->end(),
[](const TVecobj& a, const TVecobj& b) -> bool { return a.GetTime() < b.GetTime(); });
}
/**
* @brief Template for the unpacking call of a given algorithm.
*
* @tparam TAlgo Algorithm to be called
* @tparam TOutput Output element types
* @tparam TOptoutputs Optional output element types
* @param ts Timeslice
* @param icomp Component number
* @param algo Algorithm to be used for this component
* @param outtargetvec Target vector for the output elements
* @param optoutputvecs Target vectors for optional outputs
* @return std::pair<ndigis, std::pair<cputime, walltime>>
*/
template<class TConfig, class TOptOutA = std::nullptr_t, class TOptOutB = std::nullptr_t>
size_t unpack(const std::uint16_t subsysid, const fles::Timeslice* ts, std::uint16_t icomp, TConfig config,
std::vector<TOptOutA>* optouttargetvecA = nullptr, std::vector<TOptOutB>* optouttargetvecB = nullptr)
{
auto wallstarttime = std::chrono::high_resolution_clock::now();
std::clock_t cpustarttime = std::clock();
auto algo = config->GetUnpacker();
std::vector<TOptOutA> optoutAvec = {};
std::vector<TOptOutB> optoutBvec = {};
if (optouttargetvecA) { algo->SetOptOutAVec(&optoutAvec); }
if (optouttargetvecB) { algo->SetOptOutBVec(&optoutBvec); }
// Set the start time of the current TS for this algorithm
algo->SetTsStartTime(ts->start_time());
// Run the actual unpacking
auto digivec = algo->Unpack(ts, icomp);
// Check if we want to write the output to somewhere (in pure online monitoring mode for example this can/would/should be skipped)
if (config->GetOutputVec()) {
// Lets do some time-sorting if we are not doing it later
if (!fbOutputFullTimeSorting) timesort(&digivec);
// Transfer the data from the timeslice vector to the target branch vector
// Digis/default output retrieved as offered by the algorithm
for (auto digi : digivec)
config->GetOutputVec()->emplace_back(digi);
}
if (optouttargetvecA) {
// Lets do some timesorting
if (!fbOutputFullTimeSorting) timesort(&optoutAvec);
// Transfer the data from the timeslice vector to the target branch vector
for (auto optoutA : optoutAvec)
optouttargetvecA->emplace_back(optoutA);
}
if (optouttargetvecB) {
// Second opt output is not time sorted to allow non GetTime data container.
// Lets do some timesorting
timesort(&optoutAvec);
// Transfer the data from the timeslice vector to the target branch vector
for (auto optoutB : optoutBvec)
optouttargetvecB->emplace_back(optoutB);
}
std::clock_t cpuendtime = std::clock();
auto wallendtime = std::chrono::high_resolution_clock::now();
// Cpu time in [mus]
auto cputime = 1e6 * (cpuendtime - cpustarttime) / CLOCKS_PER_SEC;
algo->AddCpuTime(cputime);
// Real time in [mus]
auto walltime = std::chrono::duration<double, std::micro>(wallendtime - wallstarttime).count();
algo->AddWallTime(walltime);
// Check some numbers from this timeslice
size_t nDigis = digivec.size();
LOG(debug) << "Component " << icomp << " connected to config " << config->GetName() << " n-Digis " << nDigis
<< " processed in walltime(cputime) = " << walltime << "(" << cputime << cputime << ") micro s"
<< "this timeslice.";
if (fDoPerfProf) {
auto timeit = fTimeMap.find(subsysid);
timeit->second.first += cputime;
timeit->second.second += walltime;
auto datait = fDataSizeMap.find(subsysid);
datait->second.first += ts->size_component(icomp) / 1.0e6;
datait->second.second += nDigis * algo->GetOutputObjSize() / 1.0e6;
fNameMap.find(subsysid)->second.second += nDigis;
}
return nDigis;
}
};
#endif /* CBMDEVICEMCBMUNPACK_H_ */
/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau[committer] */
/**
* CbmDeviceBuildDigiEvents.cxx
*
* @since 2021-11-18
* @author P.-A. Loizeau
*/
#include "CbmDeviceBuildDigiEvents.h"
/// CBM headers
#include "CbmDigiEvent.h"
#include "CbmEvent.h"
#include "CbmFlesCanvasTools.h"
#include "CbmMQDefs.h"
#include "CbmMatch.h"
#include "CbmMvdDigi.h"
#include "CbmTsEventHeader.h"
#include "TimesliceMetaData.h"
/// FAIRROOT headers
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairParGenericSet.h"
#include "FairRunOnline.h"
#include "BoostSerializer.h"
#include "RootSerializer.h"
/// FAIRSOFT headers (geant, boost, ...)
#include "TCanvas.h"
#include "TFile.h"
#include "TH1.h"
#include "TList.h"
#include "TNamed.h"
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/utility.hpp>
/// C/C++ headers
#include <array>
#include <iomanip>
#include <stdexcept>
#include <string>
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
using namespace std;
CbmDeviceBuildDigiEvents::CbmDeviceBuildDigiEvents() { fpAlgo = new CbmAlgoBuildRawEvents(); }
void CbmDeviceBuildDigiEvents::InitTask()
try {
/// Read options from executable
LOG(info) << "Init options for CbmDeviceBuildDigiEvents.";
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");
fvsSetTrigMaxNb = fConfig->GetValue<std::vector<std::string>>("SetTrigMaxNb");
fvsSetTrigMinLayersNb = fConfig->GetValue<std::vector<std::string>>("SetTrigMinLayersNb");
fvsSetHistMaxDigiNb = fConfig->GetValue<std::vector<std::string>>("SetHistMaxDigiNb");
fbDoNotSend = fConfig->GetValue<bool>("DoNotSend");
fbDigiEventOutput = fConfig->GetValue<bool>("DigiEventOutput");
fsChannelNameDataInput = fConfig->GetValue<std::string>("TsNameIn");
fsChannelNameDataOutput = fConfig->GetValue<std::string>("EvtNameOut");
fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
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, &CbmDeviceBuildDigiEvents::HandleData);
}
}
/// FIXME: Disable clang formatting for now as it corrupts all alignment
/* clang-format off */
/// Initialize the Algorithm parameters
fpAlgo->SetFillHistos(fbFillHistos);
fpAlgo->SetIgnoreTsOverlap(fbIgnoreTsOverlap);
/// Extract Event Overlap Mode
EOverlapModeRaw mode = ("NoOverlap" == fsEvtOverMode ? EOverlapModeRaw::NoOverlap
: ("MergeOverlap" == fsEvtOverMode ? EOverlapModeRaw::MergeOverlap
: ("AllowOverlap" == fsEvtOverMode ? EOverlapModeRaw::AllowOverlap
: EOverlapModeRaw::NoOverlap)));
fpAlgo->SetEventOverlapMode(mode);
/// Extract refdet
RawEventBuilderDetector refDet = GetDetectorBuilderCfg(fsRefDet);
if (kRawEventBuilderDetUndef != refDet) {
fpAlgo->SetReferenceDetector(refDet);
}
else {
LOG(info) << "CbmDeviceBuildDigiEvents::InitTask => Trying to change "
"reference to unsupported detector, ignored! "
<< fsRefDet;
}
/// Extract detector to add if any
for (std::vector<std::string>::iterator itStrAdd = fvsAddDet.begin();
itStrAdd != fvsAddDet.end();
++itStrAdd) {
RawEventBuilderDetector addDet = GetDetectorBuilderCfg(*itStrAdd);
if (kRawEventBuilderDetUndef != addDet) {
fpAlgo->AddDetector(addDet);
}
else {
LOG(info) << "CbmDeviceBuildDigiEvents::InitTask => Trying to add "
"unsupported detector, ignored! "
<< (*itStrAdd);
continue;
}
}
/// Extract detector to remove if any
for (std::vector<std::string>::iterator itStrRem = fvsDelDet.begin();
itStrRem != fvsDelDet.end();
++itStrRem) {
RawEventBuilderDetector remDet = GetDetectorBuilderCfg(*itStrRem);
if (kRawEventBuilderDetUndef != remDet) {
fpAlgo->RemoveDetector(remDet);
}
else {
LOG(info) << "CbmDeviceBuildDigiEvents::InitTask => Trying to remove "
"unsupported detector, ignored! "
<< (*itStrRem);
continue;
}
}
/// Extract Trigger window to add if any
for (std::vector<std::string>::iterator itStrTrigWin = fvsSetTrigWin.begin();
itStrTrigWin != fvsSetTrigWin.end();
++itStrTrigWin) {
size_t charPosDel = (*itStrTrigWin).find(',');
if (std::string::npos == charPosDel) {
LOG(info)
<< "CbmDeviceBuildDigiEvents::InitTask => "
<< "Trying to set trigger window with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found "
<< (*itStrTrigWin) << " )";
continue;
}
/// Detector Enum Tag
std::string sSelDet = (*itStrTrigWin).substr(0, charPosDel);
ECbmModuleId selDet = GetDetectorId(sSelDet);
if (ECbmModuleId::kNotExist == selDet) {
LOG(info)
<< "CbmDeviceBuildDigiEvents::InitTask => "
<< "Trying to set trigger window for unsupported detector, ignored! "
<< sSelDet;
continue;
}
/// Window beginning
charPosDel++;
std::string sNext = (*itStrTrigWin).substr(charPosDel);
charPosDel = sNext.find(',');
if (std::string::npos == charPosDel) {
LOG(info)
<< "CbmDeviceBuildDigiEvents::InitTask => "
<< "Trying to set trigger window with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found "
<< (*itStrTrigWin) << " )";
continue;
}
Double_t dWinBeg = std::stod(sNext.substr(0, charPosDel));
/// Window end
charPosDel++;
Double_t dWinEnd = std::stod(sNext.substr(charPosDel));
fpAlgo->SetTriggerWindow(selDet, dWinBeg, dWinEnd);
}
/// Extract MinNb for trigger if any
for (std::vector<std::string>::iterator itStrMinNb = fvsSetTrigMinNb.begin();
itStrMinNb != fvsSetTrigMinNb.end();
++itStrMinNb) {
size_t charPosDel = (*itStrMinNb).find(',');
if (std::string::npos == charPosDel) {
LOG(info)
<< "CbmDeviceBuildDigiEvents::InitTask => "
<< "Trying to set trigger min Nb with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,uMinNb but instead found " << (*itStrMinNb)
<< " )";
continue;
}
/// Detector Enum Tag
std::string sSelDet = (*itStrMinNb).substr(0, charPosDel);
ECbmModuleId selDet = GetDetectorId(sSelDet);
if (ECbmModuleId::kNotExist == selDet) {
LOG(info)
<< "CbmDeviceBuildDigiEvents::InitTask => "
<< "Trying to set trigger min Nb for unsupported detector, ignored! "
<< sSelDet;
continue;
}
/// Min number
charPosDel++;
UInt_t uMinNb = std::stoul((*itStrMinNb).substr(charPosDel));
fpAlgo->SetTriggerMinNumber(selDet, uMinNb);
}
/// Extract MaxNb for trigger if any
for (std::vector<std::string>::iterator itStrMaxNb = fvsSetTrigMaxNb.begin();
itStrMaxNb != fvsSetTrigMaxNb.end();
++itStrMaxNb) {
size_t charPosDel = (*itStrMaxNb).find(',');
if (std::string::npos == charPosDel) {
LOG(info)
<< "CbmDeviceBuildDigiEvents::InitTask => "
<< "Trying to set trigger Max Nb with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,uMaxNb but instead found " << (*itStrMaxNb)
<< " )";
continue;
}
/// Detector Enum Tag
std::string sSelDet = (*itStrMaxNb).substr(0, charPosDel);
ECbmModuleId selDet = GetDetectorId(sSelDet);
if (ECbmModuleId::kNotExist == selDet) {
LOG(info)
<< "CbmDeviceBuildDigiEvents::InitTask => "
<< "Trying to set trigger Max Nb for unsupported detector, ignored! "
<< sSelDet;
continue;
}
/// Max number
charPosDel++;
Int_t iMaxNb = std::stol((*itStrMaxNb).substr(charPosDel));
fpAlgo->SetTriggerMaxNumber(selDet, iMaxNb);
}
/// Extract MinLayersNb for trigger if any
for (std::vector<std::string>::iterator itStrMinLayersNb = fvsSetTrigMinLayersNb.begin();
itStrMinLayersNb != fvsSetTrigMinLayersNb.end();
++itStrMinLayersNb) {
size_t charPosDel = (*itStrMinLayersNb).find(',');
if (std::string::npos == charPosDel) {
LOG(info)
<< "CbmDeviceBuildDigiEvents::InitTask => "
<< "Trying to set trigger min layers Nb with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,uMinLayersNb but instead found " << (*itStrMinLayersNb)
<< " )";
continue;
}
/// Detector Enum Tag
std::string sSelDet = (*itStrMinLayersNb).substr(0, charPosDel);
ECbmModuleId selDet = GetDetectorId(sSelDet);
if (ECbmModuleId::kNotExist == selDet) {
LOG(info)
<< "CbmDeviceBuildDigiEvents::InitTask => "
<< "Trying to set trigger min layers Nb for unsupported detector, ignored! "
<< sSelDet;
continue;
}
/// Min number
charPosDel++;
UInt_t uMinLayersNb = std::stoul((*itStrMinLayersNb).substr(charPosDel));
fpAlgo->SetTriggerMinLayersNumber(selDet, uMinLayersNb);
}
/// Extract Histograms Max Digi limits if any
for (std::vector<std::string>::iterator itStrHistMaxDigi = fvsSetHistMaxDigiNb.begin();
itStrHistMaxDigi != fvsSetHistMaxDigiNb.end();
++itStrHistMaxDigi) {
size_t charPosDel = (*itStrHistMaxDigi).find(',');
if (std::string::npos == charPosDel) {
LOG(info)
<< "CbmDeviceBuildDigiEvents::InitTask => "
<< "Trying to set Histos max Digi nb with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,dMaxDigiNb but instead found " << (*itStrHistMaxDigi)
<< " )";
continue;
}
/// Detector Enum Tag
std::string sSelDet = (*itStrHistMaxDigi).substr(0, charPosDel);
ECbmModuleId selDet = GetDetectorId(sSelDet);
if (ECbmModuleId::kNotExist == selDet) {
LOG(info)
<< "CbmDeviceBuildDigiEvents::InitTask => "
<< "Trying to set Histos max Digi nb for unsupported detector, ignored! "
<< sSelDet;
continue;
}
/// Min number
charPosDel++;
Double_t dHistMaxDigiNb = std::stod((*itStrHistMaxDigi).substr(charPosDel));
LOG(debug) << "set Histos max Digi nb to " << dHistMaxDigiNb;
fpAlgo->SetHistogramMaxDigiNb(selDet, dHistMaxDigiNb);
}
/// FIXME: Re-enable clang formatting after formatted lines
/* clang-format on */
/// Create input vectors
fvDigiBmon = new std::vector<CbmBmonDigi>(1000000);
fvDigiSts = new std::vector<CbmStsDigi>(1000000);
fvDigiMuch = new std::vector<CbmMuchDigi>(1000000);
fvDigiTrd = new std::vector<CbmTrdDigi>(1000000);
fvDigiTof = new std::vector<CbmTofDigi>(1000000);
fvDigiRich = new std::vector<CbmRichDigi>(1000000);
fvDigiPsd = new std::vector<CbmPsdDigi>(1000000);
fCbmTsEventHeader = new CbmTsEventHeader();
/// Digis storage
fpAlgo->SetDigis(fvDigiBmon);
fpAlgo->SetDigis(fvDigiSts);
fpAlgo->SetDigis(fvDigiMuch);
fpAlgo->SetDigis(fvDigiTrd);
fpAlgo->SetDigis(fvDigiTof);
fpAlgo->SetDigis(fvDigiRich);
fpAlgo->SetDigis(fvDigiPsd);
// Mvd currently not implemented in event builder
//std::vector<CbmMvdDigi>* pMvdDigi = new std::vector<CbmMvdDigi>();
fTimeSliceMetaDataArray = new TClonesArray("TimesliceMetaData", 1);
if (NULL == fTimeSliceMetaDataArray) { throw InitTaskError("Failed creating the TS meta data TClonesarray "); }
fpAlgo->SetTimeSliceMetaDataArray(fTimeSliceMetaDataArray);
/// Now that everything is set, initialize the Algorithm
if (kFALSE == fpAlgo->InitAlgo()) { throw InitTaskError("Failed to initialize the algorithm class."); }
/// Histograms management
if (kTRUE == fbFillHistos) {
/// Comment to prevent clang format single lining
if (kFALSE == InitHistograms()) { throw InitTaskError("Failed to initialize the histograms."); }
}
}
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 CbmDeviceBuildDigiEvents::IsChannelNameAllowed(std::string channelName)
{
for (auto const& entry : fsAllowedChannels) {
std::size_t pos1 = channelName.find(entry);
if (pos1 != std::string::npos) {
const vector<std::string>::const_iterator pos =
std::find(fsAllowedChannels.begin(), fsAllowedChannels.end(), entry);
const vector<std::string>::size_type idx = pos - fsAllowedChannels.begin();
LOG(info) << "Found " << entry << " in " << channelName;
LOG(info) << "Channel name " << channelName << " found in list of allowed channel names at position " << idx;
return true;
}
}
LOG(info) << "Channel name " << channelName << " not found in list of allowed channel names.";
LOG(error) << "Stop device.";
return false;
}
RawEventBuilderDetector CbmDeviceBuildDigiEvents::GetDetectorBuilderCfg(std::string detName)
{
/// FIXME: Disable clang formatting for now as it corrupts all alignment
/* clang-format off */
RawEventBuilderDetector cfgDet = ("kBmon" == detName ? kRawEventBuilderDetBmon
: ("kSts" == detName ? kRawEventBuilderDetSts
: ("kMuch" == detName ? kRawEventBuilderDetMuch
: ("kTrd" == detName ? kRawEventBuilderDetTrd
: ("kTrd2D" == detName ? kRawEventBuilderDetTrd2D
: ("kTof" == detName ? kRawEventBuilderDetTof
: ("kRich" == detName ? kRawEventBuilderDetRich
: ("kPsd" == detName ? kRawEventBuilderDetPsd
: kRawEventBuilderDetUndef))))))));
return cfgDet;
/// FIXME: Re-enable clang formatting after formatted lines
/* clang-format on */
}
ECbmModuleId CbmDeviceBuildDigiEvents::GetDetectorId(std::string detName)
{
/// FIXME: Disable clang formatting for now as it corrupts all alignment
/* clang-format off */
ECbmModuleId detId = ("kBmon" == detName ? ECbmModuleId::kBmon
: ("kSts" == detName ? ECbmModuleId::kSts
: ("kMuch" == detName ? ECbmModuleId::kMuch
: ("kTrd" == detName ? ECbmModuleId::kTrd
: ("kTrd2D" == detName ? ECbmModuleId::kTrd2d
: ("kTof" == detName ? ECbmModuleId::kTof
: ("kRich" == detName ? ECbmModuleId::kRich
: ("kPsd" == detName ? ECbmModuleId::kPsd
: ECbmModuleId::kNotExist))))))));
return detId;
/// FIXME: Re-enable clang formatting after formatted lines
/* clang-format on */
}
bool CbmDeviceBuildDigiEvents::InitHistograms()
{
bool initOK = true;
/// 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);
LOG(info) << "Config of hist " << psHistoConfig.first.data() << " in folder " << psHistoConfig.second.data();
} // for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto )
/// Create canvas config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Canvas name, config >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv) {
// LOG(info) << "Registering " << vCanvases[ uCanv ].first->GetName()
// << " in " << vCanvases[ uCanv ].second.data();
std::string sCanvName = (vCanvases[uCanv].first)->GetName();
std::string sCanvConf = GenerateCanvasConfigString(vCanvases[uCanv].first);
std::pair<std::string, std::string> psCanvConfig(sCanvName, sCanvConf);
fvpsCanvasConfig.push_back(psCanvConfig);
LOG(info) << "Config string of Canvas " << psCanvConfig.first.data() << " is " << psCanvConfig.second.data();
} // for( UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv )
return initOK;
}
// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
bool CbmDeviceBuildDigiEvents::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 header
// Deserialize<RootSerializer>(*parts.At(uPartIdx), fCbmTsEventHeader);
RootSerializer().Deserialize(*parts.At(uPartIdx), fCbmTsEventHeader);
++uPartIdx;
/// Bmon
if (0 < (parts.At(uPartIdx))->GetSize()) {
std::string msgStrBmon(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issBmon(msgStrBmon);
boost::archive::binary_iarchive inputArchiveBmon(issBmon);
inputArchiveBmon >> *fvDigiBmon;
}
++uPartIdx;
/// STS
if (0 < (parts.At(uPartIdx))->GetSize()) {
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
if (0 < (parts.At(uPartIdx))->GetSize()) {
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
if (0 < (parts.At(uPartIdx))->GetSize()) {
std::string msgStrTrd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTrd(msgStrTrd);
boost::archive::binary_iarchive inputArchiveTrd(issTrd);
inputArchiveTrd >> *fvDigiTrd;
}
++uPartIdx;
/// BmonF
if (0 < (parts.At(uPartIdx))->GetSize()) {
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
if (0 < (parts.At(uPartIdx))->GetSize()) {
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
if (0 < (parts.At(uPartIdx))->GetSize()) {
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;
/// TS metadata
// Deserialize<RootSerializer>(*parts.At(uPartIdx), fTsMetaData);
RootSerializer().Deserialize(*parts.At(uPartIdx), fTsMetaData);
new ((*fTimeSliceMetaDataArray)[fTimeSliceMetaDataArray->GetEntriesFast()])
TimesliceMetaData(std::move(*fTsMetaData));
++uPartIdx;
LOG(debug) << "Bmon Vector size: " << fvDigiBmon->size();
LOG(debug) << "STS Vector size: " << fvDigiSts->size();
LOG(debug) << "MUCH Vector size: " << fvDigiMuch->size();
LOG(debug) << "TRD Vector size: " << fvDigiTrd->size();
LOG(debug) << "TOF Vector size: " << fvDigiTof->size();
LOG(debug) << "RICH Vector size: " << fvDigiRich->size();
LOG(debug) << "PSD Vector size: " << fvDigiPsd->size();
if (1 == fulNumMessages) {
/// First message received
fpAlgo->SetTsParameters(0, fTsMetaData->GetDuration(), fTsMetaData->GetOverlapDuration());
}
/// Call Algo ProcessTs method
fpAlgo->ProcessTs();
/// Send events vector to ouput
if (!fbDoNotSend) {
if (fbDigiEventOutput) {
if (!(SendDigiEvents(parts))) return false;
}
else {
if (!(SendEvents(parts))) return false;
}
}
/// Clear metadata
fTimeSliceMetaDataArray->Clear();
/// Clear vectors
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
fvDigiTof->clear();
fvDigiRich->clear();
fvDigiPsd->clear();
/// Clear event vector after usage
fpAlgo->ClearEventVector();
/// 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())) {
if (!fbConfigSent) {
// Send the configuration only once per run!
fbConfigSent = SendHistoConfAndData();
} // if( !fbConfigSent )
else
SendHistograms();
fLastPublishTime = std::chrono::system_clock::now();
} // if( ( fdMaxPublishTime < elapsedSeconds.count() ) || ( 0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count() ) )
}
return true;
}
bool CbmDeviceBuildDigiEvents::SendEvents(FairMQParts& partsIn)
{
/// Get vector reference from algo
std::vector<CbmEvent*> vEvents = fpAlgo->GetEventVector();
/// Move CbmEvent from temporary vector to std::vector of full objects
LOG(debug) << "Vector size: " << vEvents.size();
std::vector<CbmEvent> vOutEvents;
for (CbmEvent* event : vEvents) {
LOG(debug) << "Vector ptr: " << event->ToString();
vOutEvents.push_back(std::move(*event));
LOG(debug) << "Vector obj: " << vOutEvents[(vOutEvents.size()) - 1].ToString();
}
/// Serialize the array of events into a single MQ message
/// FIXME: Find out if possible to use only the boost serializer
FairMQMessagePtr message(NewMessage());
// Serialize<RootSerializer>(*message, &(vOutEvents));
RootSerializer().Serialize(*message, &(vOutEvents));
/*
std::stringstream ossEvt;
boost::archive::binary_oarchive oaEvt(ossEvt);
oaEvt << vOutEvents;
std::string* strMsgEvt = new std::string(ossEvt.str());
*/
/// Add it at the end of the input composed message
/// FIXME: Find out if possible to use only the boost serializer
FairMQParts partsOut(std::move(partsIn));
partsOut.AddPart(std::move(message));
/*
partsOut.AddPart(NewMessage(
const_cast<char*>(strMsgEvt->c_str()), // data
strMsgEvt->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgEvt)); // object that manages the data
*/
if (Send(partsOut, fsChannelNameDataOutput) < 0) {
LOG(error) << "Problem sending data to " << fsChannelNameDataOutput;
return false;
}
vOutEvents.clear();
return true;
}
bool CbmDeviceBuildDigiEvents::SendDigiEvents(FairMQParts& partsIn)
{
/// Get vector reference from algo
std::vector<CbmEvent*> vEvents = fpAlgo->GetEventVector();
/// Move CbmEvent from temporary vector to std::vector of full objects
LOG(debug) << "In Vector size: " << vEvents.size();
std::vector<CbmDigiEvent> vOutEvents;
vOutEvents.reserve(vEvents.size());
for (CbmEvent* event : vEvents) {
CbmDigiEvent selEvent;
selEvent.fTime = event->GetStartTime();
selEvent.fNumber = event->GetNumber();
/// FIXME: for pure digi based event, we select "continuous slices of digis"
/// => Copy block of [First Digi index, last digi index] with assign(it_start, it_stop)
/// FIXME: Keep TRD1D + TRD2D support, may lead to holes in the digi sequence!
/// => Would need to keep the loop
/// Get the proper order for block selection as TRD1D and TRD2D may insert indices in separate loops
/// => Needed to ensure that the start and stop of the block copy do not trigger a vector size exception
event->SortIndices();
/// for each detector, find the data in the Digi vectors and copy them
/// TODO: Template + loop on list of data types?
/// ==> Bmon
uint32_t uNbDigis =
(0 < event->GetNofData(ECbmDataType::kBmonDigi) ? event->GetNofData(ECbmDataType::kBmonDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiBmon->begin() + event->GetIndex(ECbmDataType::kBmonDigi, 0);
auto stopIt = fvDigiBmon->begin() + event->GetIndex(ECbmDataType::kBmonDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fBmon.fDigis.assign(startIt, stopIt);
}
/// ==> STS
uNbDigis = (0 < event->GetNofData(ECbmDataType::kStsDigi) ? event->GetNofData(ECbmDataType::kStsDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiSts->begin() + event->GetIndex(ECbmDataType::kStsDigi, 0);
auto stopIt = fvDigiSts->begin() + event->GetIndex(ECbmDataType::kStsDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fSts.fDigis.assign(startIt, stopIt);
}
/// ==> MUCH
uNbDigis = (0 < event->GetNofData(ECbmDataType::kMuchDigi) ? event->GetNofData(ECbmDataType::kMuchDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiMuch->begin() + event->GetIndex(ECbmDataType::kMuchDigi, 0);
auto stopIt = fvDigiMuch->begin() + event->GetIndex(ECbmDataType::kMuchDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fMuch.fDigis.assign(startIt, stopIt);
}
/// ==> TRD + TRD2D
uNbDigis = (0 < event->GetNofData(ECbmDataType::kTrdDigi) ? event->GetNofData(ECbmDataType::kTrdDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiTrd->begin() + event->GetIndex(ECbmDataType::kTrdDigi, 0);
auto stopIt = fvDigiTrd->begin() + event->GetIndex(ECbmDataType::kTrdDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fTrd.fDigis.assign(startIt, stopIt);
}
/// ==> TOF
uNbDigis = (0 < event->GetNofData(ECbmDataType::kTofDigi) ? event->GetNofData(ECbmDataType::kTofDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiTof->begin() + event->GetIndex(ECbmDataType::kTofDigi, 0);
auto stopIt = fvDigiTof->begin() + event->GetIndex(ECbmDataType::kTofDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fTof.fDigis.assign(startIt, stopIt);
}
/// ==> RICH
uNbDigis = (0 < event->GetNofData(ECbmDataType::kRichDigi) ? event->GetNofData(ECbmDataType::kRichDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiRich->begin() + event->GetIndex(ECbmDataType::kRichDigi, 0);
auto stopIt = fvDigiRich->begin() + event->GetIndex(ECbmDataType::kRichDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fRich.fDigis.assign(startIt, stopIt);
}
/// ==> PSD
uNbDigis = (0 < event->GetNofData(ECbmDataType::kPsdDigi) ? event->GetNofData(ECbmDataType::kPsdDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiPsd->begin() + event->GetIndex(ECbmDataType::kPsdDigi, 0);
auto stopIt = fvDigiPsd->begin() + event->GetIndex(ECbmDataType::kPsdDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fPsd.fDigis.assign(startIt, stopIt);
}
vOutEvents.push_back(std::move(selEvent));
}
LOG(debug) << "Out Vector size: " << vEvents.size();
/// Serialize the array of events into a single MQ message
std::stringstream ossEvt;
boost::archive::binary_oarchive oaEvt(ossEvt);
oaEvt << vOutEvents;
std::string* strMsgEvt = new std::string(ossEvt.str());
FairMQMessagePtr message(NewMessage(
const_cast<char*>(strMsgEvt->c_str()), // data
strMsgEvt->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgEvt)); // object that manages the data
LOG(debug) << "Serializing done";
/// Make a new composed messaged with TsHeader + vector of Digi Event + TsMetaData
/// FIXME: Find out if possible to use only the boost serializer
FairMQParts partsOut;
partsOut.AddPart(std::move(partsIn.At(0))); // TsHeader
partsOut.AddPart(std::move(partsIn.At(partsIn.Size() - 1))); // TsMetaData
partsOut.AddPart(std::move(message)); // DigiEvent vector
LOG(debug) << "Message preparation done";
if (Send(partsOut, fsChannelNameDataOutput) < 0) {
LOG(error) << "Problem sending data to " << fsChannelNameDataOutput;
return false;
}
vOutEvents.clear();
return true;
}
bool CbmDeviceBuildDigiEvents::SendHistoConfAndData()
{
/// Prepare multiparts message and header
std::pair<uint32_t, uint32_t> pairHeader(fvpsHistosFolder.size(), fvpsCanvasConfig.size());
FairMQMessagePtr messageHeader(NewMessage());
// Serialize<BoostSerializer<std::pair<uint32_t, uint32_t>>>(*messageHeader, pairHeader);
BoostSerializer<std::pair<uint32_t, uint32_t>>().Serialize(*messageHeader, pairHeader);
FairMQParts partsOut;
partsOut.AddPart(std::move(messageHeader));
for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto) {
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, fvpsHistosFolder[uHisto]);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist, fvpsHistosFolder[uHisto]);
partsOut.AddPart(std::move(messageHist));
} // for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto)
/// Catch case where no histos are registered!
/// => Add empty message
if (0 == fvpsHistosFolder.size()) {
FairMQMessagePtr messageHist(NewMessage());
partsOut.AddPart(std::move(messageHist));
}
for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv) {
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, fvpsCanvasConfig[uCanv]);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageCan, fvpsCanvasConfig[uCanv]);
partsOut.AddPart(std::move(messageCan));
} // for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv)
/// Catch case where no Canvases are registered!
/// => Add empty message
if (0 == fvpsCanvasConfig.size()) {
FairMQMessagePtr messageHist(NewMessage());
partsOut.AddPart(std::move(messageHist));
}
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr msgHistos(NewMessage());
// Serialize<RootSerializer>(*msgHistos, &fArrayHisto);
RootSerializer().Serialize(*msgHistos, &fArrayHisto);
partsOut.AddPart(std::move(msgHistos));
/// Send the multi-parts message to the common histogram messages queue
if (Send(partsOut, fsChannelNameHistosInput) < 0) {
LOG(error) << "CbmTsConsumerReqDevExample::SendHistoConfAndData => Problem sending data";
return false;
} // if( Send( partsOut, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
fpAlgo->ResetHistograms(kFALSE);
return true;
}
bool CbmDeviceBuildDigiEvents::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
// Serialize<RootSerializer>(*message, &fArrayHisto);
RootSerializer().Serialize(*message, &fArrayHisto);
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
LOG(error) << "Problem sending data";
return false;
} // if( Send( message, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
fpAlgo->ResetHistograms(kFALSE);
return true;
}
CbmDeviceBuildDigiEvents::~CbmDeviceBuildDigiEvents()
{
/// Clear metadata
if (fCbmTsEventHeader) delete fCbmTsEventHeader;
/// Clear vectors
if (fvDigiBmon) fvDigiBmon->clear();
if (fvDigiSts) fvDigiSts->clear();
if (fvDigiMuch) fvDigiMuch->clear();
if (fvDigiTrd) fvDigiTrd->clear();
if (fvDigiTof) fvDigiTof->clear();
if (fvDigiRich) fvDigiRich->clear();
if (fvDigiPsd) fvDigiPsd->clear();
/// Clear metadata
if (fTimeSliceMetaDataArray) {
fTimeSliceMetaDataArray->Clear();
delete fTsMetaData;
delete fTimeSliceMetaDataArray;
}
if (fpAlgo) delete fpAlgo;
}
void CbmDeviceBuildDigiEvents::Finish() {}
/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau[committer] */
/**
* CbmDeviceBuildRawEvents.h
*
* @since 2021-11-18
* @author P.-A. Loizeau
*/
#ifndef CBMDEVICEBUILDDIGIEVENTS_H_
#define CBMDEVICEBUILDDIGIEVENTS_H_
/// CBM headers
#include "CbmAlgoBuildRawEvents.h"
#include "CbmBmonDigi.h"
#include "CbmMuchDigi.h"
#include "CbmPsdDigi.h"
#include "CbmRichDigi.h"
#include "CbmStsDigi.h"
#include "CbmTofDigi.h"
#include "CbmTrdDigi.h"
/// FAIRROOT headers
#include "FairMQDevice.h"
/// FAIRSOFT headers (geant, boost, ...)
#include "Rtypes.h"
#include "TObjArray.h"
/// C/C++ headers
#include <chrono>
#include <map>
#include <vector>
class TList;
class TClonesArray;
class FairRunOnline;
class CbmTsEventHeader;
class CbmDeviceBuildDigiEvents : public FairMQDevice {
public:
CbmDeviceBuildDigiEvents();
virtual ~CbmDeviceBuildDigiEvents();
protected:
virtual void InitTask();
bool HandleData(FairMQParts&, int);
bool HandleCommand(FairMQMessagePtr&, int);
private:
/// Constants
/// Control flags
Bool_t fbIgnoreTsOverlap = kFALSE; //! Ignore data in Overlap part of the TS
Bool_t fbFillHistos = kTRUE; //! Switch ON/OFF filling of histograms
/// User settings parameters
/// Algo enum settings
std::string fsEvtOverMode = "NoOverlap";
std::string fsRefDet = "kBmon";
std::vector<std::string> fvsAddDet = {};
std::vector<std::string> fvsDelDet = {};
std::vector<std::string> fvsSetTrigWin = {};
std::vector<std::string> fvsSetTrigMinNb = {};
std::vector<std::string> fvsSetTrigMaxNb = {};
std::vector<std::string> fvsSetTrigMinLayersNb = {};
std::vector<std::string> fvsSetHistMaxDigiNb = {};
/// I/O control
bool fbDoNotSend = false;
bool fbDigiEventOutput = false;
/// message queues
std::string fsChannelNameDataInput = "unpts_0";
std::string fsChannelNameDataOutput = "events";
std::string fsChannelNameCommands = "commands";
std::string fsChannelNameHistosInput = "histogram-in";
/// Histograms management
uint32_t fuPublishFreqTs = 100;
double_t fdMinPublishTime = 0.5;
double_t fdMaxPublishTime = 5.0;
/// List of MQ channels names
std::vector<std::string> fsAllowedChannels = {fsChannelNameDataInput};
/// Statistics & first TS rejection
uint64_t fulNumMessages = 0;
uint64_t fulTsCounter = 0;
std::chrono::system_clock::time_point fLastPublishTime = std::chrono::system_clock::now();
/// Processing algos
CbmAlgoBuildRawEvents* fpAlgo = nullptr;
/// TS MetaData stable values storage
size_t fuNbCoreMsPerTs = 0; //!
size_t fuNbOverMsPerTs = 0; //!
Double_t fdMsSizeInNs = 1280000; //! Size of a single MS, [nanoseconds]
Double_t fdTsCoreSizeInNs = -1.0; //! Total size of the core MS in a TS, [nanoseconds]
Double_t fdTsOverSizeInNs = -1.0; //! Total size of the overlap MS in a TS, [nanoseconds]
Double_t fdTsFullSizeInNs = -1.0; //! Total size of all MS in a TS, [nanoseconds]
/// Data reception
/// TS information in header
CbmTsEventHeader* fCbmTsEventHeader = nullptr;
/// Digis storage
std::vector<CbmBmonDigi>* fvDigiBmon = nullptr;
std::vector<CbmStsDigi>* fvDigiSts = nullptr;
std::vector<CbmMuchDigi>* fvDigiMuch = nullptr;
std::vector<CbmTrdDigi>* fvDigiTrd = nullptr;
std::vector<CbmTofDigi>* fvDigiTof = nullptr;
std::vector<CbmRichDigi>* fvDigiRich = nullptr;
std::vector<CbmPsdDigi>* fvDigiPsd = nullptr;
/// TS MetaData storage
TClonesArray* fTimeSliceMetaDataArray = nullptr; //!
TimesliceMetaData* fTsMetaData = nullptr;
/// Array of histograms to send to the histogram server
TObjArray fArrayHisto = {};
/// Vector of string pairs with ( HistoName, FolderPath ) to send to the histogram server
std::vector<std::pair<std::string, std::string>> fvpsHistosFolder = {};
/// Vector of string pairs with ( CanvasName, CanvasConfig ) to send to the histogram server
/// Format of Can config is "NbPadX(U);NbPadY(U);ConfigPad1(s);....;ConfigPadXY(s)"
/// Format of Pad config is "GrixX(b),GridY(b),LogX(b),LogY(b),LogZ(b),HistoName(s),DrawOptions(s)"
std::vector<std::pair<std::string, std::string>> fvpsCanvasConfig = {};
/// Flag indicating whether the histograms and canvases configurations were already published
bool fbConfigSent = false;
/// Check wether an MQ channel name is among those expected for this device
bool IsChannelNameAllowed(std::string channelName);
/// Get detector event builder config from string containing name
RawEventBuilderDetector GetDetectorBuilderCfg(std::string detName);
/// Get detector type from string containing name
ECbmModuleId GetDetectorId(std::string detName);
bool InitHistograms();
void Finish();
bool SendEvents(FairMQParts& partsIn);
bool SendDigiEvents(FairMQParts& partsIn);
bool SendHistoConfAndData();
bool SendHistograms();
};
#endif /* CBMDEVICEBUILDDIGIEVENTS_H_ */
......@@ -111,9 +111,9 @@ try {
: EOverlapModeRaw::NoOverlap)));
fpAlgo->SetEventOverlapMode(mode);
/// Extract refdet
RawEventBuilderDetector refDet = ("kT0" == fsRefDet ? kRawEventBuilderDetT0
: ("kSts" == fsRefDet ? kRawEventBuilderDetMuch
: ("kMuch" == fsRefDet ? kRawEventBuilderDetTrd
RawEventBuilderDetector refDet = ("kBmon" == fsRefDet ? kRawEventBuilderDetBmon
: ("kSts" == fsRefDet ? kRawEventBuilderDetSts
: ("kMuch" == fsRefDet ? kRawEventBuilderDetMuch
: ("kTrd" == fsRefDet ? kRawEventBuilderDetTrd
: ("kTof" == fsRefDet ? kRawEventBuilderDetTof
: ("kRich" == fsRefDet ? kRawEventBuilderDetRich
......@@ -121,7 +121,7 @@ try {
: kRawEventBuilderDetUndef)))))));
if (kRawEventBuilderDetUndef != refDet) {
fpAlgo->SetReferenceDetector(refDet);
}
}
else {
LOG(info) << "CbmDeviceBuildRawEvents::InitTask => Trying to change "
"reference to unsupported detector, ignored! "
......@@ -132,7 +132,7 @@ try {
for (std::vector<std::string>::iterator itStrAdd = fvsAddDet.begin();
itStrAdd != fvsAddDet.end();
++itStrAdd) {
RawEventBuilderDetector addDet = ("kT0" == *itStrAdd ? kRawEventBuilderDetT0
RawEventBuilderDetector addDet = ("kBmon" == *itStrAdd ? kRawEventBuilderDetBmon
: ("kSts" == *itStrAdd ? kRawEventBuilderDetSts
: ("kMuch" == *itStrAdd ? kRawEventBuilderDetMuch
: ("kTrd" == *itStrAdd ? kRawEventBuilderDetTrd
......@@ -142,20 +142,20 @@ try {
: kRawEventBuilderDetUndef)))))));
if (kRawEventBuilderDetUndef != addDet) {
fpAlgo->AddDetector(addDet);
}
}
else {
LOG(info) << "CbmDeviceBuildRawEvents::InitTask => Trying to add "
"unsupported detector, ignored! "
<< (*itStrAdd);
continue;
}
}
}
/// Extract detector to remove if any
for (std::vector<std::string>::iterator itStrRem = fvsDelDet.begin();
itStrRem != fvsDelDet.end();
++itStrRem) {
RawEventBuilderDetector remDet = ("kT0" == *itStrRem ? kRawEventBuilderDetT0
RawEventBuilderDetector remDet = ("kBmon" == *itStrRem ? kRawEventBuilderDetBmon
: ("kSts" == *itStrRem ? kRawEventBuilderDetSts
: ("kMuch" == *itStrRem ? kRawEventBuilderDetMuch
: ("kTrd" == *itStrRem ? kRawEventBuilderDetTrd
......@@ -165,14 +165,14 @@ try {
: kRawEventBuilderDetUndef)))))));
if (kRawEventBuilderDetUndef != remDet) {
fpAlgo->RemoveDetector(remDet);
}
}
else {
LOG(info) << "CbmDeviceBuildRawEvents::InitTask => Trying to remove "
"unsupported detector, ignored! "
<< (*itStrRem);
continue;
}
}
}
}
/// Extract Trigger window to add if any
for (std::vector<std::string>::iterator itStrTrigWin = fvsSetTrigWin.begin();
itStrTrigWin != fvsSetTrigWin.end();
......@@ -185,11 +185,11 @@ try {
<< " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found "
<< (*itStrTrigWin) << " )";
continue;
}
}
/// Detector Enum Tag
std::string sSelDet = (*itStrTrigWin).substr(0, charPosDel);
ECbmModuleId selDet = ("kT0" == sSelDet ? ECbmModuleId::kT0
ECbmModuleId selDet = ("kBmon" == sSelDet ? ECbmModuleId::kBmon
: ("kSts" == sSelDet ? ECbmModuleId::kSts
: ("kMuch" == sSelDet ? ECbmModuleId::kMuch
: ("kTrd" == sSelDet ? ECbmModuleId::kTrd
......@@ -203,7 +203,7 @@ try {
<< "Trying to set trigger window for unsupported detector, ignored! "
<< sSelDet;
continue;
}
}
/// Window beginning
charPosDel++;
......@@ -216,7 +216,7 @@ try {
<< " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found "
<< (*itStrTrigWin) << " )";
continue;
}
}
Double_t dWinBeg = std::stod(sNext.substr(0, charPosDel));
/// Window end
......@@ -224,7 +224,7 @@ try {
Double_t dWinEnd = std::stod(sNext.substr(charPosDel));
fpAlgo->SetTriggerWindow(selDet, dWinBeg, dWinEnd);
}
}
/// Extract MinNb for trigger if any
for (std::vector<std::string>::iterator itStrMinNb = fvsSetTrigMinNb.begin();
itStrMinNb != fvsSetTrigMinNb.end();
......@@ -241,7 +241,7 @@ try {
/// Detector Enum Tag
std::string sSelDet = (*itStrMinNb).substr(0, charPosDel);
ECbmModuleId selDet = ("kT0" == sSelDet ? ECbmModuleId::kT0
ECbmModuleId selDet = ("kBmon" == sSelDet ? ECbmModuleId::kBmon
: ("kSts" == sSelDet ? ECbmModuleId::kSts
: ("kMuch" == sSelDet ? ECbmModuleId::kMuch
: ("kTrd" == sSelDet ? ECbmModuleId::kTrd
......@@ -262,13 +262,13 @@ try {
UInt_t uMinNb = std::stoul((*itStrMinNb).substr(charPosDel));
fpAlgo->SetTriggerMinNumber(selDet, uMinNb);
}
}
/// FIXME: Re-enable clang formatting after formatted lines
/* clang-format on */
/// Create input vectors
fvDigiT0 = new std::vector<CbmTofDigi>();
fvDigiBmon = new std::vector<CbmBmonDigi>();
fvDigiSts = new std::vector<CbmStsDigi>();
fvDigiMuch = new std::vector<CbmMuchBeamTimeDigi>();
fvDigiTrd = new std::vector<CbmTrdDigi>();
......@@ -281,13 +281,13 @@ try {
fpAlgo->SetTimeSliceMetaDataArray(fTimeSliceMetaDataArray);
/// Digis storage
fpAlgo->SetT0Digis(fvDigiT0);
fpAlgo->SetStsDigis(fvDigiSts);
fpAlgo->SetMuchBeamTimeDigis(fvDigiMuch);
fpAlgo->SetTrdDigis(fvDigiTrd);
fpAlgo->SetTofDigis(fvDigiTof);
fpAlgo->SetRichDigis(fvDigiRich);
fpAlgo->SetPsdDigis(fvDigiPsd);
fpAlgo->SetDigis(fvDigiBmon);
fpAlgo->SetDigis(fvDigiSts);
fpAlgo->SetDigis(fvDigiMuch);
fpAlgo->SetDigis(fvDigiTrd);
fpAlgo->SetDigis(fvDigiTof);
fpAlgo->SetDigis(fvDigiRich);
fpAlgo->SetDigis(fvDigiPsd);
// Mvd currently not implemented in event builder
//std::vector<CbmMvdDigi>* pMvdDigi = new std::vector<CbmMvdDigi>();
......@@ -319,7 +319,8 @@ try {
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist(NewMessage());
Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, psHistoConfig);
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, psHistoConfig);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist, psHistoConfig);
/// Send message to the common histogram config messages queue
if (Send(messageHist, fsChannelNameHistosConfig) < 0) { throw InitTaskError("Problem sending histo config"); }
......@@ -341,7 +342,8 @@ try {
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan(NewMessage());
Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, psCanvConfig);
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, psCanvConfig);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageCan, psCanvConfig);
/// Send message to the common canvas config messages queue
if (Send(messageCan, fsChannelNameCanvasConfig) < 0) { throw InitTaskError("Problem sending canvas config"); }
......@@ -387,16 +389,17 @@ bool CbmDeviceBuildRawEvents::HandleData(FairMQParts& parts, int /*index*/)
uint32_t uPartIdx = 0;
/// TS metadata
Deserialize<RootSerializer>(*parts.At(uPartIdx), fTsMetaData);
// Deserialize<RootSerializer>(*parts.At(uPartIdx), fTsMetaData);
RootSerializer().Deserialize(*parts.At(uPartIdx), fTsMetaData);
new ((*fTimeSliceMetaDataArray)[fTimeSliceMetaDataArray->GetEntriesFast()])
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;
/// Bmon
std::string msgStrBmon(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issBmon(msgStrBmon);
boost::archive::binary_iarchive inputArchiveBmon(issBmon);
inputArchiveBmon >> *fvDigiBmon;
++uPartIdx;
/// STS
......@@ -420,7 +423,7 @@ bool CbmDeviceBuildRawEvents::HandleData(FairMQParts& parts, int /*index*/)
inputArchiveTrd >> *fvDigiTrd;
++uPartIdx;
/// T0F
/// BmonF
std::string msgStrTof(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTof(msgStrTof);
boost::archive::binary_iarchive inputArchiveTof(issTof);
......@@ -451,7 +454,7 @@ bool CbmDeviceBuildRawEvents::HandleData(FairMQParts& parts, int /*index*/)
fTimeSliceMetaDataArray->Clear();
/// Clear vectors
fvDigiT0->clear();
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
......@@ -497,7 +500,8 @@ bool CbmDeviceBuildRawEvents::SendEvents(FairMQParts& partsIn)
/// Serialize the array of events into a single MQ message
FairMQMessagePtr message(NewMessage());
Serialize<RootSerializer>(*message, fEvents);
// Serialize<RootSerializer>(*message, fEvents);
RootSerializer().Serialize(*message, fEvents);
/// Add it at the end of the input composed message
FairMQParts partsOut(std::move(partsIn));
......@@ -515,7 +519,8 @@ bool CbmDeviceBuildRawEvents::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
Serialize<RootSerializer>(*message, &fArrayHisto);
// Serialize<RootSerializer>(*message, &fArrayHisto);
RootSerializer().Serialize(*message, &fArrayHisto);
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
......@@ -536,7 +541,7 @@ CbmDeviceBuildRawEvents::~CbmDeviceBuildRawEvents()
delete fTsMetaData;
/// Clear vectors
fvDigiT0->clear();
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
......
......@@ -14,6 +14,7 @@
/// CBM headers
#include "CbmAlgoBuildRawEvents.h"
#include "CbmBmonDigi.h"
#include "CbmMuchBeamTimeDigi.h"
#include "CbmPsdDigi.h"
#include "CbmRichDigi.h"
......@@ -26,7 +27,6 @@
/// FAIRSOFT headers (geant, boost, ...)
#include "Rtypes.h"
#include "TMessage.h"
#include "TObjArray.h"
/// C/C++ headers
......@@ -59,7 +59,7 @@ private:
/// User settings parameters
/// Algo enum settings
std::string fsEvtOverMode = "NoOverlap";
std::string fsRefDet = "kT0";
std::string fsRefDet = "kBmon";
std::vector<std::string> fvsAddDet = {};
std::vector<std::string> fvsDelDet = {};
std::vector<std::string> fvsSetTrigWin = {};
......@@ -100,7 +100,7 @@ private:
TClonesArray* fTimeSliceMetaDataArray = nullptr; //!
TimesliceMetaData* fTsMetaData = nullptr;
/// Digis storage
std::vector<CbmTofDigi>* fvDigiT0 = nullptr;
std::vector<CbmBmonDigi>* fvDigiBmon = nullptr;
std::vector<CbmStsDigi>* fvDigiSts = nullptr;
std::vector<CbmMuchBeamTimeDigi>* fvDigiMuch = nullptr;
std::vector<CbmTrdDigi>* fvDigiTrd = nullptr;
......@@ -129,11 +129,4 @@ private:
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 /* CBMDEVICEBUILDRAWEVENTS_H_ */
/* Copyright (C) 2020-2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceDigiEventSink.cxx
*
* @since 2020-05-24
* @author P.-A. Loizeau
*/
#include "CbmDeviceDigiEventSink.h"
/// CBM headers
#include "CbmEvent.h"
#include "CbmFlesCanvasTools.h"
#include "CbmMQDefs.h"
#include "TimesliceMetaData.h"
/// FAIRROOT headers
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairParGenericSet.h"
#include "FairRootFileSink.h"
#include "FairRootManager.h"
#include "FairRunOnline.h"
#include "FairSource.h"
#include "BoostSerializer.h"
#include "RootSerializer.h"
/// FAIRSOFT headers (geant, boost, ...)
#include "TCanvas.h"
#include "TFile.h"
#include "TH1.h"
#include "TList.h"
#include "TNamed.h"
#include "TProfile.h"
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/utility.hpp>
/// C/C++ headers
#include <array>
#include <iomanip>
#include <stdexcept>
#include <string>
#include <thread> // this_thread::sleep_for
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
using namespace std;
//Bool_t bMcbm2018MonitorTaskBmonResetHistos = kFALSE;
CbmDeviceDigiEventSink::CbmDeviceDigiEventSink() {}
void CbmDeviceDigiEventSink::InitTask()
try {
/// Read options from executable
LOG(info) << "Init options for CbmDeviceDigiEventSink.";
fbStoreFullTs = fConfig->GetValue<bool>("StoreFullTs");
fsOutputFileName = fConfig->GetValue<std::string>("OutFileName");
fsChannelNameDataInput = fConfig->GetValue<std::string>("EvtNameIn");
fsAllowedChannels[0] = fsChannelNameDataInput;
fbBypassConsecutiveTs = fConfig->GetValue<bool>("BypassConsecutiveTs");
fbWriteMissingTs = fConfig->GetValue<bool>("WriteMissingTs");
fbDisableCompression = fConfig->GetValue<bool>("DisableCompression");
fiTreeFileMaxSize = fConfig->GetValue<int64_t>("TreeFileMaxSize");
fbDigiEventInput = fConfig->GetValue<bool>("DigiEventInput");
fbExclusiveTrdExtract = fConfig->GetValue<bool>("ExclusiveTrdExtract");
fbFillHistos = fConfig->GetValue<bool>("FillHistos");
fuPublishFreqTs = fConfig->GetValue<uint32_t>("PubFreqTs");
fdMinPublishTime = fConfig->GetValue<double_t>("PubTimeMin");
fdMaxPublishTime = fConfig->GetValue<double_t>("PubTimeMax");
fsHistosSuffix = fConfig->GetValue<std::string>("HistosSuffix");
fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
/// Associate the MissedTs Channel to the corresponding handler
OnData(fsChannelNameMissedTs, &CbmDeviceDigiEventSink::HandleMissTsData);
/// Associate the command Channel to the corresponding handler
OnData(fsChannelNameCommands, &CbmDeviceDigiEventSink::HandleCommand);
/// Associate the Event + Unp data Channel to the corresponding handler
// Get the information about created channels from the device
// Check if the defined channels from the topology (by name)
// are in the list of channels which are possible/allowed
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
//logger::SetLogLevel("INFO");
int noChannel = fChannels.size();
LOG(info) << "Number of defined channels: " << noChannel;
for (auto const& entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
if (std::string::npos != entry.first.find(fsChannelNameDataInput)) {
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
OnData(entry.first, &CbmDeviceDigiEventSink::HandleData);
} // if( entry.first.find( "ts" )
} // for( auto const &entry : fChannels )
// InitContainers();
/// Prepare storage TClonesArrays
/// TS MetaData storage
fTimeSliceMetaDataArray = new TClonesArray("TimesliceMetaData", 1);
if (NULL == fTimeSliceMetaDataArray) {
throw InitTaskError("Failed creating the TS meta data TClonesarray ");
} // if( NULL == fTimeSliceMetaDataArray )
/// Events storage
/// TODO: remove TObject from CbmEvent and switch to vectors!
fEventsSel = new std::vector<CbmDigiEvent>();
/// Prepare root output
if ("" != fsOutputFileName) {
fpRun = new FairRunOnline();
FairRootFileSink* pSink = new FairRootFileSink(fsOutputFileName);
fpFairRootMgr = FairRootManager::Instance();
fpFairRootMgr->SetSink(pSink);
if (nullptr == fpFairRootMgr->GetOutFile()) {
throw InitTaskError("Could not open root file");
} // if( nullptr == fpFairRootMgr->GetOutFile() )
if (fbDisableCompression) {
/// Completely disable the root file compression
pSink->GetRootFile()->SetCompressionLevel(0);
}
/// Set global size limit for all TTree in this process/Root instance
TTree::SetMaxTreeSize(fiTreeFileMaxSize);
} // if( "" != fsOutputFileName )
else {
throw InitTaskError("Empty output filename!");
} // else of if( "" != fsOutputFileName )
LOG(info) << "Init Root Output to " << fsOutputFileName;
fpFairRootMgr->InitSink();
fEvtHeader = new CbmTsEventHeader();
fpFairRootMgr->Register("EventHeader.", "Event", fEvtHeader, kTRUE);
/// Register all input data members with the FairRoot manager
/// TS MetaData
fpFairRootMgr->Register("TimesliceMetaData", "TS Meta Data", fTimeSliceMetaDataArray, kTRUE);
/// CbmEvent
fpFairRootMgr->RegisterAny("DigiEvent", fEventsSel, kTRUE);
/// Full TS Digis storage (optional usage, controlled by fbStoreFullTs!)
if (fbStoreFullTs) {
fvDigiBmon = new std::vector<CbmBmonDigi>();
fvDigiSts = new std::vector<CbmStsDigi>();
fvDigiMuch = new std::vector<CbmMuchDigi>();
fvDigiTrd = new std::vector<CbmTrdDigi>();
fvDigiTof = new std::vector<CbmTofDigi>();
fvDigiRich = new std::vector<CbmRichDigi>();
fvDigiPsd = new std::vector<CbmPsdDigi>();
fpFairRootMgr->RegisterAny(CbmBmonDigi::GetBranchName(), fvDigiBmon, kTRUE);
fpFairRootMgr->RegisterAny(CbmStsDigi::GetBranchName(), fvDigiSts, kTRUE);
fpFairRootMgr->RegisterAny(CbmMuchDigi::GetBranchName(), fvDigiMuch, kTRUE);
fpFairRootMgr->RegisterAny(CbmTrdDigi::GetBranchName(), fvDigiTrd, kTRUE);
fpFairRootMgr->RegisterAny(CbmTofDigi::GetBranchName(), fvDigiTof, kTRUE);
fpFairRootMgr->RegisterAny(CbmRichDigi::GetBranchName(), fvDigiRich, kTRUE);
fpFairRootMgr->RegisterAny(CbmPsdDigi::GetBranchName(), fvDigiPsd, kTRUE);
}
fpFairRootMgr->WriteFolder();
LOG(info) << "Initialized outTree with rootMgr at " << fpFairRootMgr;
/// Histograms management
if (kTRUE == fbFillHistos) {
/// Comment to prevent clang format single lining
if (kFALSE == InitHistograms()) { throw InitTaskError("Failed to initialize the histograms."); }
} // if( kTRUE == fbFillHistos )
fbInitDone = true;
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
}
bool CbmDeviceDigiEventSink::IsChannelNameAllowed(std::string channelName)
{
for (auto const& entry : fsAllowedChannels) {
std::size_t pos1 = channelName.find(entry);
if (pos1 != std::string::npos) {
const vector<std::string>::const_iterator pos =
std::find(fsAllowedChannels.begin(), fsAllowedChannels.end(), entry);
const vector<std::string>::size_type idx = pos - fsAllowedChannels.begin();
LOG(info) << "Found " << entry << " in " << channelName;
LOG(info) << "Channel name " << channelName << " found in list of allowed channel names at position " << idx;
return true;
} // if (pos1!=std::string::npos)
} // for(auto const &entry : fsAllowedChannels)
LOG(info) << "Channel name " << channelName << " not found in list of allowed channel names.";
LOG(error) << "Stop device.";
return false;
}
bool CbmDeviceDigiEventSink::InitHistograms()
{
/// Histos creation and obtain pointer on them
/// Trigger histo creation, filling vHistos and vCanvases
// bool initOK =CreateHistograms();
bool initOK = true;
/// Obtain vector of pointers on each histo from the algo (+ optionally desired folder) or create them locally
// ALGO: std::vector<std::pair<TNamed*, std::string>> vHistos = fMonitorAlgo->GetHistoVector();
std::vector<std::pair<TNamed*, std::string>> vHistos = {};
/* clang-format off */
fhFullTsBuffSizeEvo = new TProfile(Form("hFullTsBuffSizeEvo%s", fsHistosSuffix.data()),
"Evo. of the full TS buffer size; Time in run [s]; Size []",
720, 0, 7200);
fhMissTsBuffSizeEvo = new TProfile(Form("hMissTsBuffSizeEvo%s", fsHistosSuffix.data()),
"Evo. of the missed TS buffer size; Time in run [s]; Size []",
720, 0, 7200);
fhFullTsProcEvo = new TH1I(Form("hFullTsProcEvo%s", fsHistosSuffix.data()),
"Processed full TS; Time in run [s]; # []",
720, 0, 7200);
fhMissTsProcEvo = new TH1I(Form("hMissTsProcEvo%s", fsHistosSuffix.data()),
"Processed missing TS; Time in run [s]; # []",
720, 0, 7200);
fhTotalTsProcEvo = new TH1I(Form("hTotalTsProcEvo%s", fsHistosSuffix.data()),
"Total processed TS; Time in run [s]; # []",
720, 0, 7200);
fhTotalEventsEvo = new TH1I(Form("hTotalEventsEvo%s", fsHistosSuffix.data()),
"Processed events; Time in run [s]; # []",
720, 0, 7200);
/* clang-format on */
std::string sFolder = std::string("EvtSink") + fsHistosSuffix;
vHistos.push_back(std::pair<TNamed*, std::string>(fhFullTsBuffSizeEvo, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhMissTsBuffSizeEvo, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhFullTsProcEvo, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhMissTsProcEvo, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhTotalTsProcEvo, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhTotalEventsEvo, sFolder));
/// Obtain vector of pointers on each canvas from the algo (+ optionally desired folder) or create them locally
// ALGO: std::vector<std::pair<TCanvas*, std::string>> vCanvases = fMonitorAlgo->GetCanvasVector();
std::vector<std::pair<TCanvas*, std::string>> vCanvases = {};
fcEventSinkAllHist = new TCanvas(Form("cEventSinkAllHist%s", fsHistosSuffix.data()), "Event Sink Monitoring");
fcEventSinkAllHist->Divide(3, 2);
fcEventSinkAllHist->cd(1);
gPad->SetGridx();
gPad->SetGridy();
fhFullTsBuffSizeEvo->Draw("hist");
fcEventSinkAllHist->cd(2);
gPad->SetGridx();
gPad->SetGridy();
fhMissTsBuffSizeEvo->Draw("hist");
fcEventSinkAllHist->cd(3);
gPad->SetGridx();
gPad->SetGridy();
fhFullTsProcEvo->Draw("hist");
fcEventSinkAllHist->cd(4);
gPad->SetGridx();
gPad->SetGridy();
fhMissTsProcEvo->Draw("hist");
fcEventSinkAllHist->cd(5);
gPad->SetGridx();
gPad->SetGridy();
fhTotalTsProcEvo->Draw("hist");
fcEventSinkAllHist->cd(6);
gPad->SetGridx();
gPad->SetGridy();
gPad->SetLogy();
fhTotalEventsEvo->Draw("hist");
vCanvases.push_back(std::pair<TCanvas*, std::string>(fcEventSinkAllHist, std::string("canvases") + fsHistosSuffix));
/// Add pointers to each histo in the histo array
/// Create histo config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Histo name, Folder >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto) {
// LOG(info) << "Registering " << vHistos[ uHisto ].first->GetName()
// << " in " << vHistos[ uHisto ].second.data()
// ;
fArrayHisto.Add(vHistos[uHisto].first);
std::pair<std::string, std::string> psHistoConfig(vHistos[uHisto].first->GetName(), vHistos[uHisto].second);
fvpsHistosFolder.push_back(psHistoConfig);
LOG(info) << "Config of hist " << psHistoConfig.first.data() << " in folder " << psHistoConfig.second.data();
} // for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto )
/// Create canvas config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Canvas name, config >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv) {
// LOG(info) << "Registering " << vCanvases[ uCanv ].first->GetName()
// << " in " << vCanvases[ uCanv ].second.data();
std::string sCanvName = (vCanvases[uCanv].first)->GetName();
std::string sCanvConf = GenerateCanvasConfigString(vCanvases[uCanv].first);
std::pair<std::string, std::string> psCanvConfig(sCanvName, sCanvConf);
fvpsCanvasConfig.push_back(psCanvConfig);
LOG(info) << "Config string of Canvas " << psCanvConfig.first.data() << " is " << psCanvConfig.second.data();
} // for( UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv )
return initOK;
}
bool CbmDeviceDigiEventSink::ResetHistograms(bool bResetStartTime)
{
fhFullTsBuffSizeEvo->Reset();
fhMissTsBuffSizeEvo->Reset();
fhFullTsProcEvo->Reset();
fhMissTsProcEvo->Reset();
fhTotalTsProcEvo->Reset();
fhTotalEventsEvo->Reset();
if (bResetStartTime) {
/// Reset the start time of the time evolution histograms
fStartTime = std::chrono::system_clock::now();
}
return true;
}
//--------------------------------------------------------------------//
// handler is called whenever a message arrives on fsChannelNameMissedTs, with a reference to the message and a sub-channel index (here 0)
bool CbmDeviceDigiEventSink::HandleMissTsData(FairMQMessagePtr& msg, int /*index*/)
{
std::vector<uint64_t> vIndices;
std::string msgStrMissTs(static_cast<char*>(msg->GetData()), msg->GetSize());
std::istringstream issMissTs(msgStrMissTs);
boost::archive::binary_iarchive inputArchiveMissTs(issMissTs);
inputArchiveMissTs >> vIndices;
fvulMissedTsIndices.insert(fvulMissedTsIndices.end(), vIndices.begin(), vIndices.end());
/// Check TS queue and process it if needed (in case it filled a hole!)
if (!fbBypassConsecutiveTs) {
/// But only if Consecutive TS check is not disabled explicitly by user
CheckTsQueues();
}
return true;
}
//--------------------------------------------------------------------//
// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
bool CbmDeviceDigiEventSink::HandleData(FairMQParts& parts, int /*index*/)
{
fulNumMessages++;
LOG(debug) << "Received message number " << fulNumMessages << " with " << parts.Size() << " parts"
<< ", size0: " << parts.At(0)->GetSize();
if (0 == fulNumMessages % 10000) LOG(info) << "Received " << fulNumMessages << " messages";
/// Unpack the message
CbmEventTimeslice unpTs(parts, fbDigiEventInput);
/// FIXME: Need to check if TS arrived in order (probably not!!!) + buffer!!!
LOG(debug) << "Next TS check " << fuPrevTsIndex << " " << fulTsCounter << " " << unpTs.fTsMetaData.GetIndex()
<< " Storage size: " << fmFullTsStorage.size();
if (fbBypassConsecutiveTs || (fuPrevTsIndex + 1 == unpTs.fTsMetaData.GetIndex())
|| (0 == fuPrevTsIndex && 0 == fulTsCounter && 0 == unpTs.fTsMetaData.GetIndex())) {
LOG(debug) << "TS direct to dump";
/// Fill all storage variables registers for data output
PrepareTreeEntry(unpTs);
/// Trigger FairRoot manager to dump Tree entry
DumpTreeEntry();
/// Update counters
fuPrevTsIndex = unpTs.fTsMetaData.GetIndex();
fulTsCounter++;
}
else {
LOG(debug) << "TS direct to storage";
/// If not consecutive to last TS sent,
fmFullTsStorage.emplace_hint(fmFullTsStorage.end(),
std::pair<uint64_t, CbmEventTimeslice>(unpTs.fTsMetaData.GetIndex(), unpTs));
}
LOG(debug) << "TS metadata checked";
/// Clear metadata => crashes, maybe not needed as due to move the pointer is invalidated?
// delete fTsMetaData;
if (fbBypassConsecutiveTs) {
/// Skip checking the TS buffer as writing straight to file
/// => Just check if we are done and can close the file or not
if (fbReceivedEof) {
/// In this case we cannot check if the last TS received/processed is the final one due to lack of order
/// => use instead the fact that we received all expected TS
if ((fulTsCounter + fvulMissedTsIndices.size()) == fuTotalTsCount) {
LOG(info) << "CbmDeviceDigiEventSink::HandleData => "
<< "Found all expected TS (" << fulTsCounter << ") and total nb of TS " << fuTotalTsCount
<< " after accounting for the ones reported as missing by the source (" << fvulMissedTsIndices.size()
<< ")";
Finish();
} // if ((fulTsCounter + fvulMissedTsIndices.size()) == fuTotalTsCount)
}
}
else {
/// Check TS queue and process it if needed (in case it filled a hole!)
CheckTsQueues();
LOG(debug) << "TS queues checked";
}
/// Histograms management
if (kTRUE == fbFillHistos) {
std::chrono::system_clock::time_point currentTime = std::chrono::system_clock::now();
/// Fill histograms every 5 or more seconds
/// TODO: make it a parameter
std::chrono::duration<double_t> elapsedSecondsFill = currentTime - fLastFillTime;
if (1.0 < elapsedSecondsFill.count()) {
std::chrono::duration<double_t> secInRun = currentTime - fStartTime;
/// Rely on the fact that all histos have same X axis to avoid multiple "current bin" search
/*
int32_t iBinIndex = fhFullTsBuffSizeEvo->FindBin(secInRun.count());
fhFullTsBuffSizeEvo->SetBinContent(iBinIndex, fmFullTsStorage.size());
fhMissTsBuffSizeEvo->SetBinContent(iBinIndex, fvulMissedTsIndices.size());
fhFullTsProcEvo->SetBinContent(iBinIndex, fulTsCounter);
fhMissTsProcEvo->SetBinContent(iBinIndex, fulMissedTsCounter);
fhTotalTsProcEvo->SetBinContent(iBinIndex, (fulTsCounter + fulMissedTsCounter));
fhTotalEventsEvo->SetBinContent(iBinIndex, fulProcessedEvents);
*/
fhFullTsBuffSizeEvo->Fill(secInRun.count(), fmFullTsStorage.size());
fhMissTsBuffSizeEvo->Fill(secInRun.count(), fvulMissedTsIndices.size());
fhFullTsProcEvo->Fill(secInRun.count(), (fulTsCounter - fulLastFullTsCounter));
fhMissTsProcEvo->Fill(secInRun.count(), (fulMissedTsCounter - fulLastMissTsCounter));
fhTotalTsProcEvo->Fill(secInRun.count(),
(fulTsCounter - fulLastFullTsCounter + fulMissedTsCounter - fulLastMissTsCounter));
fhTotalEventsEvo->Fill(secInRun.count(), fulProcessedEvents - fulLastProcessedEvents);
fLastFillTime = currentTime;
fulLastFullTsCounter = fulTsCounter;
fulLastMissTsCounter = fulMissedTsCounter;
fulLastProcessedEvents = fulProcessedEvents;
}
/// Send histograms each N timeslices.
/// Use also runtime checker to trigger sending after M s if
/// processing too slow or delay sending if processing too fast
std::chrono::duration<double_t> elapsedSeconds = currentTime - fLastPublishTime;
if ((fdMaxPublishTime < elapsedSeconds.count())
|| (0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count())) {
if (!fbConfigSent) {
// Send the configuration only once per run!
fbConfigSent = SendHistoConfAndData();
} // if( !fbConfigSent )
else
SendHistograms();
fLastPublishTime = currentTime;
} // if( ( fdMaxPublishTime < elapsedSeconds.count() ) || ( 0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count() ) )
} // if( kTRUE == fbFillHistos )
LOG(debug) << "Processed TS with saving " << (fulTsCounter + fulMissedTsCounter) << " TS (" << fulTsCounter
<< " full ones and " << fulMissedTsCounter << " missed/empty ones)";
LOG(debug) << "Buffers are " << fmFullTsStorage.size() << " full TS and " << fvulMissedTsIndices.size()
<< " missed/empty ones)";
return true;
}
//--------------------------------------------------------------------//
bool CbmDeviceDigiEventSink::HandleCommand(FairMQMessagePtr& msg, int /*index*/)
{
/*
std::string sCommand( static_cast< char * >( msg->GetData() ),
msg->GetSize() );
*/
std::string sCommand;
std::string msgStrCmd(static_cast<char*>(msg->GetData()), msg->GetSize());
std::istringstream issCmd(msgStrCmd);
boost::archive::binary_iarchive inputArchiveCmd(issCmd);
inputArchiveCmd >> sCommand;
std::string sCmdTag = sCommand;
size_t charPosDel = sCommand.find(' ');
if (std::string::npos != charPosDel) {
sCmdTag = sCommand.substr(0, charPosDel);
} // if( std::string::npos != charPosDel )
if ("EOF" == sCmdTag) {
fbReceivedEof = true;
/// Extract the last TS index and global full TS count
if (std::string::npos == charPosDel) {
LOG(fatal) << "CbmDeviceDigiEventSink::HandleCommand => "
<< "Incomplete EOF command received: " << sCommand;
return false;
} // if( std::string::npos == charPosDel )
/// Last TS index
charPosDel++;
std::string sNext = sCommand.substr(charPosDel);
charPosDel = sNext.find(' ');
if (std::string::npos == charPosDel) {
LOG(fatal) << "CbmDeviceDigiEventSink::HandleCommand => "
<< "Incomplete EOF command received: " << sCommand;
return false;
} // if( std::string::npos == charPosDel )
fuLastTsIndex = std::stoul(sNext.substr(0, charPosDel));
/// Total TS count
charPosDel++;
fuTotalTsCount = std::stoul(sNext.substr(charPosDel));
LOG(info) << "CbmDeviceDigiEventSink::HandleCommand => "
<< "Received EOF command with final TS index " << fuLastTsIndex << " and total nb TS " << fuTotalTsCount;
/// End of data: clean save of data + close file + send last state of histos if enabled
if (fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount) {
LOG(info) << "CbmDeviceDigiEventSink::HandleCommand => "
<< "Found final TS index " << fuLastTsIndex << " and total nb TS " << fuTotalTsCount;
Finish();
} // if( fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount )
} // if( "EOF" == sCmdTag )
else if ("STOP" == sCmdTag) {
/// TODO: different treatment in case of "BAD" ending compared to EOF?
/// Source failure: clean save of received data + close file + send last state of histos if enabled
Finish();
} // else if( "STOP" == sCmdTag )
else {
LOG(warning) << "Unknown command received: " << sCmdTag << " => will be ignored!";
} // else if command not recognized
return true;
}
//--------------------------------------------------------------------//
void CbmDeviceDigiEventSink::CheckTsQueues()
{
bool bHoleFoundInBothQueues = false;
std::map<uint64_t, CbmEventTimeslice>::iterator itFullTs = fmFullTsStorage.begin();
std::vector<uint64_t>::iterator itMissTs = fvulMissedTsIndices.begin();
while (!bHoleFoundInBothQueues) {
/// Check if the first TS in the full TS queue is the next one
if (fmFullTsStorage.end() != itFullTs && fuPrevTsIndex + 1 == (*itFullTs).first) {
/// Fill all storage variables registers for data output
PrepareTreeEntry((*itFullTs).second);
/// Trigger FairRoot manager to dump Tree entry
DumpTreeEntry();
/// Update counters
fuPrevTsIndex = (*itFullTs).first;
fulTsCounter++;
/// Increment iterator
++itFullTs;
continue;
} // if( fmFullTsStorage.end() != itFullTs && fuPrevTsIndex + 1 == (*itFullTs).first() )
if (fmFullTsStorage.end() != itFullTs)
LOG(debug) << "CbmDeviceDigiEventSink::CheckTsQueues => Full TS " << (*itFullTs).first << " VS "
<< (fuPrevTsIndex + 1);
/// Check if the first TS in the missed TS queue is the next one
if (fvulMissedTsIndices.end() != itMissTs
&& ((0 == fuPrevTsIndex && fuPrevTsIndex == (*itMissTs))
|| ((0 < fulTsCounter || 0 < fulMissedTsCounter) && fuPrevTsIndex + 1 == (*itMissTs)))) {
if (fbWriteMissingTs) {
/// Prepare entry with only dummy TS metadata and empty storage variables
new ((*fTimeSliceMetaDataArray)[fTimeSliceMetaDataArray->GetEntriesFast()])
TimesliceMetaData(0, 0, 0, (*itMissTs));
/// Trigger FairRoot manager to dump Tree entry
DumpTreeEntry();
}
/// Update counters
fuPrevTsIndex = (*itMissTs);
fulMissedTsCounter++;
/// Increment iterator
++itMissTs;
continue;
} // if( fvulMissedTsIndices.end() != itMissTs && fuPrevTsIndex + 1 == (*itMissTs ) )
if (fvulMissedTsIndices.end() != itMissTs)
LOG(debug) << "CbmDeviceDigiEventSink::CheckTsQueues => Empty TS " << (*itMissTs) << " VS "
<< (fuPrevTsIndex + 1);
/// Should be reached only if both queues at the end or hole found in both
bHoleFoundInBothQueues = true;
} // while( !bHoleFoundInBothQueues )
LOG(debug) << "CbmDeviceDigiEventSink::CheckTsQueues => buffered TS " << fmFullTsStorage.size()
<< " buffered empties " << fvulMissedTsIndices.size();
for (auto it = fmFullTsStorage.begin(); it != fmFullTsStorage.end(); ++it) {
LOG(debug) << "CbmDeviceDigiEventSink::CheckTsQueues => buffered TS index " << (*it).first;
}
/// Delete the processed entries
fmFullTsStorage.erase(fmFullTsStorage.begin(), itFullTs);
fvulMissedTsIndices.erase(fvulMissedTsIndices.begin(), itMissTs);
/// End of data: clean save of data + close file + send last state of histos if enabled
if (fbReceivedEof && fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount) {
LOG(info) << "CbmDeviceDigiEventSink::CheckTsQueues => "
<< "Found final TS index " << fuLastTsIndex << " and total nb TS " << fuTotalTsCount;
Finish();
} // if( fbReceivedEof && fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount )
}
//--------------------------------------------------------------------//
void CbmDeviceDigiEventSink::PrepareTreeEntry(CbmEventTimeslice unpTs)
{
/// FIXME: poor man solution with lots of data copy until we undertsnad how to properly deal
/// with FairMq messages ownership and memory managment
(*fEvtHeader) = std::move(unpTs.fCbmTsEventHeader);
/// FIXME: Not sure if this is the proper way to insert the data
new ((*fTimeSliceMetaDataArray)[fTimeSliceMetaDataArray->GetEntriesFast()])
TimesliceMetaData(std::move(unpTs.fTsMetaData));
/// Extract CbmEvent vector from input message
// FU, 29.06.22 Remove std::move to allow copy ellision
(*fEventsSel) = unpTs.GetSelectedData(fbExclusiveTrdExtract);
if (kTRUE == fbFillHistos) {
/// Accumulated counts, will show rise + plateau pattern in spill
fulProcessedEvents += fEventsSel->size();
}
/// Full TS Digis storage (optional usage, controlled by fbStoreFullTs!)
if (fbStoreFullTs) {
if (0 < unpTs.fvDigiBmon.size()) fvDigiBmon->assign(unpTs.fvDigiBmon.begin(), unpTs.fvDigiBmon.end());
if (0 < unpTs.fvDigiSts.size()) fvDigiSts->assign(unpTs.fvDigiSts.begin(), unpTs.fvDigiSts.end());
if (0 < unpTs.fvDigiMuch.size()) fvDigiMuch->assign(unpTs.fvDigiMuch.begin(), unpTs.fvDigiMuch.end());
if (0 < unpTs.fvDigiTrd.size()) fvDigiTrd->assign(unpTs.fvDigiTrd.begin(), unpTs.fvDigiTrd.end());
if (0 < unpTs.fvDigiTof.size()) fvDigiTof->assign(unpTs.fvDigiTof.begin(), unpTs.fvDigiTof.end());
if (0 < unpTs.fvDigiRich.size()) fvDigiRich->assign(unpTs.fvDigiRich.begin(), unpTs.fvDigiRich.end());
if (0 < unpTs.fvDigiPsd.size()) fvDigiPsd->assign(unpTs.fvDigiPsd.begin(), unpTs.fvDigiPsd.end());
}
}
void CbmDeviceDigiEventSink::DumpTreeEntry()
{
// Unpacked digis + CbmEvent output to root file
/*
* NH style
// fpFairRootMgr->FillEventHeader(fEvtHeader);
// LOG(info) << "Fill WriteOutBuffer with FairRootManager at " << fpFairRootMgr;
// fpOutRootFile->cd();
fpFairRootMgr->Fill();
fpFairRootMgr->StoreWriteoutBufferData( fpFairRootMgr->GetEventTime() );
//fpFairRootMgr->StoreAllWriteoutBufferData();
fpFairRootMgr->DeleteOldWriteoutBufferData();
*/
/// FairRunOnline style
fpFairRootMgr->StoreWriteoutBufferData(fpFairRootMgr->GetEventTime());
auto source = fpFairRootMgr->GetSource();
if (source) { source->FillEventHeader(fEvtHeader); }
fpFairRootMgr->Fill();
fpFairRootMgr->DeleteOldWriteoutBufferData();
// fpFairRootMgr->Write();
/// Clear metadata array
fTimeSliceMetaDataArray->Clear();
/// Clear event vector
fEventsSel->clear();
/// Full TS Digis storage (optional usage, controlled by fbStoreFullTs!)
if (fbStoreFullTs) {
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
fvDigiTof->clear();
fvDigiRich->clear();
fvDigiPsd->clear();
}
}
//--------------------------------------------------------------------//
bool CbmDeviceDigiEventSink::SendHistoConfAndData()
{
/// Prepare multiparts message and header
std::pair<uint32_t, uint32_t> pairHeader(fvpsHistosFolder.size(), fvpsCanvasConfig.size());
FairMQMessagePtr messageHeader(NewMessage());
// Serialize<BoostSerializer<std::pair<uint32_t, uint32_t>>>(*messageHeader, pairHeader);
BoostSerializer<std::pair<uint32_t, uint32_t>>().Serialize(*messageHeader, pairHeader);
FairMQParts partsOut;
partsOut.AddPart(std::move(messageHeader));
for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto) {
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, fvpsHistosFolder[uHisto]);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist, fvpsHistosFolder[uHisto]);
partsOut.AddPart(std::move(messageHist));
} // for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto)
/// Catch case where no histos are registered!
/// => Add empty message
if (0 == fvpsHistosFolder.size()) {
FairMQMessagePtr messageHist(NewMessage());
partsOut.AddPart(std::move(messageHist));
}
for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv) {
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, fvpsCanvasConfig[uCanv]);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageCan, fvpsCanvasConfig[uCanv]);
partsOut.AddPart(std::move(messageCan));
} // for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv)
/// Catch case where no Canvases are registered!
/// => Add empty message
if (0 == fvpsCanvasConfig.size()) {
FairMQMessagePtr messageHist(NewMessage());
partsOut.AddPart(std::move(messageHist));
}
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr msgHistos(NewMessage());
RootSerializer().Serialize(*msgHistos, &fArrayHisto);
partsOut.AddPart(std::move(msgHistos));
/// Send the multi-parts message to the common histogram messages queue
if (Send(partsOut, fsChannelNameHistosInput) < 0) {
LOG(error) << "CbmTsConsumerReqDevExample::SendHistoConfAndData => Problem sending data";
return false;
} // if( Send( partsOut, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
ResetHistograms(false);
return true;
}
bool CbmDeviceDigiEventSink::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
RootSerializer().Serialize(*message, &fArrayHisto);
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
LOG(error) << "Problem sending data";
return false;
} // if( Send( message, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
ResetHistograms(false);
return true;
}
//--------------------------------------------------------------------//
void CbmDeviceDigiEventSink::PostRun()
{
// Needed to avoid due to other end of ZMQ channel being already gone if called during Finish/destructor
if (kTRUE == fbFillHistos) {
SendHistograms();
fLastPublishTime = std::chrono::system_clock::now();
} // if( kTRUE == fbFillHistos )
}
//--------------------------------------------------------------------//
CbmDeviceDigiEventSink::~CbmDeviceDigiEventSink()
{
/// FIXME: Add pointers check before delete
/// Close things properly if not already done
if (fbInitDone && !fbFinishDone) Finish();
/// Clear events vector
if (fbInitDone) {
fEventsSel->clear();
delete fEventsSel;
}
delete fpRun;
}
void CbmDeviceDigiEventSink::Finish()
{
LOG(info) << "Performing clean close of the file";
// Clean closure of output to root file
fpFairRootMgr->Write(); // Broken due to FileMaxSize?!?
fpFairRootMgr->CloseSink();
LOG(info) << "File closed after saving " << (fulTsCounter + fulMissedTsCounter) << " TS (" << fulTsCounter
<< " full ones and " << fulMissedTsCounter << " missed/empty ones)";
LOG(info) << "Still buffered TS " << fmFullTsStorage.size() << " and still buffered empties "
<< fvulMissedTsIndices.size();
if (fair::mq::State::Running == GetCurrentState()) {
/// Force state transitions only if not already done by ODC/DDS!
ChangeState(fair::mq::Transition::Stop);
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
ChangeState(fair::mq::Transition::End);
}
fbFinishDone = kTRUE;
}
CbmEventTimeslice::CbmEventTimeslice(FairMQParts& parts, bool bDigiEvtInput)
{
fbDigiEvtInput = bDigiEvtInput;
uint32_t uPartIdx = 0;
if (fbDigiEvtInput) {
/// Digi events => Extract selected data from input message
if (3 != parts.Size()) {
LOG(error) << "CbmEventTimeslice::CbmEventTimeslice => Wrong number of parts to deserialize DigiEvents: "
<< parts.Size() << " VS 3!";
LOG(fatal) << "Probably the wrong value was used for the option DigiEventInput of the Sink or DigiEventOutput of "
<< "the event builder";
}
/// (1) TS header
TObject* tempObjectPointer = nullptr;
RootSerializer().Deserialize(*parts.At(uPartIdx), tempObjectPointer);
if (tempObjectPointer && TString(tempObjectPointer->ClassName()).EqualTo("CbmTsEventHeader")) {
fCbmTsEventHeader = *(static_cast<CbmTsEventHeader*>(tempObjectPointer));
}
else {
LOG(fatal) << "Failed to deserialize the TS header";
}
++uPartIdx;
/// (2) TS metadata
tempObjectPointer = nullptr;
RootSerializer().Deserialize(*parts.At(uPartIdx), tempObjectPointer);
if (tempObjectPointer && TString(tempObjectPointer->ClassName()).EqualTo("TimesliceMetaData")) {
fTsMetaData = *(static_cast<TimesliceMetaData*>(tempObjectPointer));
}
else {
LOG(fatal) << "Failed to deserialize the TS metadata";
}
++uPartIdx;
/// (3) Events
std::string msgStrEvt(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issEvt(msgStrEvt);
boost::archive::binary_iarchive inputArchiveEvt(issEvt);
inputArchiveEvt >> fvDigiEvents;
++uPartIdx;
LOG(debug) << "Input event array " << fvDigiEvents.size();
}
else {
/// Raw data + raw events => Extract unpacked data from input message
if (10 != parts.Size()) {
LOG(error) << "CbmEventTimeslice::CbmEventTimeslice => Wrong number of parts to deserialize raw data + events: "
<< parts.Size() << " VS 10!";
LOG(fatal) << "Probably the wrong value was used for the option DigiEventInput of the Sink or DigiEventOutput of "
<< "the event builder";
}
/// (1) TS header
TObject* tempObjectPointer = nullptr;
RootSerializer().Deserialize(*parts.At(uPartIdx), tempObjectPointer);
if (tempObjectPointer && TString(tempObjectPointer->ClassName()).EqualTo("CbmTsEventHeader")) {
fCbmTsEventHeader = *(static_cast<CbmTsEventHeader*>(tempObjectPointer));
}
else {
LOG(fatal) << "Failed to deserialize the TS header";
}
++uPartIdx;
/// (2) Bmon
std::string msgStrBmon(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issBmon(msgStrBmon);
boost::archive::binary_iarchive inputArchiveBmon(issBmon);
inputArchiveBmon >> fvDigiBmon;
++uPartIdx;
/// (3) STS
std::string msgStrSts(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issSts(msgStrSts);
boost::archive::binary_iarchive inputArchiveSts(issSts);
inputArchiveSts >> fvDigiSts;
++uPartIdx;
/// (4) MUCH
std::string msgStrMuch(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issMuch(msgStrMuch);
boost::archive::binary_iarchive inputArchiveMuch(issMuch);
inputArchiveMuch >> fvDigiMuch;
++uPartIdx;
/// (5) TRD
std::string msgStrTrd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTrd(msgStrTrd);
boost::archive::binary_iarchive inputArchiveTrd(issTrd);
inputArchiveTrd >> fvDigiTrd;
++uPartIdx;
/// (6) BmonF
std::string msgStrTof(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTof(msgStrTof);
boost::archive::binary_iarchive inputArchiveTof(issTof);
inputArchiveTof >> fvDigiTof;
++uPartIdx;
/// (7) RICH
std::string msgStrRich(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issRich(msgStrRich);
boost::archive::binary_iarchive inputArchiveRich(issRich);
inputArchiveRich >> fvDigiRich;
++uPartIdx;
/// (8) PSD
std::string msgStrPsd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issPsd(msgStrPsd);
boost::archive::binary_iarchive inputArchivePsd(issPsd);
inputArchivePsd >> fvDigiPsd;
++uPartIdx;
/// (9) TS metadata
tempObjectPointer = nullptr;
RootSerializer().Deserialize(*parts.At(uPartIdx), tempObjectPointer);
if (tempObjectPointer && TString(tempObjectPointer->ClassName()).EqualTo("TimesliceMetaData")) {
fTsMetaData = *(static_cast<TimesliceMetaData*>(tempObjectPointer));
}
else {
LOG(fatal) << "Failed to deserialize the TS metadata";
}
++uPartIdx;
/// (10) Events
/// FIXME: Find out if possible to use only the boost serializer/deserializer
/*
std::string msgStrEvt(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issEvt(msgStrEvt);
boost::archive::binary_iarchive inputArchiveEvt(issEvt);
inputArchiveEvt >> fvEvents;
++uPartIdx;
LOG(info) << "Input event array " << fvEvents.size();
*/
std::vector<CbmEvent>* pvOutEvents = nullptr;
RootSerializer().Deserialize(*parts.At(uPartIdx), pvOutEvents);
fvEvents = std::move(*pvOutEvents);
LOG(debug) << "Input event array " << fvEvents.size();
}
}
CbmEventTimeslice::~CbmEventTimeslice()
{
fvDigiBmon.clear();
fvDigiSts.clear();
fvDigiMuch.clear();
fvDigiTrd.clear();
fvDigiTof.clear();
fvDigiRich.clear();
fvDigiPsd.clear();
fvEvents.clear();
fvDigiEvents.clear();
}
void CbmEventTimeslice::ExtractSelectedData(bool bExclusiveTrdExtract)
{
fvDigiEvents.reserve(fvEvents.size());
/// Loop on events in input vector
for (CbmEvent event : fvEvents) {
CbmDigiEvent selEvent;
selEvent.fTime = event.GetStartTime();
selEvent.fNumber = event.GetNumber();
/// For pure digi based event, we select "continuous slices of digis"
/// => Copy block of [First Digi index, last digi index] with assign(it_start, it_stop)
/// => No data increase for most detectors as we use time window selection
/// Keep TRD1D + TRD2D support as single det, otherwise may lead to holes in the digi sequence!
/// => Need option to keep the loop to avoid adding extra digis if comparison to CbmEvents wanted
/// Get the proper order for block selection as TRD1D and TRD2D may insert indices in separate loops
/// => Needed to ensure that the start and stop of the block copy do not trigger a vector size exception
event.SortIndices();
/// for each detector, find the data in the Digi vectors and copy them
/// TODO: Template + loop on list of data types?
/// ==> Bmon
uint32_t uNbDigis = (0 < event.GetNofData(ECbmDataType::kBmonDigi) ? event.GetNofData(ECbmDataType::kBmonDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiBmon.begin() + event.GetIndex(ECbmDataType::kBmonDigi, 0);
auto stopIt = fvDigiBmon.begin() + event.GetIndex(ECbmDataType::kBmonDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fBmon.fDigis.assign(startIt, stopIt);
}
/// ==> STS
uNbDigis = (0 < event.GetNofData(ECbmDataType::kStsDigi) ? event.GetNofData(ECbmDataType::kStsDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiSts.begin() + event.GetIndex(ECbmDataType::kStsDigi, 0);
auto stopIt = fvDigiSts.begin() + event.GetIndex(ECbmDataType::kStsDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fSts.fDigis.assign(startIt, stopIt);
}
/// ==> MUCH
uNbDigis = (0 < event.GetNofData(ECbmDataType::kMuchDigi) ? event.GetNofData(ECbmDataType::kMuchDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiMuch.begin() + event.GetIndex(ECbmDataType::kMuchDigi, 0);
auto stopIt = fvDigiMuch.begin() + event.GetIndex(ECbmDataType::kMuchDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fMuch.fDigis.assign(startIt, stopIt);
}
/// ==> TRD + TRD2D
uNbDigis = (0 < event.GetNofData(ECbmDataType::kTrdDigi) ? event.GetNofData(ECbmDataType::kTrdDigi) : 0);
if (uNbDigis) {
if (bExclusiveTrdExtract) {
for (uint32_t uDigiInEvt = 0; uDigiInEvt < uNbDigis; ++uDigiInEvt) {
/// Copy each digi in the event by itself to make sure we skip ones outside their own selection window but
/// inside the selection window of the other TRD subsystem, effectively enforcing differetn windows:
/// [t, t+dt](TRD) = [t, t+dt](TRD1D) + [t, t+dt](TRD2D)
/// => Exclusive but slower
selEvent.fData.fTrd.fDigis.push_back(fvDigiTrd[event.GetIndex(ECbmDataType::kTrdDigi, uDigiInEvt)]);
}
}
else {
/// Block copy of all TRD digis, has feature that it may include digis which are not matching the selection
/// window of a given TRD subsystem, effectively making a larger selection window:
/// [t, t+dt](TRD) = [t, t+dt](TRD1D) U [t, t+dt](TRD2D)
/// => Faster but inclusive, will lead to more TRD hits and tracks than expected
auto startIt = fvDigiTrd.begin() + event.GetIndex(ECbmDataType::kTrdDigi, 0);
auto stopIt = fvDigiTrd.begin() + event.GetIndex(ECbmDataType::kTrdDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fTrd.fDigis.assign(startIt, stopIt);
}
}
/// ==> TOF
uNbDigis = (0 < event.GetNofData(ECbmDataType::kTofDigi) ? event.GetNofData(ECbmDataType::kTofDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiTof.begin() + event.GetIndex(ECbmDataType::kTofDigi, 0);
auto stopIt = fvDigiTof.begin() + event.GetIndex(ECbmDataType::kTofDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fTof.fDigis.assign(startIt, stopIt);
}
/// ==> RICH
uNbDigis = (0 < event.GetNofData(ECbmDataType::kRichDigi) ? event.GetNofData(ECbmDataType::kRichDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiRich.begin() + event.GetIndex(ECbmDataType::kRichDigi, 0);
auto stopIt = fvDigiRich.begin() + event.GetIndex(ECbmDataType::kRichDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fRich.fDigis.assign(startIt, stopIt);
}
/// ==> PSD
uNbDigis = (0 < event.GetNofData(ECbmDataType::kPsdDigi) ? event.GetNofData(ECbmDataType::kPsdDigi) : 0);
if (uNbDigis) {
auto startIt = fvDigiPsd.begin() + event.GetIndex(ECbmDataType::kPsdDigi, 0);
auto stopIt = fvDigiPsd.begin() + event.GetIndex(ECbmDataType::kPsdDigi, uNbDigis - 1);
++stopIt;
selEvent.fData.fPsd.fDigis.assign(startIt, stopIt);
}
fvDigiEvents.push_back(selEvent);
}
}
/* Copyright (C) 2020-2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceDigiEventSink.h
*
* @since 2020-05-04
* @author P.-A. Loizeau
*/
#ifndef CBMDEVICEDIGIEVTSINK_H_
#define CBMDEVICEDIGIEVTSINK_H_
/// CBM headers
#include "CbmBmonDigi.h"
#include "CbmDigiEvent.h"
#include "CbmEvent.h"
#include "CbmMqTMessage.h"
#include "CbmMuchDigi.h"
#include "CbmPsdDigi.h"
#include "CbmRichDigi.h"
#include "CbmStsDigi.h"
#include "CbmTofDigi.h"
#include "CbmTrdDigi.h"
#include "CbmTsEventHeader.h"
#include "TimesliceMetaData.h"
/// FAIRROOT headers
#include "FairMQDevice.h"
/// FAIRSOFT headers (geant, boost, ...)
#include "Rtypes.h"
#include "TClonesArray.h"
#include "TObjArray.h"
/// C/C++ headers
#include <chrono>
#include <map>
#include <vector>
class TCanvas;
class TFile;
class TH1;
class TProfile;
class TList;
class TClonesArray;
//class TimesliceMetaData;
class FairRunOnline;
class FairRootManager;
class CbmEventTimeslice {
/// TODO: rename to CbmTsWithEvents
public:
CbmEventTimeslice(FairMQParts& parts, bool bDigiEvtInput = false);
~CbmEventTimeslice();
void ExtractSelectedData(bool bExclusiveTrdExtract = true);
std::vector<CbmDigiEvent>& GetSelectedData(bool bExclusiveTrdExtract = true)
{
if (!fbDigiEvtInput) ExtractSelectedData(bExclusiveTrdExtract);
return fvDigiEvents;
}
/// Input Type
bool fbDigiEvtInput = false;
/// TS information in header
CbmTsEventHeader fCbmTsEventHeader;
/// Raw data
std::vector<CbmBmonDigi> fvDigiBmon;
std::vector<CbmStsDigi> fvDigiSts;
std::vector<CbmMuchDigi> fvDigiMuch;
std::vector<CbmTrdDigi> fvDigiTrd;
std::vector<CbmTofDigi> fvDigiTof;
std::vector<CbmRichDigi> fvDigiRich;
std::vector<CbmPsdDigi> fvDigiPsd;
/// extra Metadata
TimesliceMetaData fTsMetaData;
/// Raw events
std::vector<CbmEvent> fvEvents;
/// Digi events
std::vector<CbmDigiEvent> fvDigiEvents;
};
class CbmDeviceDigiEventSink : public FairMQDevice {
public:
CbmDeviceDigiEventSink();
virtual ~CbmDeviceDigiEventSink();
protected:
virtual void InitTask();
bool HandleMissTsData(FairMQMessagePtr&, int);
bool HandleData(FairMQParts&, int);
bool HandleCommand(FairMQMessagePtr&, int);
virtual void PostRun();
private:
/// Constants
/// Control flags
bool fbStoreFullTs = false; //! If true, store digis vectors with full TS in addition to selected events
bool fbBypassConsecutiveTs = false; //! Switch ON/OFF the bypass of the consecutive TS buffer before writing to file
bool fbWriteMissingTs = false; //! Switch ON/OFF writing of empty TS to file for the missing ones (if no bypass)
bool fbDisableCompression = false; //! Switch ON/OFF the ROOT file compression
bool fbDigiEventInput = false; //! Switch ON/OFF the input of CbmDigiEvents instead of raw data + CbmEvents
bool fbExclusiveTrdExtract = true; //! Switch ON/OFF loop based extraction of TRD digis due to 1D/2D
bool fbFillHistos = false; //! Switch ON/OFF filling of histograms
bool fbInitDone = false; //! Keep track of whether the Init was already fully completed
bool fbFinishDone = false; //! Keep track of whether the Finish was already called
/// User settings parameters
/// Algo enum settings
std::string fsOutputFileName = "mcbm_digis_events.root";
/// message queues
std::string fsChannelNameMissedTs = "missedts";
std::string fsChannelNameDataInput = "events";
std::string fsChannelNameCommands = "commands";
std::string fsChannelNameHistosInput = "histogram-in";
/// Output file/tree management
int64_t fiTreeFileMaxSize = 10000000000LL; //! Default value: ~10 GB
/// Histograms management
uint32_t fuPublishFreqTs = 100;
double_t fdMinPublishTime = 0.5;
double_t fdMaxPublishTime = 5.0;
std::string fsHistosSuffix = "";
/// List of MQ channels names
std::vector<std::string> fsAllowedChannels = {fsChannelNameDataInput};
/// Parameters management
// TList* fParCList = nullptr;
// Bool_t InitParameters( TList* fParCList );
/// Statistics & missed TS detection
uint64_t fuPrevTsIndex = 0;
uint64_t fulNumMessages = 0;
uint64_t fulTsCounter = 0;
uint64_t fulMissedTsCounter = 0;
uint64_t fulProcessedEvents = 0;
uint64_t fulLastFullTsCounter = 0;
uint64_t fulLastMissTsCounter = 0;
uint64_t fulLastProcessedEvents = 0;
std::chrono::system_clock::time_point fLastPublishTime = std::chrono::system_clock::now();
std::chrono::system_clock::time_point fLastFillTime = std::chrono::system_clock::now();
std::chrono::system_clock::time_point fStartTime = std::chrono::system_clock::now();
/// Control Commands reception
bool fbReceivedEof = false;
uint64_t fuLastTsIndex = 0;
uint64_t fuTotalTsCount = 0;
/// Data reception
/// Event (TS) header
CbmTsEventHeader* fEvtHeader = nullptr;
/// TS MetaData storage
TClonesArray* fTimeSliceMetaDataArray = nullptr; //!
// TimesliceMetaData* fTsMetaData = nullptr;
/// CbmEvents
std::vector<CbmDigiEvent>* fEventsSel = nullptr; //! output container of CbmEvents
/// Full TS Digis storage (optional usage, controlled by fbStoreFullTs!)
std::vector<CbmBmonDigi>* fvDigiBmon = nullptr;
std::vector<CbmStsDigi>* fvDigiSts = nullptr;
std::vector<CbmMuchDigi>* fvDigiMuch = nullptr;
std::vector<CbmTrdDigi>* fvDigiTrd = nullptr;
std::vector<CbmTofDigi>* fvDigiTof = nullptr;
std::vector<CbmRichDigi>* fvDigiRich = nullptr;
std::vector<CbmPsdDigi>* fvDigiPsd = nullptr;
/// Storage for re-ordering
/// Missed TS vector
std::vector<uint64_t> fvulMissedTsIndices = {};
/// Buffered TS
std::map<uint64_t, CbmEventTimeslice> fmFullTsStorage = {};
/// Data storage
FairRunOnline* fpRun = nullptr;
FairRootManager* fpFairRootMgr = nullptr;
/// Array of histograms to send to the histogram server
TObjArray fArrayHisto = {};
/// Vector of string pairs with ( HistoName, FolderPath ) to send to the histogram server
std::vector<std::pair<std::string, std::string>> fvpsHistosFolder = {};
/// Vector of string pairs with ( CanvasName, CanvasConfig ) to send to the histogram server
/// Format of Can config is "NbPadX(U);NbPadY(U);ConfigPad1(s);....;ConfigPadXY(s)"
/// Format of Pad config is "GrixX(b),GridY(b),LogX(b),LogY(b),LogZ(b),HistoName(s),DrawOptions(s)"
std::vector<std::pair<std::string, std::string>> fvpsCanvasConfig = {};
/// Flag indicating whether the histograms and canvases configurations were already published
bool fbConfigSent = false;
TProfile* fhFullTsBuffSizeEvo;
TProfile* fhMissTsBuffSizeEvo;
TH1* fhFullTsProcEvo;
TH1* fhMissTsProcEvo;
TH1* fhTotalTsProcEvo;
TH1* fhTotalEventsEvo;
TCanvas* fcEventSinkAllHist;
/// Internal methods
bool IsChannelNameAllowed(std::string channelName);
bool InitHistograms();
bool ResetHistograms(bool bResetStartTime = false);
void CheckTsQueues();
void PrepareTreeEntry(CbmEventTimeslice unpTs);
void DumpTreeEntry();
bool SendHistoConfAndData();
bool SendHistograms();
void Finish();
};
#endif /* CBMDEVICEDIGIEVTSINK_H_ */
......@@ -52,7 +52,7 @@ struct InitTaskError : std::runtime_error {
using namespace std;
//Bool_t bMcbm2018MonitorTaskT0ResetHistos = kFALSE;
//Bool_t bMcbm2018MonitorTaskBmonResetHistos = kFALSE;
CbmDeviceMcbmEventBuilderWin::CbmDeviceMcbmEventBuilderWin() { fpAlgo = new CbmMcbm2019TimeWinEventBuilderAlgo(); }
......@@ -116,9 +116,9 @@ try {
: EOverlapMode::NoOverlap)));
fpAlgo->SetEventOverlapMode(mode);
/// Extract refdet
EventBuilderDetector refDet = ("kT0" == fsRefDet ? kEventBuilderDetT0
: ("kSts" == fsRefDet ? kEventBuilderDetMuch
: ("kMuch" == fsRefDet ? kEventBuilderDetTrd
EventBuilderDetector refDet = ("kBmon" == fsRefDet ? kEventBuilderDetBmon
: ("kSts" == fsRefDet ? kEventBuilderDetSts
: ("kMuch" == fsRefDet ? kEventBuilderDetMuch
: ("kTrd" == fsRefDet ? kEventBuilderDetTrd
: ("kTof" == fsRefDet ? kEventBuilderDetTof
: ("kRich" == fsRefDet ? kEventBuilderDetRich
......@@ -137,7 +137,7 @@ try {
for (std::vector<std::string>::iterator itStrAdd = fvsAddDet.begin();
itStrAdd != fvsAddDet.end();
++itStrAdd) {
EventBuilderDetector addDet = ("kT0" == *itStrAdd ? kEventBuilderDetT0
EventBuilderDetector addDet = ("kBmon" == *itStrAdd ? kEventBuilderDetBmon
: ("kSts" == *itStrAdd ? kEventBuilderDetSts
: ("kMuch" == *itStrAdd ? kEventBuilderDetMuch
: ("kTrd" == *itStrAdd ? kEventBuilderDetTrd
......@@ -160,7 +160,7 @@ try {
for (std::vector<std::string>::iterator itStrRem = fvsDelDet.begin();
itStrRem != fvsDelDet.end();
++itStrRem) {
EventBuilderDetector remDet = ("kT0" == *itStrRem ? kEventBuilderDetT0
EventBuilderDetector remDet = ("kBmon" == *itStrRem ? kEventBuilderDetBmon
: ("kSts" == *itStrRem ? kEventBuilderDetSts
: ("kMuch" == *itStrRem ? kEventBuilderDetMuch
: ("kTrd" == *itStrRem ? kEventBuilderDetTrd
......@@ -194,7 +194,7 @@ try {
/// Detector Enum Tag
std::string sSelDet = (*itStrTrigWin).substr(0, charPosDel);
ECbmModuleId selDet = ("kT0" == sSelDet ? ECbmModuleId::kT0
ECbmModuleId selDet = ("kBmon" == sSelDet ? ECbmModuleId::kBmon
: ("kSts" == sSelDet ? ECbmModuleId::kSts
: ("kMuch" == sSelDet ? ECbmModuleId::kMuch
: ("kTrd" == sSelDet ? ECbmModuleId::kTrd
......@@ -246,7 +246,7 @@ try {
/// Detector Enum Tag
std::string sSelDet = (*itStrMinNb).substr(0, charPosDel);
ECbmModuleId selDet = ("kT0" == sSelDet ? ECbmModuleId::kT0
ECbmModuleId selDet = ("kBmon" == sSelDet ? ECbmModuleId::kBmon
: ("kSts" == sSelDet ? ECbmModuleId::kSts
: ("kMuch" == sSelDet ? ECbmModuleId::kMuch
: ("kTrd" == sSelDet ? ECbmModuleId::kTrd
......@@ -273,7 +273,7 @@ try {
/* clang-format on */
/// Create input vectors
fvDigiT0 = new std::vector<CbmTofDigi>();
fvDigiBmon = new std::vector<CbmTofDigi>();
fvDigiSts = new std::vector<CbmStsDigi>();
fvDigiMuch = new std::vector<CbmMuchBeamTimeDigi>();
fvDigiTrd = new std::vector<CbmTrdDigi>();
......@@ -290,7 +290,7 @@ try {
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("BmonDigi", fvDigiBmon, kFALSE);
ioman->RegisterAny("StsDigi", fvDigiSts, kFALSE);
ioman->RegisterAny("MuchBeamTimeDigi", fvDigiMuch, kFALSE);
ioman->RegisterAny("TrdDigi", fvDigiTrd, kFALSE);
......@@ -340,7 +340,8 @@ try {
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist(NewMessage());
Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, psHistoConfig);
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, psHistoConfig);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist, psHistoConfig);
/// Send message to the common histogram config messages queue
if (Send(messageHist, fsChannelNameHistosConfig) < 0) {
......@@ -365,7 +366,8 @@ try {
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan(NewMessage());
Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, psCanvConfig);
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, psCanvConfig);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageCan, psCanvConfig);
/// Send message to the common canvas config messages queue
if (Send(messageCan, fsChannelNameCanvasConfig) < 0) {
......@@ -442,7 +444,7 @@ Bool_t CbmDeviceMcbmEventBuilderWin::InitParameters( TList* fParCList )
{
if( 0 != rep->GetSize() )
{
CbmMQTMessage tmsg( rep->GetData(), 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();
......@@ -482,18 +484,19 @@ bool CbmDeviceMcbmEventBuilderWin::HandleData(FairMQParts& parts, int /*index*/)
inputArchiveTsMeta >> (*fTsMetaData);
++uPartIdx;
*/
Deserialize<RootSerializer>(*parts.At(uPartIdx), fTsMetaData);
// Deserialize<RootSerializer>(*parts.At(uPartIdx), fTsMetaData);
RootSerializer().Deserialize(*parts.At(uPartIdx), fTsMetaData);
/// FIXME: Not if this is the proper way to insert the data
new ((*fTimeSliceMetaDataArray)[fTimeSliceMetaDataArray->GetEntriesFast()
// ] ) TimesliceMetaData( *fTsMetaData ) ;
]) TimesliceMetaData(std::move(*fTsMetaData));
++uPartIdx;
/// 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;
/// BMON
std::string msgStrBmon(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issBmon(msgStrBmon);
boost::archive::binary_iarchive inputArchiveBmon(issBmon);
inputArchiveBmon >> *fvDigiBmon;
++uPartIdx;
/// STS
......@@ -517,7 +520,7 @@ bool CbmDeviceMcbmEventBuilderWin::HandleData(FairMQParts& parts, int /*index*/)
inputArchiveTrd >> *fvDigiTrd;
++uPartIdx;
/// T0F
/// TOF
std::string msgStrTof(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTof(msgStrTof);
boost::archive::binary_iarchive inputArchiveTof(issTof);
......@@ -549,7 +552,7 @@ bool CbmDeviceMcbmEventBuilderWin::HandleData(FairMQParts& parts, int /*index*/)
// delete fTsMetaData;
/// Clear vectors
fvDigiT0->clear();
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
......@@ -598,7 +601,8 @@ bool CbmDeviceMcbmEventBuilderWin::SendEvents(FairMQParts& partsIn)
/// Serialize the array of events into a single MQ message
FairMQMessagePtr message(NewMessage());
Serialize<RootSerializer>(*message, fEvents);
// Serialize<RootSerializer>(*message, fEvents);
RootSerializer().Serialize(*message, fEvents);
/// Add it at the end of the input composed message
/// FIXME: use move or fix addition of new part to avoid full message copy
......@@ -634,7 +638,8 @@ bool CbmDeviceMcbmEventBuilderWin::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
Serialize<RootSerializer>(*message, &fArrayHisto);
// Serialize<RootSerializer>(*message, &fArrayHisto);
RootSerializer().Serialize(*message, &fArrayHisto);
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
......@@ -655,7 +660,7 @@ CbmDeviceMcbmEventBuilderWin::~CbmDeviceMcbmEventBuilderWin()
delete fTsMetaData;
/// Clear vectors
fvDigiT0->clear();
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
......
......@@ -14,6 +14,7 @@
/// CBM headers
#include "CbmMcbm2019TimeWinEventBuilderAlgo.h"
#include "CbmMqTMessage.h"
#include "CbmMuchBeamTimeDigi.h"
#include "CbmPsdDigi.h"
#include "CbmRichDigi.h"
......@@ -26,7 +27,6 @@
/// FAIRSOFT headers (geant, boost, ...)
#include "Rtypes.h"
#include "TMessage.h"
#include "TObjArray.h"
/// C/C++ headers
......@@ -59,7 +59,7 @@ private:
/// User settings parameters
/// Algo enum settings
std::string fsEvtOverMode = "NoOverlap";
std::string fsRefDet = "kT0";
std::string fsRefDet = "kBmon";
std::vector<std::string> fvsAddDet = {};
std::vector<std::string> fvsDelDet = {};
std::vector<std::string> fvsSetTrigWin = {};
......@@ -104,7 +104,7 @@ private:
TClonesArray* fTimeSliceMetaDataArray = nullptr; //!
TimesliceMetaData* fTsMetaData = nullptr;
/// Digis storage
std::vector<CbmTofDigi>* fvDigiT0 = nullptr;
std::vector<CbmTofDigi>* fvDigiBmon = nullptr;
std::vector<CbmStsDigi>* fvDigiSts = nullptr;
std::vector<CbmMuchBeamTimeDigi>* fvDigiMuch = nullptr;
std::vector<CbmTrdDigi>* fvDigiTrd = nullptr;
......@@ -134,11 +134,4 @@ private:
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_ */
......@@ -54,7 +54,7 @@ struct InitTaskError : std::runtime_error {
using namespace std;
//Bool_t bMcbm2018MonitorTaskT0ResetHistos = kFALSE;
//Bool_t bMcbm2018MonitorTaskBmonResetHistos = kFALSE;
CbmDeviceMcbmEventSink::CbmDeviceMcbmEventSink() {}
......@@ -105,7 +105,7 @@ try {
// InitContainers();
/// Create input vectors
fvDigiT0 = new std::vector<CbmTofDigi>();
fvDigiBmon = new std::vector<CbmTofDigi>();
fvDigiSts = new std::vector<CbmStsDigi>();
fvDigiMuch = new std::vector<CbmMuchBeamTimeDigi>();
fvDigiTrd = new std::vector<CbmTrdDigi>();
......@@ -151,7 +151,7 @@ try {
/// TS MetaData
fpFairRootMgr->Register("TimesliceMetaData", "TS Meta Data", fTimeSliceMetaDataArray, kTRUE);
/// Digis storage
fpFairRootMgr->RegisterAny("T0Digi", fvDigiT0, kTRUE);
fpFairRootMgr->RegisterAny("BmonDigi", fvDigiBmon, kTRUE);
fpFairRootMgr->RegisterAny("StsDigi", fvDigiSts, kTRUE);
fpFairRootMgr->RegisterAny("MuchBeamTimeDigi", fvDigiMuch, kTRUE);
fpFairRootMgr->RegisterAny("TrdDigi", fvDigiTrd, kTRUE);
......@@ -194,7 +194,8 @@ try {
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist( NewMessage() );
Serialize< BoostSerializer < std::pair< std::string, std::string > > >( *messageHist, psHistoConfig );
// Serialize< BoostSerializer < std::pair< std::string, std::string > > >( *messageHist, psHistoConfig );
BoostSerializer < std::pair< std::string, std::string > >.Serialize( *messageHist, psHistoConfig );
/// Send message to the common histogram config messages queue
if( Send( messageHist, fsChannelNameHistosConfig ) < 0 )
......@@ -222,7 +223,8 @@ try {
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan( NewMessage() );
Serialize< BoostSerializer < std::pair< std::string, std::string > > >( *messageCan, psCanvConfig );
// Serialize< BoostSerializer < std::pair< std::string, std::string > > >( *messageCan, psCanvConfig );
BoostSerializer < std::pair< std::string, std::string > >.Serialize( *messageCan, psCanvConfig );
/// Send message to the common canvas config messages queue
if( Send( messageCan, fsChannelNameCanvasConfig ) < 0 )
......@@ -302,7 +304,7 @@ Bool_t CbmDeviceMcbmEventSink::InitParameters( TList* fParCList )
{
if( 0 != rep->GetSize() )
{
CbmMQTMessage tmsg( rep->GetData(), 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();
......@@ -360,7 +362,8 @@ bool CbmDeviceMcbmEventSink::HandleData(FairMQParts& parts, int /*index*/)
inputArchiveTsMeta >> (*fTsMetaData);
++uPartIdx;
*/
Deserialize<RootSerializer>(*parts.At(uPartIdx), fTsMetaData);
// Deserialize<RootSerializer>(*parts.At(uPartIdx), fTsMetaData);
RootSerializer().Deserialize(*parts.At(uPartIdx), fTsMetaData);
LOG(debug) << "TS metadata extracted";
/// FIXME: Need to check if TS arrived in order (probably not!!!) + buffer!!!
......@@ -538,15 +541,15 @@ void CbmDeviceMcbmEventSink::PrepareTreeEntry(CbmUnpackedTimeslice unpTs)
/*
/// Explicit copy version: safe but slow
/// T0
fvDigiT0->insert( fvDigiT0->end(), unpTs.fvDigiT0.begin(), unpTs.fvDigiT0.end() );
/// Bmon
fvDigiBmon->insert( fvDigiBmon->end(), unpTs.fvDigiBmon.begin(), unpTs.fvDigiBmon.end() );
/// STS
fvDigiSts->insert( fvDigiSts->end(), unpTs.fvDigiSts.begin(), unpTs.fvDigiSts.end() );
/// MUCH
fvDigiMuch->insert( fvDigiMuch->end(), unpTs.fvDigiMuch.begin(), unpTs.fvDigiMuch.end() );
/// TRD
fvDigiTrd->insert( fvDigiTrd->end(), unpTs.fvDigiTrd.begin(), unpTs.fvDigiTrd.end() );
/// T0F
/// BmonF
fvDigiTof->insert( fvDigiTof->end(), unpTs.fvDigiTof.begin(), unpTs.fvDigiTof.end() );
/// RICH
fvDigiRich->insert( fvDigiRich->end(), unpTs.fvDigiRich.begin(), unpTs.fvDigiRich.end() );
......@@ -554,15 +557,15 @@ void CbmDeviceMcbmEventSink::PrepareTreeEntry(CbmUnpackedTimeslice unpTs)
fvDigiPsd->insert( fvDigiPsd->end(), unpTs.fvDigiPsd.begin(), unpTs.fvDigiPsd.end() );
*/
/// move version: safe but slow
/// T0
(*fvDigiT0) = std::move(unpTs.fvDigiT0);
/// Bmon
(*fvDigiBmon) = std::move(unpTs.fvDigiBmon);
/// STS
(*fvDigiSts) = std::move(unpTs.fvDigiSts);
/// MUCH
(*fvDigiMuch) = std::move(unpTs.fvDigiMuch);
/// TRD
(*fvDigiTrd) = std::move(unpTs.fvDigiTrd);
/// T0F
/// BmonF
(*fvDigiTof) = std::move(unpTs.fvDigiTof);
/// RICH
(*fvDigiRich) = std::move(unpTs.fvDigiRich);
......@@ -594,7 +597,7 @@ void CbmDeviceMcbmEventSink::DumpTreeEntry()
fTimeSliceMetaDataArray->Clear();
/// Clear vectors
fvDigiT0->clear();
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
......@@ -613,7 +616,8 @@ bool CbmDeviceMcbmEventSink::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
Serialize<RootSerializer>(*message, &fArrayHisto);
// Serialize<RootSerializer>(*message, &fArrayHisto);
RootSerializer().Serialize(*message, &fArrayHisto);
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
......@@ -641,7 +645,7 @@ CbmDeviceMcbmEventSink::~CbmDeviceMcbmEventSink()
delete fTsMetaData;
/// Clear vectors
fvDigiT0->clear();
fvDigiBmon->clear();
fvDigiSts->clear();
fvDigiMuch->clear();
fvDigiTrd->clear();
......@@ -699,11 +703,11 @@ CbmUnpackedTimeslice::CbmUnpackedTimeslice(FairMQParts& parts) : fEventsArray("C
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;
/// Bmon
std::string msgStrBmon(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issBmon(msgStrBmon);
boost::archive::binary_iarchive inputArchiveBmon(issBmon);
inputArchiveBmon >> fvDigiBmon;
++uPartIdx;
/// STS
......@@ -727,7 +731,7 @@ CbmUnpackedTimeslice::CbmUnpackedTimeslice(FairMQParts& parts) : fEventsArray("C
inputArchiveTrd >> fvDigiTrd;
++uPartIdx;
/// T0F
/// BmonF
std::string msgStrTof(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issTof(msgStrTof);
boost::archive::binary_iarchive inputArchiveTof(issTof);
......@@ -763,7 +767,7 @@ CbmUnpackedTimeslice::CbmUnpackedTimeslice(FairMQParts& parts) : fEventsArray("C
CbmUnpackedTimeslice::~CbmUnpackedTimeslice()
{
fvDigiT0.clear();
fvDigiBmon.clear();
fvDigiSts.clear();
fvDigiMuch.clear();
fvDigiTrd.clear();
......
......@@ -14,6 +14,7 @@
/// CBM headers
#include "CbmEvent.h"
#include "CbmMqTMessage.h"
#include "CbmMuchBeamTimeDigi.h"
#include "CbmPsdDigi.h"
#include "CbmRichDigi.h"
......@@ -29,7 +30,6 @@
/// FAIRSOFT headers (geant, boost, ...)
#include "Rtypes.h"
#include "TClonesArray.h"
#include "TMessage.h"
#include "TObjArray.h"
/// C/C++ headers
......@@ -51,7 +51,7 @@ public:
~CbmUnpackedTimeslice();
TimesliceMetaData fTsMetaData;
std::vector<CbmTofDigi> fvDigiT0;
std::vector<CbmTofDigi> fvDigiBmon;
std::vector<CbmStsDigi> fvDigiSts;
std::vector<CbmMuchBeamTimeDigi> fvDigiMuch;
std::vector<CbmTrdDigi> fvDigiTrd;
......@@ -120,7 +120,7 @@ private:
TClonesArray* fTimeSliceMetaDataArray = nullptr; //!
TimesliceMetaData* fTsMetaData = nullptr;
/// Digis storage
std::vector<CbmTofDigi>* fvDigiT0 = nullptr;
std::vector<CbmTofDigi>* fvDigiBmon = nullptr;
std::vector<CbmStsDigi>* fvDigiSts = nullptr;
std::vector<CbmMuchBeamTimeDigi>* fvDigiMuch = nullptr;
std::vector<CbmTrdDigi>* fvDigiTrd = nullptr;
......@@ -160,11 +160,4 @@ private:
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_ */
......@@ -150,7 +150,7 @@ Bool_t CbmDeviceMcbmMonitorPulser::InitContainers()
if ( Send(req, "parameters") > 0 ) {
if ( Receive( rep, "parameters" ) >= 0) {
if ( rep->GetSize() != 0 ) {
CbmMQTMessage tmsg( rep->GetData(), 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();
......@@ -201,7 +201,8 @@ Bool_t CbmDeviceMcbmMonitorPulser::InitContainers()
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist( NewMessage() );
Serialize< BoostSerializer < std::pair< std::string, std::string > > >( *messageHist, psHistoConfig );
// Serialize< BoostSerializer < std::pair< std::string, std::string > > >( *messageHist, psHistoConfig );
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist,psHistoConfig);
/// Send message to the common histogram config messages queue
if( Send( messageHist, fsChannelNameHistosConfig ) < 0 )
......@@ -230,7 +231,8 @@ Bool_t CbmDeviceMcbmMonitorPulser::InitContainers()
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan( NewMessage() );
Serialize< BoostSerializer < std::pair< std::string, std::string > > >( *messageCan, psCanvConfig );
// Serialize< BoostSerializer < std::pair< std::string, std::string > > >( *messageCan, psCanvConfig );
BoostSerializer < std::pair< std::string, std::string > >().Serialize( *messageCan, psCanvConfig );
/// Send message to the common canvas config messages queue
if( Send( messageCan, fsChannelNameCanvasConfig ) < 0 )
......@@ -266,13 +268,14 @@ bool CbmDeviceMcbmMonitorPulser::HandleData(FairMQParts& parts, int /*index*/)
inputArchiveTsMeta >> (*fTsMetaData);
++uPartIdx;
*/
Deserialize<RootSerializer>(*parts.At(uPartIdx), fTsMetaData);
// Deserialize<RootSerializer>(*parts.At(uPartIdx), fTsMetaData);
RootSerializer().Deserialize(*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;
std::string msgStrBmon(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
std::istringstream issBmon(msgStrBmon);
boost::archive::binary_iarchive inputArchiveBmon(issBmon);
inputArchiveBmon >> fvDigiBmon;
++uPartIdx;
std::string msgStrSts(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
......@@ -315,7 +318,7 @@ bool CbmDeviceMcbmMonitorPulser::HandleData(FairMQParts& parts, int /*index*/)
/// Clear vectors
delete fTsMetaData;
fvDigiT0.clear();
fvDigiBmon.clear();
fvDigiSts.clear();
fvDigiMuch.clear();
fvDigiTrd.clear();
......@@ -360,12 +363,14 @@ bool CbmDeviceMcbmMonitorPulser::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
Serialize<RootSerializer>(*message, &fArrayHisto);
// Serialize<RootSerializer>(*message, &fArrayHisto);
RootSerializer().Serialize(*message, &fArrayHisto);
// test code to check if deserialization works
/*
TObject* tempObject = nullptr;
Deserialize<RootDeserializer>(*message, tempObject);
// Deserialize<RootDeserializer>(*message, tempObject);
RootDeserializer().Deserialize(*message, tempObject);
if (TString(tempObject->ClassName()).EqualTo("TObjArray")) {
TObjArray* arrayHisto = static_cast<TObjArray*>(tempObject);
......
......@@ -12,6 +12,7 @@
#ifndef CBMDEVICEMCBMMONITORPULSER_H_
#define CBMDEVICEMCBMMONITORPULSER_H_
#include "CbmMqTMessage.h"
#include "CbmMuchBeamTimeDigi.h"
#include "CbmPsdDigi.h"
#include "CbmRichDigi.h"
......@@ -22,7 +23,6 @@
#include "FairMQDevice.h"
#include "Rtypes.h"
#include "TMessage.h"
#include "TObjArray.h"
#include <chrono>
......@@ -91,7 +91,7 @@ private:
/// TS MetaData storage
TimesliceMetaData* fTsMetaData = nullptr;
/// Digis storage
std::vector<CbmTofDigi> fvDigiT0 = {};
std::vector<CbmTofDigi> fvDigiBmon = {};
std::vector<CbmStsDigi> fvDigiSts = {};
std::vector<CbmMuchBeamTimeDigi> fvDigiMuch = {};
std::vector<CbmTrdDigi> fvDigiTrd = {};
......@@ -128,7 +128,7 @@ private:
void CreateHistos();
/// Variables to store the previous digi time
Double_t fPrevTimeT0 = 0.;
Double_t fPrevTimeBmon = 0.;
Double_t fPrevTimeSts = 0.;
Double_t fPrevTimeMuch = 0.;
Double_t fPrevTimeTrd = 0.;
......@@ -136,19 +136,19 @@ private:
Double_t fPrevTimeRich = 0.;
Double_t fPrevTimePsd = 0.;
/// Variables to store the first digi fitting the previous T0 hits
/// Variables to store the first digi fitting the previous Bmon hits
/// => Time-order means the time window for following one can only be in a later digi
Int_t fPrevT0FirstDigiSts = 0;
Int_t fPrevT0FirstDigiMuch = 0;
Int_t fPrevT0FirstDigiTrd = 0;
Int_t fPrevT0FirstDigiTof = 0;
Int_t fPrevT0FirstDigiRich = 0;
Int_t fPrevT0FirstDigiPsd = 0;
Int_t fPrevBmonFirstDigiSts = 0;
Int_t fPrevBmonFirstDigiMuch = 0;
Int_t fPrevBmonFirstDigiTrd = 0;
Int_t fPrevBmonFirstDigiTof = 0;
Int_t fPrevBmonFirstDigiRich = 0;
Int_t fPrevBmonFirstDigiPsd = 0;
/// User settings: Data correction parameters
/// Charge cut
UInt_t fuMinTotPulserT0 = 182;
UInt_t fuMaxTotPulserT0 = 190;
UInt_t fuMinTotPulserBmon = 182;
UInt_t fuMaxTotPulserBmon = 190;
UInt_t fuMinAdcPulserSts = 90;
UInt_t fuMaxAdcPulserSts = 100;
UInt_t fuMinAdcPulserMuch = 5;
......@@ -184,37 +184,37 @@ private:
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;
TH1* fBmonStsDiff = nullptr;
TH1* fBmonMuchDiff = nullptr;
TH1* fBmonTrdDiff = nullptr;
TH1* fBmonTofDiff = nullptr;
TH1* fBmonRichDiff = nullptr;
TH1* fBmonPsdDiff = nullptr;
TH2* fBmonPsdDiffCharge = nullptr;
TH2* fBmonStsDiffEvo = nullptr;
TH2* fBmonMuchDiffEvo = nullptr;
TH2* fBmonTrdDiffEvo = nullptr;
TH2* fBmonTofDiffEvo = nullptr;
TH2* fBmonRichDiffEvo = nullptr;
TH2* fBmonPsdDiffEvo = nullptr;
TH2* fBmonStsDiffEvoLong = nullptr;
TH2* fBmonMuchDiffEvoLong = nullptr;
TH2* fBmonTrdDiffEvoLong = nullptr;
TH2* fBmonTofDiffEvoLong = nullptr;
TH2* fBmonRichDiffEvoLong = nullptr;
TH2* fBmonPsdDiffEvoLong = nullptr;
Double_t fdStartTime = -1;
TProfile* fT0StsMeanEvo = nullptr;
TProfile* fT0MuchMeanEvo = nullptr;
TProfile* fT0TrdMeanEvo = nullptr;
TProfile* fT0TofMeanEvo = nullptr;
TProfile* fT0RichMeanEvo = nullptr;
TProfile* fT0PsdMeanEvo = nullptr;
TH1* fT0T0Diff = nullptr;
TProfile* fBmonStsMeanEvo = nullptr;
TProfile* fBmonMuchMeanEvo = nullptr;
TProfile* fBmonTrdMeanEvo = nullptr;
TProfile* fBmonTofMeanEvo = nullptr;
TProfile* fBmonRichMeanEvo = nullptr;
TProfile* fBmonPsdMeanEvo = nullptr;
TH1* fBmonBmonDiff = nullptr;
TH1* fStsStsDiff = nullptr;
TH1* fMuchMuchDiff = nullptr;
TH1* fTrdTrdDiff = nullptr;
......@@ -222,14 +222,14 @@ private:
TH1* fRichRichDiff = nullptr;
TH1* fPsdPsdDiff = nullptr;
TH2* fT0StsNb = nullptr;
TH2* fT0MuchNb = nullptr;
TH2* fT0TrdNb = nullptr;
TH2* fT0TofNb = nullptr;
TH2* fT0RichNb = nullptr;
TH2* fT0PsdNb = nullptr;
TH2* fBmonStsNb = nullptr;
TH2* fBmonMuchNb = nullptr;
TH2* fBmonTrdNb = nullptr;
TH2* fBmonTofNb = nullptr;
TH2* fBmonRichNb = nullptr;
TH2* fBmonPsdNb = nullptr;
Int_t fiT0Nb = 0;
Int_t fiBmonNb = 0;
Int_t fiStsNb = 0;
Int_t fiMuchNb = 0;
Int_t fiTrdNb = 0;
......@@ -237,36 +237,29 @@ private:
Int_t fiRichNb = 0;
Int_t fiPsdNb = 0;
TH1* fT0Address = nullptr;
TH1* fT0Channel = nullptr;
TH1* fBmonAddress = nullptr;
TH1* fBmonChannel = nullptr;
TH2* fT0StsDpbDiff = nullptr;
TH2* fT0StsDpbDiffEvo[kuMaxNbStsDpbs];
TH2* fBmonStsDpbDiff = nullptr;
TH2* fBmonStsDpbDiffEvo[kuMaxNbStsDpbs];
TH1* fStsDpbCntsEvo[kuMaxNbStsDpbs];
TH2* fT0MuchRocDiff = nullptr;
TH2* fT0MuchAsicDiff = nullptr;
TH2* fT0MuchAsicDiffEvo[kuMaxNbMuchAsics];
TH2* fBmonMuchRocDiff = nullptr;
TH2* fBmonMuchAsicDiff = nullptr;
TH2* fBmonMuchAsicDiffEvo[kuMaxNbMuchAsics];
TH2* fDigisPerAsicEvo = nullptr;
Double_t fdLastMuchDigi[kuMaxNbMuchAsics][kuNbChanSMX];
Double_t fdLastMuchDigiPulser[kuMaxNbMuchAsics][kuNbChanSMX];
TH2* fSameChanDigisDistEvo = nullptr;
Double_t fdLastT0DigiPulser = 0;
Double_t fdLastBmonDigiPulser = 0;
TH2* fDigiTimeEvoT0 = nullptr;
TH2* fDigiTimeEvoBmon = 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_ */
......@@ -49,7 +49,7 @@ struct InitTaskError : std::runtime_error {
using namespace std;
Bool_t bMcbm2018MonitorTaskT0ResetHistos = kFALSE;
Bool_t bMcbm2018MonitorTaskBmonResetHistos = kFALSE;
CbmDeviceMcbmUnpack::CbmDeviceMcbmUnpack()
{
......@@ -69,7 +69,7 @@ try {
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 !!!!
/// TODO: option to set fuDigiMaskedIdBmon !!!!
fsAllowedChannels[0] = fsChannelNameDataInput;
// Get the information about created channels from the device
......@@ -219,7 +219,7 @@ Bool_t CbmDeviceMcbmUnpack::InitParameters(TList* fParCList)
if (Send(req, "parameters") > 0) {
if (Receive(rep, "parameters") >= 0) {
if (0 != rep->GetSize()) {
CbmMQTMessage tmsg(rep->GetData(), 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();
......@@ -305,7 +305,8 @@ bool CbmDeviceMcbmUnpack::SendUnpData()
std::string* strMsgTsMetaE = new std::string(ossTsMeta.str());
*/
FairMQMessagePtr messTsMeta(NewMessage());
Serialize<RootSerializer>(*messTsMeta, fTsMetaData);
// Serialize<RootSerializer>(*messTsMeta, fTsMetaData);
RootSerializer().Serialize(*messTsMeta, fTsMetaData);
std::stringstream ossSts;
boost::archive::binary_oarchive oaSts(ossSts);
......@@ -322,20 +323,20 @@ bool CbmDeviceMcbmUnpack::SendUnpData()
oaTrd << fUnpAlgoTrd->GetVector();
std::string* strMsgTrd = new std::string(ossTrd.str());
/// Split TOF vector in TOF and T0
std::vector<CbmTofDigi>& vDigiTofT0 = fUnpAlgoTof->GetVector();
/// Split TOF vector in TOF and Bmon
std::vector<CbmTofDigi>& vDigiTofBmon = fUnpAlgoTof->GetVector();
std::vector<CbmTofDigi> vDigiTof = {};
std::vector<CbmTofDigi> vDigiT0 = {};
std::vector<CbmTofDigi> vDigiBmon = {};
for (auto digi : vDigiTofT0) {
if (fuDigiMaskedIdT0 == (digi.GetAddress() & fuDigiMaskId)) {
/// Insert data in T0 output container
vDigiT0.emplace_back(digi);
} // if( fuDigiMaskedIdT0 == ( digi.GetAddress() & fuDigiMaskId ) )
for (auto digi : vDigiTofBmon) {
if (fuDigiMaskedIdBmon == (digi.GetAddress() & fuDigiMaskId)) {
/// Insert data in Bmon output container
vDigiBmon.emplace_back(digi);
} // if( fuDigiMaskedIdBmon == ( digi.GetAddress() & fuDigiMaskId ) )
else {
/// Insert data in TOF output container
vDigiTof.emplace_back(digi);
} // else of if( fuDigiMaskedIdT0 == ( digi.GetAddress() & fuDigiMaskId ) )
} // else of if( fuDigiMaskedIdBmon == ( digi.GetAddress() & fuDigiMaskId ) )
} // for( auto digi: vDigi )
std::stringstream ossTof;
......@@ -343,10 +344,10 @@ bool CbmDeviceMcbmUnpack::SendUnpData()
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 ossBmon;
boost::archive::binary_oarchive oaBmon(ossBmon);
oaBmon << vDigiBmon;
std::string* strMsgBmon = new std::string(ossBmon.str());
std::stringstream ossRich;
boost::archive::binary_oarchive oaRich(ossRich);
......@@ -371,10 +372,10 @@ bool CbmDeviceMcbmUnpack::SendUnpData()
*/
parts.AddPart(NewMessage(
const_cast<char*>(strMsgT0->c_str()), // data
strMsgT0->length(), // size
const_cast<char*>(strMsgBmon->c_str()), // data
strMsgBmon->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgT0)); // object that manages the data
strMsgBmon)); // object that manages the data
parts.AddPart(NewMessage(
const_cast<char*>(strMsgSts->c_str()), // data
......@@ -455,10 +456,10 @@ Bool_t CbmDeviceMcbmUnpack::DoUnpack(const fles::Timeslice& ts, size_t /*compone
fUnpAlgoTof->AddMsComponentToList(uCompIdx, kusSysIdTof);
break;
} // case kusSysIdTof
case kusSysIdT0: {
fUnpAlgoTof->AddMsComponentToList(uCompIdx, kusSysIdT0);
case kusSysIdBmon: {
fUnpAlgoTof->AddMsComponentToList(uCompIdx, kusSysIdBmon);
break;
} // case kusSysIdT0
} // case kusSysIdBmon
case kusSysIdRich: {
fUnpAlgoRich->AddMsComponentToList(uCompIdx, kusSysIdRich);
break;
......@@ -475,32 +476,32 @@ Bool_t CbmDeviceMcbmUnpack::DoUnpack(const fles::Timeslice& ts, size_t /*compone
if (kFALSE == fUnpAlgoSts->ProcessTs(ts)) {
LOG(error) << "Failed processing TS " << ts.index() << " in STS unpacker algorithm class";
return kTRUE;
return kFALSE;
} // if( kFALSE == fUnpAlgoSts->ProcessTs( ts ) )
if (kFALSE == fUnpAlgoMuch->ProcessTs(ts)) {
LOG(error) << "Failed processing TS " << ts.index() << " in MUCH unpacker algorithm class";
return kTRUE;
return kFALSE;
} // if( kFALSE == fUnpAlgoMuch->ProcessTs( ts ) )
if (kFALSE == fUnpAlgoTrd->ProcessTs(ts)) {
LOG(error) << "Failed processing TS " << ts.index() << " in TRD unpacker algorithm class";
return kTRUE;
return kFALSE;
} // if( kFALSE == fUnpAlgoTrd->ProcessTs( ts ) )
if (kFALSE == fUnpAlgoTof->ProcessTs(ts)) {
LOG(error) << "Failed processing TS " << ts.index() << " in TOF unpacker algorithm class";
return kTRUE;
return kFALSE;
} // if( kFALSE == fUnpAlgoTof->ProcessTs( ts ) )
if (kFALSE == fUnpAlgoRich->ProcessTs(ts)) {
LOG(error) << "Failed processing TS " << ts.index() << " in RICH unpacker algorithm class";
return kTRUE;
return kFALSE;
} // if( kFALSE == fUnpAlgoRich->ProcessTs( ts ) )
if (kFALSE == fUnpAlgoPsd->ProcessTs(ts)) {
LOG(error) << "Failed processing TS " << ts.index() << " in PSD unpacker algorithm class";
return kTRUE;
return kFALSE;
} // if( kFALSE == fUnpAlgoPsd->ProcessTs( ts ) )
......
......@@ -12,12 +12,13 @@
#ifndef CBMDEVICEMCBMUNPACK_H_
#define CBMDEVICEMCBMUNPACK_H_
#include "CbmMqTMessage.h"
#include "Timeslice.hpp"
#include "FairMQDevice.h"
#include "Rtypes.h"
#include "TMessage.h"
#include "TObjArray.h"
#include <map>
......@@ -48,7 +49,7 @@ private:
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 kusSysIdBmon = 0x90;
static const uint16_t kusSysIdRich = 0x30;
static const uint16_t kusSysIdPsd = 0x80;
......@@ -60,7 +61,7 @@ private:
std::string fsChannelNameDataInput = "fullts";
std::string fsChannelNameDataOutput = "unpts_0";
std::string fsChannelNameCommands = "commands";
UInt_t fuDigiMaskedIdT0 = 0x00005006;
UInt_t fuDigiMaskedIdBmon = 0x00005006;
UInt_t fuDigiMaskId = 0x0001FFFF;
/// List of MQ channels names
......@@ -101,11 +102,4 @@ private:
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_ */
/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceUnpack.cxx
*
* @since 2020-05-04
* @author P.-A. Loizeau
*/
#include "CbmDeviceUnpack.h"
#include "CbmBmonUnpackConfig.h"
#include "CbmFlesCanvasTools.h"
#include "CbmMQDefs.h"
#include "CbmMuchUnpackConfig.h"
#include "CbmPsdUnpackConfig.h"
#include "CbmRichUnpackConfig.h"
#include "CbmSetup.h"
#include "CbmStsUnpackConfig.h"
#include "CbmTofUnpackConfig.h"
#include "CbmTrdUnpackConfig.h"
#include "CbmTrdUnpackFaspConfig.h"
#include "StorableTimeslice.hpp"
#include "TimesliceMetaData.h"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairParGenericSet.h"
#include "TCanvas.h"
#include "TFile.h"
#include "TH1.h"
#include "TList.h"
#include "TNamed.h"
#include "BoostSerializer.h"
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/utility.hpp>
#include <array>
#include <iomanip>
#include <stdexcept>
#include <string>
#include <utility>
#include "RootSerializer.h"
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
using namespace std;
//Bool_t bMcbm2018MonitorTaskBmonResetHistos = kFALSE;
CbmDeviceUnpack::CbmDeviceUnpack() {}
void CbmDeviceUnpack::InitTask()
try {
/// Read options from executable
LOG(info) << "Init options for CbmDeviceUnpack.";
fsSetupName = fConfig->GetValue<std::string>("Setup");
fuRunId = fConfig->GetValue<uint32_t>("RunId");
fbUnpBmon = fConfig->GetValue<bool>("UnpBmon");
fbUnpSts = fConfig->GetValue<bool>("UnpSts");
fbUnpMuch = fConfig->GetValue<bool>("UnpMuch");
fbUnpTrd1D = fConfig->GetValue<bool>("UnpTrd1d");
fbUnpTrd2D = fConfig->GetValue<bool>("UnpTrd2d");
fbUnpTof = fConfig->GetValue<bool>("UnpTof");
fbUnpRich = fConfig->GetValue<bool>("UnpRich");
fbUnpPsd = fConfig->GetValue<bool>("UnpPsd");
fbIgnoreOverlapMs = fConfig->GetValue<bool>("IgnOverMs");
fbOutputFullTimeSorting = fConfig->GetValue<bool>("FullTimeSort");
fvsSetTimeOffs = fConfig->GetValue<std::vector<std::string>>("SetTimeOffs");
fsChannelNameDataInput = fConfig->GetValue<std::string>("TsNameIn");
fsChannelNameDataOutput = fConfig->GetValue<std::string>("TsNameOut");
fuPublishFreqTs = fConfig->GetValue<uint32_t>("PubFreqTs");
fdMinPublishTime = fConfig->GetValue<double_t>("PubTimeMin");
fdMaxPublishTime = fConfig->GetValue<double_t>("PubTimeMax");
fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
}
Bool_t CbmDeviceUnpack::InitContainers()
{
LOG(info) << "Init parameter containers for CbmDeviceUnpack.";
// ----- FIXME: Environment settings? or binary option?
TString srcDir = std::getenv("VMCWORKDIR"); // top source directory, standard C++ library
// TString srcDir = gSystem->Getenv("VMCWORKDIR"); // top source directory
// ----- CbmSetup -----------------------------------------------------
// TODO: support for multiple setups on Par Server? with request containing setup name?
CbmSetup* cbmsetup = CbmSetup::Instance();
FairMQMessagePtr req(NewSimpleMessage("setup"));
FairMQMessagePtr rep(NewMessage());
if (Send(req, "parameters") > 0) {
if (Receive(rep, "parameters") >= 0) {
if (0 != rep->GetSize()) {
CbmSetupStorable* exchangableSetup;
CbmMqTMessage tmsg(rep->GetData(), rep->GetSize());
exchangableSetup = dynamic_cast<CbmSetupStorable*>(tmsg.ReadObject(tmsg.GetClass()));
if (nullptr != exchangableSetup) {
/// Prevent clang format single line if
cbmsetup->LoadStoredSetup(exchangableSetup);
}
else {
LOG(error) << "Received corrupt reply. Setup not available";
throw InitTaskError("Setup not received from par-server.");
}
} // if( 0 != rep->GetSize() )
else {
LOG(error) << "Received empty reply. Setup not available";
throw InitTaskError("Setup not received from par-server.");
} // else of if( 0 != rep->GetSize() )
} // if( Receive( rep, "parameters" ) >= 0)
} // if( Send(req, "parameters") > 0 )
// ------------------------------------------------------------------------
/// Initialize the UnpackerConfigs objects and their "user options"
// ---- BMON ----
std::shared_ptr<CbmBmonUnpackConfig> bmonconfig = nullptr;
if (fbUnpBmon) {
bmonconfig = std::make_shared<CbmBmonUnpackConfig>("", fuRunId);
if (bmonconfig) {
// bmonconfig->SetDebugState();
bmonconfig->SetDoWriteOutput();
// bmonconfig->SetDoWriteOptOutA("CbmBmonErrors");
std::string parfilesbasepathBmon = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
bmonconfig->SetParFilesBasePath(parfilesbasepathBmon);
bmonconfig->SetParFileName("mBmonCriPar.par");
bmonconfig->SetSystemTimeOffset(-1220); // [ns] value to be updated
if (2160 <= fuRunId) {
bmonconfig->SetSystemTimeOffset(-80); // [ns] value to be updated
}
if (2350 <= fuRunId) {
bmonconfig->SetSystemTimeOffset(0); // [ns] value to be updated
}
/// Enable Monitor plots
// bmonconfig->SetMonitor(GetTofMonitor(outfilename, true)); // FIXME: Unsupported for now
}
}
// -------------
// ---- STS ----
std::shared_ptr<CbmStsUnpackConfig> stsconfig = nullptr;
TString stsSetupTag = "";
cbmsetup->GetGeoTag(ECbmModuleId::kSts, stsSetupTag);
if ("" != stsSetupTag && fbUnpSts) {
LOG(info) << "From received setup, using STS tag: " << stsSetupTag;
stsconfig = std::make_shared<CbmStsUnpackConfig>(std::string(fsSetupName), fuRunId);
if (stsconfig) {
// stsconfig->SetDebugState();
stsconfig->SetDoWriteOutput();
stsconfig->SetDoWriteOptOutA("StsDigiPulser");
std::string parfilesbasepathSts = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data());
if (2060 <= fuRunId) {
/// Starting to readout the U3 since 10/03/2022 Carbon run
parfilesbasepathSts = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
}
stsconfig->SetParFilesBasePath(parfilesbasepathSts);
/// Enable duplicates rejection, Ignores the ADC for duplicates check
stsconfig->SetDuplicatesRejection(true, true);
/// Enable Monitor plots
// stsconfig->SetMonitor(GetStsMonitor(outfilename, true)); // FIXME: Unsupported for now
stsconfig->SetSystemTimeOffset(-2221); // [ns] value to be updated
if (2160 <= fuRunId) {
stsconfig->SetSystemTimeOffset(-1075); // [ns] value to be updated
}
if (2350 <= fuRunId) {
stsconfig->SetSystemTimeOffset(-970); // [ns] value to be updated
}
stsconfig->SetMinAdcCut(1, 1);
stsconfig->SetMinAdcCut(2, 1);
stsconfig->SetMinAdcCut(3, 1);
stsconfig->SetMinAdcCut(4, 1);
stsconfig->MaskNoisyChannel(3, 56);
stsconfig->MaskNoisyChannel(3, 75);
stsconfig->MaskNoisyChannel(3, 79);
stsconfig->MaskNoisyChannel(3, 85);
stsconfig->MaskNoisyChannel(7, 123);
stsconfig->MaskNoisyChannel(7, 124);
stsconfig->MaskNoisyChannel(7, 125);
stsconfig->MaskNoisyChannel(7, 158);
stsconfig->MaskNoisyChannel(7, 159);
stsconfig->MaskNoisyChannel(7, 162);
stsconfig->MaskNoisyChannel(7, 715);
stsconfig->MaskNoisyChannel(9, 709);
stsconfig->MaskNoisyChannel(12, 119);
// Time Walk correction
std::map<uint32_t, CbmStsParModule> walkMap;
auto parAsic = new CbmStsParAsic(128, 31, 31., 1., 5., 800., 1000., 3.9789e-3);
// Module params: number of channels, number of channels per ASIC
auto parMod = new CbmStsParModule(2048, 128);
// default
double p0 = 0, p1 = 0, p2 = 0, p3 = 0;
parAsic->SetWalkCoef({p0, p1, p2, p3});
parMod->SetAllAsics(*parAsic);
walkMap[0x10107C02] = CbmStsParModule(*parMod); // Make a copy for storage
walkMap[0x101FFC02] = CbmStsParModule(*parMod); // Make a copy for storage
/// To be replaced by a storage in a new parameter class later
int sensor, asic;
std::ifstream asicTimeWalk_par(Form("%s/mStsAsicTimeWalk.par", parfilesbasepathSts.data()));
while (asicTimeWalk_par >> std::hex >> sensor >> std::dec >> asic >> p0 >> p1 >> p2 >> p3) {
std::cout << Form("Setting time-walk parametersfor: module %x, ASIC %u\n", sensor, asic);
parAsic->SetWalkCoef({p0, p1, p2, p3});
if (walkMap.find(sensor) == walkMap.end()) { walkMap[sensor] = CbmStsParModule(*parMod); }
walkMap[sensor].SetAsic(asic, *parAsic);
}
stsconfig->SetWalkMap(walkMap);
}
} // if ("" != stsSetupTag)
// -------------
// ---- MUCH ----
std::shared_ptr<CbmMuchUnpackConfig> muchconfig = nullptr;
TString muchSetupTag = "";
cbmsetup->GetGeoTag(ECbmModuleId::kMuch, muchSetupTag);
if ("" != muchSetupTag && fbUnpMuch) {
LOG(info) << "From received setup, using MUCH tag: " << muchSetupTag;
muchconfig = std::make_shared<CbmMuchUnpackConfig>(std::string(fsSetupName), fuRunId);
if (muchconfig) {
// muchconfig->SetDebugState();
muchconfig->SetDoWriteOutput();
muchconfig->SetDoWriteOptOutA("MuchDigiPulser");
std::string parfilesbasepathMuch = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
muchconfig->SetParFilesBasePath(parfilesbasepathMuch);
if (2060 <= fuRunId && fuRunId <= 2162) {
/// Starting to use CRI Based MUCH setup with 2GEM and 1 RPC since 09/03/2022 Carbon run
muchconfig->SetParFileName("mMuchParUpto26032022.par");
}
else if (2163 <= fuRunId && fuRunId <= 2291) {
/// First nickel runs
muchconfig->SetParFileName("mMuchParUpto03042022.par");
}
else if (2311 <= fuRunId && fuRunId <= 2315) {
///
muchconfig->SetParFileName("mMuchParUpto10042022.par");
}
else if (2316 <= fuRunId && fuRunId <= 2366) {
///
muchconfig->SetParFileName("mMuchParUpto23052022.par");
}
else if (2367 <= fuRunId && fuRunId <= 2397) {
/// Starting to use GEM 2 moved to CRI 0 on 24/05/2022
muchconfig->SetParFileName("mMuchParUpto26052022.par");
}
/// Enable duplicates rejection, Ignores the ADC for duplicates check
muchconfig->SetDuplicatesRejection(true, true);
/// Enable Monitor plots
//muchconfig->SetMonitor(GetMuchMonitor(outfilename, true));
muchconfig->SetSystemTimeOffset(-2221); // [ns] value to be updated
if (2160 <= fuRunId) {
muchconfig->SetSystemTimeOffset(-1020); // [ns] value to be updated
}
if (2350 <= fuRunId) {
muchconfig->SetSystemTimeOffset(-980); // [ns] value to be updated
}
// muchconfig->SetMinAdcCut(1, 1);
// muchconfig->MaskNoisyChannel(3, 56);
}
}
// -------------
// ---- TRD ----
std::shared_ptr<CbmTrdUnpackConfig> trd1Dconfig = nullptr;
TString trdsetuptag = "";
cbmsetup->GetGeoTag(ECbmModuleId::kTrd, trdsetuptag);
if ("" != trdsetuptag && fbUnpTrd1D) {
LOG(info) << "From received setup, using TRD tag: " << trdsetuptag;
// trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), fuRunId);
trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), 3);
if (trd1Dconfig) {
trd1Dconfig->SetDoWriteOutput();
// Activate the line below to write Trd1D digis to a separate "TrdSpadicDigi" branch. Can be used to separate between Fasp and Spadic digis
// trd1Dconfig->SetOutputBranchName("TrdSpadicDigi");
// trd1Dconfig->SetDoWriteOptOutA(CbmTrdRawMessageSpadic::GetBranchName());
// trd1Dconfig->SetDoWriteOptOutB("SpadicInfoMessages"); // SpadicInfoMessages
std::string parfilesbasepathTrd = Form("%s/parameters/trd", srcDir.Data());
trd1Dconfig->SetParFilesBasePath(parfilesbasepathTrd);
// trd1Dconfig->SetMonitor(GetTrdMonitor(outfilename)); // FIXME: Unsupported for now
// Get the spadic configuration true = avg baseline active / false plain sample 0
trd1Dconfig->SetSpadicObject(GetTrdSpadic(true));
trd1Dconfig->SetSystemTimeOffset(0); // [ns] value to be updated
if (2160 <= fuRunId) {
trd1Dconfig->SetSystemTimeOffset(1140); // [ns] value to be updated
}
if (2350 <= fuRunId) {
trd1Dconfig->SetSystemTimeOffset(1300); // [ns] value to be updated
}
}
} // if ("" != trdsetuptag)
// -------------
// ---- TRDFASP2D ----
std::shared_ptr<CbmTrdUnpackFaspConfig> trdfasp2dconfig = nullptr;
if ("" != trdsetuptag && fbUnpTrd2D) {
trdfasp2dconfig = std::make_shared<CbmTrdUnpackFaspConfig>(trdsetuptag.Data());
if (trdfasp2dconfig) {
// trdfasp2dconfig->SetDebugState();
trdfasp2dconfig->SetDoWriteOutput();
// Activate the line below to write Trd1D digis to a separate "TrdFaspDigi" branch. Can be used to separate between Fasp and Spadic digis
//trdfasp2dconfig->SetOutputBranchName("TrdFaspDigi");
// uint16_t crob_map[NCROBMOD];
// if (fuRunId <= 1588) {
// uint16_t crob_map21[] = {0x00f0, 0, 0, 0, 0};
// for (uint32_t i(0); i < NCROBMOD; i++)
// crob_map[i] = crob_map21[i];
// }
// else if (fuRunId >= 2335) {
// uint16_t crob_map22[] = {0xffc2, 0xffc5, 0xffc1, 0, 0};
// for (uint32_t i(0); i < NCROBMOD; i++)
// crob_map[i] = crob_map22[i];
// }
// trdfasp2dconfig->SetCrobMapping(5, crob_map);
std::string parfilesbasepathTrdfasp2d = Form("%s/parameters/trd", srcDir.Data());
trdfasp2dconfig->SetParFilesBasePath(parfilesbasepathTrdfasp2d);
trdfasp2dconfig->SetSystemTimeOffset(-1800); // [ns] value to be updated
if (2160 <= fuRunId) {
trdfasp2dconfig->SetSystemTimeOffset(-570); // [ns] value to be updated
}
if (2350 <= fuRunId) {
trdfasp2dconfig->SetSystemTimeOffset(-510); // [ns] value to be updated
}
}
} // if ("" != trdsetuptag)
// -------------
// ---- TOF ----
std::shared_ptr<CbmTofUnpackConfig> tofconfig = nullptr;
TString tofSetupTag = "";
cbmsetup->GetGeoTag(ECbmModuleId::kTof, tofSetupTag);
if ("" != tofSetupTag && fbUnpTof) {
LOG(info) << "From received setup, using TOF tag: " << tofSetupTag;
tofconfig = std::make_shared<CbmTofUnpackConfig>("", fuRunId);
if (tofconfig) {
// tofconfig->SetDebugState();
tofconfig->SetDoWriteOutput();
// tofconfig->SetDoWriteOptOutA("CbmTofErrors");
std::string parfilesbasepathTof = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data());
std::string parFileNameTof = "mTofCriPar.par";
if (2060 <= fuRunId) {
/// Additional modules added just before the 10/03/2022 Carbon run
parfilesbasepathTof = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
/// Setup changed multiple times between the 2022 carbon and uranium runs
if (fuRunId <= 2065) {
/// Carbon runs: 2060 - 2065
parFileNameTof = "mTofCriParCarbon.par";
}
else if (2150 <= fuRunId && fuRunId <= 2160) {
/// Iron runs: 2150 - 2160
parFileNameTof = "mTofCriParIron.par";
}
else if (2176 <= fuRunId && fuRunId <= 2310) {
/// Uranium runs: 2176 - 2310
parFileNameTof = "mTofCriParUranium.par";
}
else if (2335 <= fuRunId && fuRunId <= 2497) {
/// Nickel runs: 2335 - 2397
/// Gold runs: 2400 - 2497
parFileNameTof = "mTofCriParNickel.par";
}
else {
parFileNameTof = "mTofCriPar.par";
}
}
tofconfig->SetParFilesBasePath(parfilesbasepathTof);
tofconfig->SetParFileName(parFileNameTof);
tofconfig->SetSystemTimeOffset(-1220); // [ns] value to be updated
if (2160 <= fuRunId) {
tofconfig->SetSystemTimeOffset(0); // [ns] value to be updated
}
if (2350 <= fuRunId) {
tofconfig->SetSystemTimeOffset(45); // [ns] value to be updated
}
if (fuRunId <= 1659) {
/// Switch ON the -4 offset in epoch count (hack for Spring-Summer 2021)
tofconfig->SetFlagEpochCountHack2021();
}
}
} // if ("" != tofSetupTag)
// -------------
// ---- RICH ----
std::shared_ptr<CbmRichUnpackConfig> richconfig = nullptr;
TString richSetupTag = "";
cbmsetup->GetGeoTag(ECbmModuleId::kRich, richSetupTag);
if ("" != richSetupTag && fbUnpRich) {
LOG(info) << "From received setup, using RICH tag: " << richSetupTag;
richconfig = std::make_shared<CbmRichUnpackConfig>("", fuRunId);
if (richconfig) {
if (1904 < fuRunId) {
/// Switch to new unpacking algo starting from first combined cosmics run in 2022
richconfig->SetUnpackerVersion(CbmRichUnpackerVersion::v03);
}
richconfig->DoTotOffsetCorrection(); // correct ToT offset
richconfig->SetDebugState();
richconfig->SetDoWriteOutput();
std::string parfilesbasepathRich = Form("%s/macro/beamtime/mcbm2024/", srcDir.Data());
richconfig->SetParFilesBasePath(parfilesbasepathRich);
richconfig->SetSystemTimeOffset(256000 - 1200); // [ns] 1 MS and additional correction
if (1904 < fuRunId) richconfig->SetSystemTimeOffset(-1200);
if (2160 <= fuRunId) {
richconfig->SetSystemTimeOffset(50); // [ns] value to be updated
}
if (2350 <= fuRunId) {
richconfig->SetSystemTimeOffset(100); // [ns] value to be updated
}
if (1588 == fuRunId) richconfig->MaskDiRICH(0x7150);
}
} // if ("" != richSetupTag)
// -------------
// ---- PSD ----
std::shared_ptr<CbmPsdUnpackConfig> psdconfig = nullptr;
TString psdSetupTag = "";
cbmsetup->GetGeoTag(ECbmModuleId::kPsd, psdSetupTag);
if ("" != psdSetupTag && fbUnpPsd) {
LOG(info) << "From received setup, using PSD tag: " << psdSetupTag;
psdconfig = std::make_shared<CbmPsdUnpackConfig>("", fuRunId);
if (psdconfig) {
// psdconfig->SetDebugState();
psdconfig->SetDoWriteOutput();
// psdconfig->SetDoWriteOptOutA("CbmPsdDsp");
std::string parfilesbasepathPsd = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data());
psdconfig->SetParFilesBasePath(parfilesbasepathPsd);
psdconfig->SetSystemTimeOffset(0); // [ns] value to be updated
}
} // if ("" != psdSetupTag)
// -------------
/// Enable full time sorting instead of time sorting per FLIM link
if (stsconfig) SetUnpackConfig(stsconfig);
if (muchconfig) SetUnpackConfig(muchconfig);
if (trd1Dconfig) SetUnpackConfig(trd1Dconfig);
if (trdfasp2dconfig) SetUnpackConfig(trdfasp2dconfig);
if (tofconfig) SetUnpackConfig(tofconfig);
if (bmonconfig) SetUnpackConfig(bmonconfig);
if (richconfig) SetUnpackConfig(richconfig);
if (psdconfig) SetUnpackConfig(psdconfig);
/// Load time offsets
for (std::vector<std::string>::iterator itStrOffs = fvsSetTimeOffs.begin(); itStrOffs != fvsSetTimeOffs.end();
++itStrOffs) {
size_t charPosDel = (*itStrOffs).find(',');
if (std::string::npos == charPosDel) {
LOG(info) << "CbmDeviceUnpack::InitContainers => "
<< "Trying to set trigger window with invalid option pattern, ignored! "
<< " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found " << (*itStrOffs) << " )";
} // if( std::string::npos == charPosDel )
/// Detector Enum Tag
std::string sSelDet = (*itStrOffs).substr(0, charPosDel);
/// Min number
charPosDel++;
int32_t iOffset = std::stoi((*itStrOffs).substr(charPosDel));
if ("kBmon" == sSelDet && fBmonConfig) { //
fBmonConfig->SetSystemTimeOffset(iOffset);
} // else if( "kBmon" == sSelDet )
else if ("kSTS" == sSelDet && fStsConfig) { //
fStsConfig->SetSystemTimeOffset(iOffset);
} // if( "kSTS" == sSelDet && fStsConfig)
else if ("kMUCH" == sSelDet && fMuchConfig) {
fMuchConfig->SetSystemTimeOffset(iOffset);
} // else if( "kMUCH" == sSelDet )
else if ("kTRD" == sSelDet && fTrd1DConfig) {
fTrd1DConfig->SetSystemTimeOffset(iOffset);
} // else if( "kTRD" == sSelDet && fTrd2DConfig )
else if ("kTRD2D" == sSelDet && fTrd2DConfig) {
fTrd2DConfig->SetSystemTimeOffset(iOffset);
} // else if( "kTRD" == sSelDet && fTrd2DConfig )
else if ("kTOF" == sSelDet && fTofConfig) {
fTofConfig->SetSystemTimeOffset(iOffset);
} // else if( "kTOF" == sSelDet && fTofConfig)
else if ("kRICH" == sSelDet && fRichConfig) {
fRichConfig->SetSystemTimeOffset(iOffset);
} // else if( "kRICH" == sSelDet && fRichConfig)
else if ("kPSD" == sSelDet && fPsdConfig) {
fPsdConfig->SetSystemTimeOffset(iOffset);
} // else if( "kPSD" == sSelDet )
else {
LOG(info) << "CbmDeviceUnpack::InitContainers => Trying to set time "
"offset for unsupported detector, ignored! "
<< (sSelDet);
continue;
} // else of detector enum detection
} // for( std::vector< std::string >::iterator itStrAdd = fvsAddDet.begin(); itStrAdd != fvsAddDet.end(); ++itStrAdd )
Bool_t initOK = kTRUE;
// --- Sts
if (fStsConfig) {
fStsConfig->InitOutput();
// RegisterOutputs( ioman, fStsConfig ); /// Framework bound work = kept in this Task
fStsConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
fStsConfig->SetAlgo();
initOK &= InitParameters(fStsConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fStsConfig->InitAlgo();
// initPerformanceMaps(fkFlesSts, "STS");
}
// --- Much
if (fMuchConfig) {
fMuchConfig->InitOutput();
// RegisterOutputs(ioman, fMuchConfig); /// Framework bound work = kept in this Task
fMuchConfig->SetAlgo();
initOK &= InitParameters(fMuchConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fMuchConfig->InitAlgo();
// initPerformanceMaps(fkFlesMuch, "MUCH");
}
// --- Trd
if (fTrd1DConfig) {
fTrd1DConfig->InitOutput();
// RegisterOutputs( ioman, fTrd1DConfig ); /// Framework bound work = kept in this Task
fTrd1DConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
fTrd1DConfig->SetAlgo();
initOK &= InitParameters(fTrd1DConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fTrd1DConfig->InitAlgo();
// initPerformanceMaps(fkFlesTrd, "TRD1D");
}
// --- TRD2D
if (fTrd2DConfig) {
if (fTrd1DConfig && (fTrd2DConfig->GetOutputBranchName() == fTrd1DConfig->GetOutputBranchName())) {
LOG(info) << fTrd2DConfig->GetName() << "::Init() ---------------------------------";
fTrd2DConfig->SetOutputVec(fTrd1DConfig->GetOutputVec());
}
else {
fTrd2DConfig->InitOutput();
// RegisterOutputs( ioman, fTrd2DConfig ); /// Framework bound work = kept in this Task
}
fTrd2DConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
fTrd2DConfig->SetAlgo();
initOK &= InitParameters(fTrd2DConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fTrd2DConfig->InitAlgo();
// initPerformanceMaps(fkFlesTrd2D, "TRD2D");
}
// This is an ugly work around, because the TRD and TRD2D want to access the same vector and there is no
// function to retrieve a writeable vector<obj> from the FairRootManager, especially before the branches
// are created, as far as I am aware.
// The second option workaround is in in Init() to look for the fasp config and create a separate branch
// for fasp created CbmTrdDigis PR 072021
// --- Tof
if (fTofConfig) {
fTofConfig->InitOutput();
// RegisterOutputs( ioman, fTofConfig ); /// Framework bound work = kept in this Task
fTofConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
fTofConfig->SetAlgo();
initOK &= InitParameters(fTofConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
LOG(info) << "TOF call InitAlgo()";
fTofConfig->InitAlgo();
// initPerformanceMaps(fkFlesTof, "TOF");
}
// --- Bmon
if (fBmonConfig) {
fBmonConfig->InitOutput();
// RegisterOutputs(ioman, fBmonConfig); /// Framework bound work = kept in this Task
fBmonConfig->SetAlgo();
fBmonConfig->LoadParFileName(); /// Needed to change the Parameter file name before it is used!!!
initOK &= InitParameters(fBmonConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fBmonConfig->InitAlgo();
// initPerformanceMaps(fkFlesBmon, "Bmon");
}
// --- Rich
if (fRichConfig) {
fRichConfig->InitOutput();
// RegisterOutputs( ioman, fRichConfig ); /// Framework bound work = kept in this Task
fRichConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
fRichConfig->SetAlgo();
initOK &= InitParameters(fRichConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fRichConfig->InitAlgo();
// initPerformanceMaps(fkFlesRich, "RICH");
}
// --- Psd
if (fPsdConfig) {
fPsdConfig->InitOutput();
// RegisterOutputs( ioman, fPsdConfig ); /// Framework bound work = kept in this Task
fPsdConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
fPsdConfig->SetAlgo();
initOK &= InitParameters(fPsdConfig->GetParContainerRequest()); /// Framework bound work = kept in this Device
fPsdConfig->InitAlgo();
// initPerformanceMaps(fkFlesPsd, "PSD");
}
/// Event header object
fCbmTsEventHeader = new CbmTsEventHeader();
return initOK;
}
Bool_t
CbmDeviceUnpack::InitParameters(std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* reqparvec)
{
LOG(info) << "CbmDeviceUnpack::InitParameters";
if (!reqparvec) {
LOG(info) << "CbmDeviceUnpack::InitParameters - empty requirements vector no parameters initialized.";
return kTRUE;
}
// Now get the actual ascii files and init the containers with the asciiIo
for (auto& pair : *reqparvec) {
/*
auto filepath = pair.first;
auto parset = pair.second;
FairParAsciiFileIo asciiInput;
if (!filepath.empty()) {
if (asciiInput.open(filepath.data())) { parset->init(&asciiInput); }
}
* */
std::string paramName {pair.second->GetName()};
// NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
// Should only be used for small data because of the cost of an additional copy
// Here must come the proper Runid
std::string message = paramName + ",111";
LOG(info) << "Requesting parameter container " << paramName << ", sending message: " << message;
FairMQMessagePtr req(NewSimpleMessage(message));
FairMQMessagePtr rep(NewMessage());
FairParGenericSet* newObj = nullptr;
if (Send(req, "parameters") > 0) {
if (Receive(rep, "parameters") >= 0) {
if (0 != rep->GetSize()) {
CbmMqTMessage tmsg(rep->GetData(), rep->GetSize());
newObj = static_cast<FairParGenericSet*>(tmsg.ReadObject(tmsg.GetClass()));
LOG(info) << "Received unpack parameter from the server: " << newObj->GetName();
newObj->print();
} // if( 0 != rep->GetSize() )
else {
LOG(error) << "Received empty reply. Parameter not available";
return kFALSE;
} // else of if( 0 != rep->GetSize() )
} // if( Receive( rep, "parameters" ) >= 0)
} // if( Send(req, "parameters") > 0 )
pair.second.reset(newObj); /// Potentially unsafe reasignment of raw pointer to the shared pointer?
//delete newObj;
}
return kTRUE;
}
bool CbmDeviceUnpack::InitHistograms()
{
/// Histos creation and obtain pointer on them
/// Trigger histo creation on all associated algos
// ALGO: bool initOK = fMonitorAlgo->CreateHistograms();
bool initOK = true;
/// Obtain vector of pointers on each histo from the algo (+ optionally desired folder)
// ALGO: std::vector<std::pair<TNamed*, std::string>> vHistos = fMonitorAlgo->GetHistoVector();
std::vector<std::pair<TNamed*, std::string>> vHistos = {};
/// Obtain vector of pointers on each canvas from the algo (+ optionally desired folder)
// ALGO: std::vector<std::pair<TCanvas*, std::string>> vCanvases = fMonitorAlgo->GetCanvasVector();
std::vector<std::pair<TCanvas*, std::string>> vCanvases = {};
/// Add pointers to each histo in the histo array
/// Create histo config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Histo name, Folder >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto) {
// LOG(info) << "Registering " << vHistos[ uHisto ].first->GetName()
// << " in " << vHistos[ uHisto ].second.data()
// ;
fArrayHisto.Add(vHistos[uHisto].first);
std::pair<std::string, std::string> psHistoConfig(vHistos[uHisto].first->GetName(), vHistos[uHisto].second);
fvpsHistosFolder.push_back(psHistoConfig);
LOG(info) << "Config of hist " << psHistoConfig.first.data() << " in folder " << psHistoConfig.second.data();
} // for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto )
/// Create canvas config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Canvas name, config >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv) {
// LOG(info) << "Registering " << vCanvases[ uCanv ].first->GetName()
// << " in " << vCanvases[ uCanv ].second.data();
std::string sCanvName = (vCanvases[uCanv].first)->GetName();
std::string sCanvConf = GenerateCanvasConfigString(vCanvases[uCanv].first);
std::pair<std::string, std::string> psCanvConfig(sCanvName, sCanvConf);
fvpsCanvasConfig.push_back(psCanvConfig);
LOG(info) << "Config string of Canvas " << psCanvConfig.first.data() << " is " << psCanvConfig.second.data();
} // for( UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv )
return initOK;
}
// Method called by run loop and requesting new data from the TS source whenever
bool CbmDeviceUnpack::ConditionalRun()
{
/// First do Algo related Initialization steps if needed
if (0 == fulNumMessages) {
try {
InitContainers();
}
catch (InitTaskError& e) {
LOG(error) << e.what();
ChangeState(fair::mq::Transition::ErrorFound);
}
} // if( 0 == fulNumMessages)
if (0 == fulNumMessages) InitHistograms();
/// First request a new TS (full one)
std::string message = "full";
LOG(debug) << "Requesting new TS by sending message: full" << message;
FairMQMessagePtr req(NewSimpleMessage(message));
FairMQMessagePtr rep(NewMessage());
if (Send(req, fsChannelNameDataInput) <= 0) {
LOG(error) << "Failed to send the request! message was " << message;
return false;
} // if (Send(req, fsChannelNameDataInput) <= 0)
else if (Receive(rep, fsChannelNameDataInput) < 0) {
LOG(error) << "Failed to receive a reply to the request! message was " << message;
return false;
} // else if (Receive(rep, fsChannelNameDataInput) < 0)
else if (rep->GetSize() == 0) {
LOG(error) << "Received empty reply. Something went wrong with the timeslice generation! message was " << message;
return false;
} // else if (rep->GetSize() == 0)
fulNumMessages++;
LOG(debug) << "Received message number " << fulNumMessages << " with size " << rep->GetSize();
if (0 == fulNumMessages % 10000) LOG(info) << "Received " << fulNumMessages << " messages";
std::string msgStr(static_cast<char*>(rep->GetData()), rep->GetSize());
std::istringstream iss(msgStr);
boost::archive::binary_iarchive inputArchive(iss);
/// Create an empty TS and fill it with the incoming message
fles::StorableTimeslice ts {0};
inputArchive >> ts;
/// On first TS, extract the TS parameters from header (by definition stable over time)
if (-1.0 == fdTsCoreSizeInNs) {
fuNbCoreMsPerTs = ts.num_core_microslices();
fuNbOverMsPerTs = ts.num_microslices(0) - ts.num_core_microslices();
fdMsSizeInNs = (ts.descriptor(0, fuNbCoreMsPerTs).idx - ts.descriptor(0, 0).idx) / fuNbCoreMsPerTs;
fdTsCoreSizeInNs = fdMsSizeInNs * (fuNbCoreMsPerTs);
fdTsOverSizeInNs = fdMsSizeInNs * (fuNbOverMsPerTs);
fdTsFullSizeInNs = fdTsCoreSizeInNs + fdTsOverSizeInNs;
LOG(info) << "Timeslice parameters: each TS has " << fuNbCoreMsPerTs << " Core MS and " << fuNbOverMsPerTs
<< " Overlap MS, for a MS duration of " << fdMsSizeInNs << " ns, a core duration of " << fdTsCoreSizeInNs
<< " ns and a full duration of " << fdTsFullSizeInNs << " ns";
fTsMetaData = new TimesliceMetaData(ts.descriptor(0, 0).idx, fdTsCoreSizeInNs, fdTsOverSizeInNs, ts.index());
} // if( -1.0 == fdTsCoreSizeInNs )
else {
/// Update only the fields changing from TS to TS
fTsMetaData->SetStartTime(ts.descriptor(0, 0).idx);
fTsMetaData->SetIndex(ts.index());
}
/// Process the Timeslice
DoUnpack(ts, 0);
LOG(debug) << "Unpack: Sending TS index " << ts.index();
/// Send digi vectors to ouput
if (!SendUnpData()) return false;
LOG(debug) << "Unpack: Sent TS index " << ts.index();
// Reset the event header for a new timeslice
fCbmTsEventHeader->Reset();
// Reset the unpackers for a new timeslice, e.g. clear the output vectors
// ---- Bmon ----
if (fBmonConfig) fBmonConfig->Reset();
// ---- Sts ----
if (fStsConfig) fStsConfig->Reset();
// ----Much ----
if (fMuchConfig) fMuchConfig->Reset();
// ---- Trd ----
if (fTrd1DConfig) fTrd1DConfig->Reset();
// ---- Trd2D ----
if (fTrd2DConfig) fTrd2DConfig->Reset();
// ---- Tof ----
if (fTofConfig) fTofConfig->Reset();
// ---- Rich ----
if (fRichConfig) fRichConfig->Reset();
// ---- Psd ----
if (fPsdConfig) fPsdConfig->Reset();
/// Send histograms each 100 time slices. Should be each ~1s
/// Use also runtime checker to trigger sending after M s if
/// processing too slow or delay sending if processing too fast
std::chrono::system_clock::time_point currentTime = std::chrono::system_clock::now();
std::chrono::duration<double_t> elapsedSeconds = currentTime - fLastPublishTime;
if ((fdMaxPublishTime < elapsedSeconds.count())
|| (0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count())) {
if (!fbConfigSent) {
// Send the configuration only once per run!
fbConfigSent = SendHistoConfAndData();
} // if( !fbConfigSent )
else
SendHistograms();
fLastPublishTime = std::chrono::system_clock::now();
} // if( ( fdMaxPublishTime < elapsedSeconds.count() ) || ( 0 == fulNumMessages % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count() ) )
return true;
}
bool CbmDeviceUnpack::SendUnpData()
{
FairMQParts parts;
/// Prepare serialized versions of the TS Event header
FairMQMessagePtr messTsHeader(NewMessage());
// Serialize<RootSerializer>(*messTsHeader, fCbmTsEventHeader);
RootSerializer().Serialize(*messTsHeader, fCbmTsEventHeader);
parts.AddPart(std::move(messTsHeader));
// ---- Bmon ----
std::stringstream ossBmon;
boost::archive::binary_oarchive oaBmon(ossBmon);
if (fBmonConfig) { //
oaBmon << *(fBmonConfig->GetOutputVec());
}
else {
oaBmon << (std::vector<CbmBmonDigi>());
}
std::string* strMsgBmon = new std::string(ossBmon.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgBmon->c_str()), // data
strMsgBmon->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgBmon)); // object that manages the data
// ---- Sts ----
std::stringstream ossSts;
boost::archive::binary_oarchive oaSts(ossSts);
if (fStsConfig) { //
oaSts << *(fStsConfig->GetOutputVec());
}
else {
oaSts << (std::vector<CbmStsDigi>());
}
std::string* strMsgSts = new std::string(ossSts.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgSts->c_str()), // data
strMsgSts->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgSts)); // object that manages the data
// ---- Much ----
std::stringstream ossMuch;
boost::archive::binary_oarchive oaMuch(ossMuch);
if (fMuchConfig) { //
oaMuch << *(fMuchConfig->GetOutputVec());
}
else {
oaMuch << (std::vector<CbmMuchDigi>());
}
std::string* strMsgMuch = new std::string(ossMuch.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgMuch->c_str()), // data
strMsgMuch->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgMuch)); // object that manages the data
// ---- Trd ----
std::stringstream ossTrd;
boost::archive::binary_oarchive oaTrd(ossTrd);
if (fTrd1DConfig || fTrd2DConfig) { //
oaTrd << *(fTrd1DConfig ? fTrd1DConfig->GetOutputVec() : fTrd2DConfig->GetOutputVec());
}
else {
oaTrd << (std::vector<CbmTrdDigi>());
}
std::string* strMsgTrd = new std::string(ossTrd.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgTrd->c_str()), // data
strMsgTrd->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgTrd)); // object that manages the data
// ---- Tof ----
std::stringstream ossTof;
boost::archive::binary_oarchive oaTof(ossTof);
if (fTofConfig) { //
oaTof << *(fTofConfig->GetOutputVec());
}
else {
oaTof << (std::vector<CbmTofDigi>());
}
std::string* strMsgTof = new std::string(ossTof.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgTof->c_str()), // data
strMsgTof->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgTof)); // object that manages the data
// ---- Rich ----
std::stringstream ossRich;
boost::archive::binary_oarchive oaRich(ossRich);
if (fRichConfig) { //
oaRich << *(fRichConfig->GetOutputVec());
}
else {
oaRich << (std::vector<CbmRichDigi>());
}
std::string* strMsgRich = new std::string(ossRich.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgRich->c_str()), // data
strMsgRich->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgRich)); // object that manages the data
// ---- Psd ----
std::stringstream ossPsd;
boost::archive::binary_oarchive oaPsd(ossPsd);
if (fPsdConfig) { //
oaPsd << *(fPsdConfig->GetOutputVec());
}
else {
oaPsd << (std::vector<CbmPsdDigi>());
}
std::string* strMsgPsd = new std::string(ossPsd.str());
parts.AddPart(NewMessage(
const_cast<char*>(strMsgPsd->c_str()), // data
strMsgPsd->length(), // size
[](void*, void* object) { delete static_cast<std::string*>(object); },
strMsgPsd)); // object that manages the data
/// Prepare serialized versions of the TS Meta
/// FIXME: only for TS duration and overlap, should be sent to parameter service instead as stable values in run
/// Index and start time are already included in the TsHeader object!
FairMQMessagePtr messTsMeta(NewMessage());
// Serialize<RootSerializer>(*messTsMeta, fTsMetaData);
RootSerializer().Serialize(*messTsMeta, fTsMetaData);
parts.AddPart(std::move(messTsMeta));
if (Send(parts, fsChannelNameDataOutput) < 0) {
LOG(error) << "Problem sending data to " << fsChannelNameDataOutput;
return false;
}
return true;
}
bool CbmDeviceUnpack::SendHistoConfAndData()
{
/// Prepare multiparts message and header
std::pair<uint32_t, uint32_t> pairHeader(fvpsHistosFolder.size(), fvpsCanvasConfig.size());
FairMQMessagePtr messageHeader(NewMessage());
// Serialize<BoostSerializer<std::pair<uint32_t, uint32_t>>>(*messageHeader, pairHeader);
BoostSerializer<std::pair<uint32_t, uint32_t>>().Serialize(*messageHeader, pairHeader);
FairMQParts partsOut;
partsOut.AddPart(std::move(messageHeader));
for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto) {
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, fvpsHistosFolder[uHisto]);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist, fvpsHistosFolder[uHisto]);
partsOut.AddPart(std::move(messageHist));
} // for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto)
/// Catch case where no histos are registered!
/// => Add empty message
if (0 == fvpsHistosFolder.size()) {
FairMQMessagePtr messageHist(NewMessage());
partsOut.AddPart(std::move(messageHist));
}
for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv) {
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, fvpsCanvasConfig[uCanv]);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageCan, fvpsCanvasConfig[uCanv]);
partsOut.AddPart(std::move(messageCan));
} // for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv)
/// Catch case where no Canvases are registered!
/// => Add empty message
if (0 == fvpsCanvasConfig.size()) {
FairMQMessagePtr messageHist(NewMessage());
partsOut.AddPart(std::move(messageHist));
}
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr msgHistos(NewMessage());
// Serialize<RootSerializer>(*msgHistos, &fArrayHisto);
RootSerializer().Serialize(*msgHistos, &fArrayHisto);
partsOut.AddPart(std::move(msgHistos));
/// Send the multi-parts message to the common histogram messages queue
if (Send(partsOut, fsChannelNameHistosInput) < 0) {
LOG(error) << "CbmTsConsumerReqDevExample::SendHistoConfAndData => Problem sending data";
return false;
} // if( Send( partsOut, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
// ALGO: fMonitorAlgo->ResetHistograms(kFALSE);
return true;
}
bool CbmDeviceUnpack::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
// Serialize<RootSerializer>(*message, &fArrayHisto);
RootSerializer().Serialize(*message, &fArrayHisto);
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
LOG(error) << "Problem sending data";
return false;
} // if( Send( message, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
// ALGO: fMonitorAlgo->ResetHistograms(kFALSE);
return true;
}
CbmDeviceUnpack::~CbmDeviceUnpack()
{
if (fBmonConfig) fBmonConfig->GetUnpacker()->Finish();
if (fStsConfig) fStsConfig->GetUnpacker()->Finish();
if (fMuchConfig) fMuchConfig->GetUnpacker()->Finish();
if (fTrd1DConfig) fTrd1DConfig->GetUnpacker()->Finish();
if (fTrd2DConfig) fTrd2DConfig->GetUnpacker()->Finish();
if (fTofConfig) fTofConfig->GetUnpacker()->Finish();
if (fRichConfig) fRichConfig->GetUnpacker()->Finish();
if (fPsdConfig) fPsdConfig->GetUnpacker()->Finish();
}
Bool_t CbmDeviceUnpack::DoUnpack(const fles::Timeslice& ts, size_t /*component*/)
{
fulTsCounter++;
// Prepare timeslice
// const fles::Timeslice& timeslice = *ts;
fCbmTsEventHeader->SetTsIndex(ts.index());
fCbmTsEventHeader->SetTsStartTime(ts.start_time());
uint64_t nComponents = ts.num_components();
// if (fDoDebugPrints) LOG(info) << "Unpack: TS index " << ts.index() << " components " << nComponents;
LOG(debug) << "Unpack: TS index " << ts.index() << " components " << nComponents;
for (uint64_t component = 0; component < nComponents; component++) {
auto systemId = static_cast<std::uint16_t>(ts.descriptor(component, 0).sys_id);
switch (systemId) {
case fkFlesBmon: {
if (fBmonConfig) {
fCbmTsEventHeader->AddNDigisBmon(
unpack(systemId, &ts, component, fBmonConfig, fBmonConfig->GetOptOutAVec(), fBmonConfig->GetOptOutBVec()));
}
break;
}
case fkFlesSts: {
if (fStsConfig) {
fCbmTsEventHeader->AddNDigisSts(
unpack(systemId, &ts, component, fStsConfig, fStsConfig->GetOptOutAVec(), fStsConfig->GetOptOutBVec()));
}
break;
}
case fkFlesMuch: {
if (fMuchConfig) {
fCbmTsEventHeader->AddNDigisMuch(
unpack(systemId, &ts, component, fMuchConfig, fMuchConfig->GetOptOutAVec(), fMuchConfig->GetOptOutBVec()));
}
break;
}
case fkFlesTrd: {
if (fTrd1DConfig) {
fCbmTsEventHeader->AddNDigisTrd1D(unpack(systemId, &ts, component, fTrd1DConfig,
fTrd1DConfig->GetOptOutAVec(), fTrd1DConfig->GetOptOutBVec()));
}
break;
}
case fkFlesTrd2D: {
if (fTrd2DConfig) {
fCbmTsEventHeader->AddNDigisTrd2D(unpack(systemId, &ts, component, fTrd2DConfig,
fTrd2DConfig->GetOptOutAVec(), fTrd2DConfig->GetOptOutBVec()));
}
break;
}
case fkFlesTof: {
if (fTofConfig) {
fCbmTsEventHeader->AddNDigisTof(
unpack(systemId, &ts, component, fTofConfig, fTofConfig->GetOptOutAVec(), fTofConfig->GetOptOutBVec()));
}
break;
}
case fkFlesRich: {
if (fRichConfig) {
fCbmTsEventHeader->AddNDigisRich(
unpack(systemId, &ts, component, fRichConfig, fRichConfig->GetOptOutAVec(), fRichConfig->GetOptOutBVec()));
}
break;
}
case fkFlesPsd: {
if (fPsdConfig) {
fCbmTsEventHeader->AddNDigisPsd(
unpack(systemId, &ts, component, fPsdConfig, fPsdConfig->GetOptOutAVec(), fPsdConfig->GetOptOutBVec()));
}
break;
}
default: {
if (fDoDebugPrints) LOG(error) << "Unpack: Unknown system ID " << systemId << " for component " << component;
break;
}
}
}
if (fbOutputFullTimeSorting) {
/// Time sort the output vectors of all unpackers present
if (fBmonConfig && fBmonConfig->GetOutputVec()) { timesort(fBmonConfig->GetOutputVec()); }
if (fStsConfig && fStsConfig->GetOutputVec()) { timesort(fStsConfig->GetOutputVec()); }
if (fMuchConfig && fMuchConfig->GetOutputVec()) { timesort(fMuchConfig->GetOutputVec()); }
if (fTrd1DConfig && fTrd1DConfig->GetOutputVec()) { timesort(fTrd1DConfig->GetOutputVec()); }
if (fTrd2DConfig && fTrd2DConfig->GetOutputVec()) { timesort(fTrd2DConfig->GetOutputVec()); }
if (fTofConfig && fTofConfig->GetOutputVec()) { timesort(fTofConfig->GetOutputVec()); }
if (fRichConfig && fRichConfig->GetOutputVec()) { timesort(fRichConfig->GetOutputVec()); }
if (fPsdConfig && fPsdConfig->GetOutputVec()) { timesort(fPsdConfig->GetOutputVec()); }
/// Time sort the output vectors of all unpackers present
if (fBmonConfig && fBmonConfig->GetOptOutAVec()) { timesort(fBmonConfig->GetOptOutAVec()); }
if (fStsConfig && fStsConfig->GetOptOutAVec()) { timesort(fStsConfig->GetOptOutAVec()); }
if (fMuchConfig && fMuchConfig->GetOptOutAVec()) { timesort(fMuchConfig->GetOptOutAVec()); }
if (fTrd1DConfig && fTrd1DConfig->GetOptOutAVec()) { timesort(fTrd1DConfig->GetOptOutAVec()); }
if (fTrd2DConfig && fTrd2DConfig->GetOptOutAVec()) { timesort(fTrd2DConfig->GetOptOutAVec()); }
if (fTofConfig && fTofConfig->GetOptOutAVec()) { timesort(fTofConfig->GetOptOutAVec()); }
if (fRichConfig && fRichConfig->GetOptOutAVec()) { timesort(fRichConfig->GetOptOutAVec()); }
if (fPsdConfig && fPsdConfig->GetOptOutAVec()) { timesort(fPsdConfig->GetOptOutAVec()); }
}
if (0 == fulTsCounter % 10000) LOG(info) << "Processed " << fulTsCounter << " time slices";
return kTRUE;
}
/**
* @brief Get the Trd Spadic
* @return std::shared_ptr<CbmTrdSpadic>
*/
std::shared_ptr<CbmTrdSpadic> CbmDeviceUnpack::GetTrdSpadic(bool useAvgBaseline)
{
auto spadic = std::make_shared<CbmTrdSpadic>();
spadic->SetUseBaselineAverage(useAvgBaseline);
spadic->SetMaxAdcToEnergyCal(1.0);
return spadic;
}
void CbmDeviceUnpack::Finish() {}
/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/**
* CbmDeviceUnpack.h
*
* @since 2020-05-04
* @author P.-A. Loizeau
*/
#ifndef CBMDEVICEUNPACK_H_
#define CBMDEVICEUNPACK_H_
#include "CbmMqTMessage.h"
#include "CbmTsEventHeader.h"
#include "Timeslice.hpp"
#include "FairMQDevice.h"
#include "FairParGenericSet.h"
#include "Rtypes.h"
#include "TObjArray.h"
#include <chrono>
#include <map>
#include <vector>
class TList;
class CbmBmonUnpackConfig;
class CbmStsUnpackConfig;
class CbmMuchUnpackConfig;
class CbmTrdUnpackFaspConfig;
class CbmTrdUnpackConfig;
class CbmTofUnpackConfig;
class CbmRichUnpackConfig;
class CbmPsdUnpackConfig;
class TimesliceMetaData;
class CbmTrdSpadic;
class CbmDeviceUnpack : public FairMQDevice {
public:
CbmDeviceUnpack();
virtual ~CbmDeviceUnpack();
protected:
virtual void InitTask();
bool ConditionalRun();
bool HandleCommand(FairMQMessagePtr&, int);
/** @brief Set the Bmon Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmBmonUnpackConfig> config) { fBmonConfig = config; }
/** @brief Set the Sts Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmStsUnpackConfig> config) { fStsConfig = config; }
/** @brief Set the Much Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmMuchUnpackConfig> config) { fMuchConfig = config; }
/** @brief Set the Trd Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmTrdUnpackConfig> config) { fTrd1DConfig = config; }
/** @brief Set the Trd2D Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmTrdUnpackFaspConfig> config) { fTrd2DConfig = config; }
/** @brief Set the Tof Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmTofUnpackConfig> config) { fTofConfig = config; }
/** @brief Set the Rich Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmRichUnpackConfig> config) { fRichConfig = config; }
/** @brief Set the Psd Unpack Config @param config */
void SetUnpackConfig(std::shared_ptr<CbmPsdUnpackConfig> config) { fPsdConfig = config; }
private:
/// Constants
static constexpr std::uint16_t fkFlesBmon = static_cast<std::uint16_t>(fles::Subsystem::BMON);
static constexpr std::uint16_t fkFlesMvd = static_cast<std::uint16_t>(fles::Subsystem::MVD);
static constexpr std::uint16_t fkFlesSts = static_cast<std::uint16_t>(fles::Subsystem::STS);
static constexpr std::uint16_t fkFlesMuch = static_cast<std::uint16_t>(fles::Subsystem::MUCH);
static constexpr std::uint16_t fkFlesTrd = static_cast<std::uint16_t>(fles::Subsystem::TRD);
static constexpr std::uint16_t fkFlesTrd2D = static_cast<std::uint16_t>(fles::Subsystem::TRD2D);
static constexpr std::uint16_t fkFlesTof = static_cast<std::uint16_t>(fles::Subsystem::TOF);
static constexpr std::uint16_t fkFlesRich = static_cast<std::uint16_t>(fles::Subsystem::RICH);
static constexpr std::uint16_t fkFlesPsd = static_cast<std::uint16_t>(fles::Subsystem::PSD);
/// Control flags
Bool_t fbIgnoreOverlapMs = false; //! Ignore Overlap Ms: all fuOverlapMsNb MS at the end of timeslice
Bool_t fbComponentsAddedToList = kFALSE;
/** @brief Flag if extended debug output is to be printed or not*/
bool fDoDebugPrints = false; //!
/** @brief Flag if performance profiling should be activated or not.*/
bool fDoPerfProf = false; //!
/** @brief Flag to Enable/disable a full time sorting. If off, time sorting happens per link/FLIM source */
bool fbOutputFullTimeSorting = false;
/// User settings parameters
std::string fsSetupName = "mcbm_beam_2021_07_surveyed";
uint32_t fuRunId = 1588;
/// ---> for selective unpacking
bool fbUnpBmon = false;
bool fbUnpSts = true;
bool fbUnpMuch = false;
bool fbUnpTrd1D = true;
bool fbUnpTrd2D = true;
bool fbUnpTof = true;
bool fbUnpRich = true;
bool fbUnpPsd = true;
/// message queues
std::string fsChannelNameDataInput = "ts-request";
std::string fsChannelNameDataOutput = "unpts_0";
std::string fsChannelNameCommands = "commands";
std::string fsChannelNameHistosInput = "histogram-in";
/// Histograms management
uint32_t fuPublishFreqTs = 100;
double_t fdMinPublishTime = 0.5;
double_t fdMaxPublishTime = 5.0;
/// Parameters management
// TList* fParCList = nullptr;
Bool_t InitParameters(std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* reqparvec);
/// Statistics & first TS rejection
uint64_t fulNumMessages = 0;
uint64_t fulTsCounter = 0;
std::chrono::system_clock::time_point fLastPublishTime = std::chrono::system_clock::now();
/** @brief Map to store a name for the unpackers and the processed amount of digis, key = fkFlesId*/
std::map<std::uint16_t, std::pair<std::string, size_t>> fNameMap = {}; //!
/** @brief Map to store the cpu and wall time, key = fkFlesId*/
std::map<std::uint16_t, std::pair<double, double>> fTimeMap = {}; //!
/** @brief Map to store the in and out data amount, key = fkFlesId*/
std::map<std::uint16_t, std::pair<double, double>> fDataSizeMap = {}; //!
/// Configuration of the unpackers. Provides the configured algorithm
std::shared_ptr<CbmBmonUnpackConfig> fBmonConfig = nullptr;
std::shared_ptr<CbmStsUnpackConfig> fStsConfig = nullptr;
std::shared_ptr<CbmMuchUnpackConfig> fMuchConfig = nullptr;
std::shared_ptr<CbmTrdUnpackFaspConfig> fTrd2DConfig = nullptr;
std::shared_ptr<CbmTrdUnpackConfig> fTrd1DConfig = nullptr;
std::shared_ptr<CbmTofUnpackConfig> fTofConfig = nullptr;
std::shared_ptr<CbmRichUnpackConfig> fRichConfig = nullptr;
std::shared_ptr<CbmPsdUnpackConfig> fPsdConfig = nullptr;
/// Pointer to the Timeslice header conatining start time and index
CbmTsEventHeader* fCbmTsEventHeader = nullptr;
/// Time offsets
std::vector<std::string> fvsSetTimeOffs = {};
/// TS MetaData storage: stable so should be moved somehow to parameters handling (not transmitted with each TS
size_t fuNbCoreMsPerTs = 0; //!
size_t fuNbOverMsPerTs = 0; //!
Double_t fdMsSizeInNs = 0; //! Size of a single MS, [nanoseconds]
Double_t fdTsCoreSizeInNs = -1.0; //! Total size of the core MS in a TS, [nanoseconds]
Double_t fdTsOverSizeInNs = -1.0; //! Total size of the overlap MS in a TS, [nanoseconds]
Double_t fdTsFullSizeInNs = -1.0; //! Total size of all MS in a TS, [nanoseconds]
TimesliceMetaData* fTsMetaData;
/// Array of histograms to send to the histogram server
TObjArray fArrayHisto = {};
/// Vector of string pairs with ( HistoName, FolderPath ) to send to the histogram server
std::vector<std::pair<std::string, std::string>> fvpsHistosFolder = {};
/// Vector of string pairs with ( CanvasName, CanvasConfig ) to send to the histogram server
/// Format of Can config is "NbPadX(U);NbPadY(U);ConfigPad1(s);....;ConfigPadXY(s)"
/// Format of Pad config is "GrixX(b),GridY(b),LogX(b),LogY(b),LogZ(b),HistoName(s),DrawOptions(s)"
std::vector<std::pair<std::string, std::string>> fvpsCanvasConfig = {};
/// Flag indicating whether the histograms and canvases configurations were already published
bool fbConfigSent = false;
Bool_t InitContainers();
bool InitHistograms();
Bool_t DoUnpack(const fles::Timeslice& ts, size_t component);
void Finish();
bool SendUnpData();
bool SendHistoConfAndData();
bool SendHistograms();
std::shared_ptr<CbmTrdSpadic> GetTrdSpadic(bool useAvgBaseline);
/** @brief Sort a vector timewise vector type has to provide GetTime() */
template<typename TVecobj>
typename std::enable_if<std::is_same<TVecobj, std::nullptr_t>::value == true, void>::type
timesort(std::vector<TVecobj>* /*vec = nullptr*/)
{
LOG(debug) << "CbmDeviceUnpack::timesort() got an object that has no member function GetTime(). Hence, we can and "
"will not timesort it!";
}
template<typename TVecobj>
typename std::enable_if<!std::is_member_function_pointer<decltype(&TVecobj::GetTime)>::value, void>::type
timesort(std::vector<TVecobj>* /*vec = nullptr*/)
{
LOG(debug) << "CbmDeviceUnpack::timesort() " << TVecobj::Class_Name()
<< "is an object that has no member function GetTime(). Hence, we can and "
"will not timesort it!";
}
template<typename TVecobj>
typename std::enable_if<std::is_member_function_pointer<decltype(&TVecobj::GetTime)>::value, void>::type
timesort(std::vector<TVecobj>* vec = nullptr)
{
if (vec == nullptr) return;
std::sort(vec->begin(), vec->end(),
[](const TVecobj& a, const TVecobj& b) -> bool { return a.GetTime() < b.GetTime(); });
}
/**
* @brief Template for the unpacking call of a given algorithm.
*
* @tparam TAlgo Algorithm to be called
* @tparam TOutput Output element types
* @tparam TOptoutputs Optional output element types
* @param ts Timeslice
* @param icomp Component number
* @param algo Algorithm to be used for this component
* @param outtargetvec Target vector for the output elements
* @param optoutputvecs Target vectors for optional outputs
* @return std::pair<ndigis, std::pair<cputime, walltime>>
*/
template<class TConfig, class TOptOutA = std::nullptr_t, class TOptOutB = std::nullptr_t>
size_t unpack(const std::uint16_t subsysid, const fles::Timeslice* ts, std::uint16_t icomp, TConfig config,
std::vector<TOptOutA>* optouttargetvecA = nullptr, std::vector<TOptOutB>* optouttargetvecB = nullptr)
{
auto wallstarttime = std::chrono::high_resolution_clock::now();
std::clock_t cpustarttime = std::clock();
auto algo = config->GetUnpacker();
std::vector<TOptOutA> optoutAvec = {};
std::vector<TOptOutB> optoutBvec = {};
if (optouttargetvecA) { algo->SetOptOutAVec(&optoutAvec); }
if (optouttargetvecB) { algo->SetOptOutBVec(&optoutBvec); }
// Set the start time of the current TS for this algorithm
algo->SetTsStartTime(ts->start_time());
// Run the actual unpacking
auto digivec = algo->Unpack(ts, icomp);
// Check if we want to write the output to somewhere (in pure online monitoring mode for example this can/would/should be skipped)
if (config->GetOutputVec()) {
// Lets do some time-sorting if we are not doing it later
if (!fbOutputFullTimeSorting) timesort(&digivec);
// Transfer the data from the timeslice vector to the target branch vector
// Digis/default output retrieved as offered by the algorithm
for (auto digi : digivec)
config->GetOutputVec()->emplace_back(digi);
}
if (optouttargetvecA) {
// Lets do some timesorting
if (!fbOutputFullTimeSorting) timesort(&optoutAvec);
// Transfer the data from the timeslice vector to the target branch vector
for (auto optoutA : optoutAvec)
optouttargetvecA->emplace_back(optoutA);
}
if (optouttargetvecB) {
// Second opt output is not time sorted to allow non GetTime data container.
// Lets do some timesorting
timesort(&optoutAvec);
// Transfer the data from the timeslice vector to the target branch vector
for (auto optoutB : optoutBvec)
optouttargetvecB->emplace_back(optoutB);
}
std::clock_t cpuendtime = std::clock();
auto wallendtime = std::chrono::high_resolution_clock::now();
// Cpu time in [mus]
auto cputime = 1e6 * (cpuendtime - cpustarttime) / CLOCKS_PER_SEC;
algo->AddCpuTime(cputime);
// Real time in [mus]
auto walltime = std::chrono::duration<double, std::micro>(wallendtime - wallstarttime).count();
algo->AddWallTime(walltime);
// Check some numbers from this timeslice
size_t nDigis = digivec.size();
LOG(debug) << "Component " << icomp << " connected to config " << config->GetName() << " n-Digis " << nDigis
<< " processed in walltime(cputime) = " << walltime << "(" << cputime << cputime << ") micro s"
<< "this timeslice.";
if (fDoPerfProf) {
auto timeit = fTimeMap.find(subsysid);
timeit->second.first += cputime;
timeit->second.second += walltime;
auto datait = fDataSizeMap.find(subsysid);
datait->second.first += ts->size_component(icomp) / 1.0e6;
datait->second.second += nDigis * algo->GetOutputObjSize() / 1.0e6;
fNameMap.find(subsysid)->second.second += nDigis;
}
return nDigis;
}
};
#endif /* CBMDEVICEMCBMUNPACK_H_ */