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 2041 additions and 0 deletions
Installation Instructions for for CbmRoot
=========================================
The easiest way to install CbmRoot is described in Chapter 3 which
introduces a scripts for automatic installation of CbmRoot and its
dependencies. If you are unsure how to install CbmRoot please follow
the instructions in this chapter.
# 1. Dependencies
## 1.1 Compiler
To be able to compile CbmRoot, the used compiler must support the C++17 standard.
A GCC beginning from version 7 and clang beginning from version 6 should be okay.
## 1.2 FairSoft
To install, compile, and run CbmRoot, several external programs are required.
These are for example Root, Geant3 or Geant4 and many others. Installing these
is the first step of the CbmRoot installation. As the individual installation of
each of these programs is very time consuming, the FairRoot team provides a
software bundle known as FairSoft, which contains all the needed packages, and also
provides tools for its automated installation on several platforms. The most up-to-date
information regarding the installation of FairSoft, together with a complete list of
the contained packages, can be found on the project's GitHub page:
https://github.com/FairRootGroup/FairSoft
This page should be considered the primary source of information regarding FairSoft,
which takes precedence over any others (which may in some cases be outdated).
Additional information, for instance regarding older versions, can be found on
CBM Redmine:
https://redmine.cbm.gsi.de/projects/cbmroot/wiki/Install_External_Packages
We recommend to always use the latest FairSoft release version. Currently this is
"apr21p2", which is compatible with the latest version of CbmRoot. Different
combinations of older versions of FairSoft, FairRoot and CbmRoot may work in
principle, but are not endorsed or actively supported.
Please make sure SQLite is installed on your system before compiling
FairSoft, as this is required by CbmRoot. Failing to compile FairSoft
with SQLite support will lead to a crash during the CbmRoot compilation
which results in a complete reinstallation of FairSoft and FairRoot after
the package was installed.
There have also been reports about problems with other missing packages.
Mainly these were the Threading Building Blocks (tbb), the GNU Scientific
Library and ZSTD, which is used for compressing experimental data since May 2024.
Since these packages may be missing in the instructions from the FairRoot
webpage please install them using the following commands depending on your
OS.
Debian/Ubuntu:
sudo apt install sqlite3 libsqlite3-dev
sudo apt install libgsl-dev
sudo apt install libtbb-dev
sudo apt install libzstd-dev
OpenSuse:
sudo zypper install sqlite3 sqlite3-devel
sudo zypper install gsl-devel
sudo zypper install tbb-devel
Fedora:
sudo dnf install sqlite-devel
sudo dnf install gsl-devel
sudo dnf install tbb-devel
The complete installation of FairSoft (and likewise FairRoot and CbmRoot) doesn't
need any administrative privileges and an installation into system paths is strongly
discouraged, as this may create conflicts with existing software.
So please make sure that you do the installation as normal user.
For an installation which is to be shared between users on a MacOS or linux system
it is recommended to use the opt/ folder.
Consider also using the auto installer (see section 3).
The compilation of FairSoft is the most time-consuming part of the CbmRoot installation
and can take several hours, depending on your system. If you are working at GSI there are
always ready-to-use versions of FairSoft available. For detailed information please check
the following wiki page
https://redmine.cbm.gsi.de/projects/cbmroot/wiki/RunCbmGSI
## 1.3 FairRoot
CbmRoot is based on FairRoot, a simulation, reconstruction and analysis
framework based on the ROOT system, which by now is also used by several other experiments
as base for their developments. Beside FairSoft you need also to install FairRoot to be able
to compile CbmRoot.
Detailed instructions how to get and compile FairRoot can be found on
the project's GitHub page at:
https://github.com/FairRootGroup/FairRoot
We again recommend this official repository as the primary source of
information, and recommend using the latest release version.
Other information can be found at:
https://redmine.cbm.gsi.de/projects/cbmroot/wiki/InstallFairRoot
In order to compile FairRoot, you must set the environment variable SIMPATH
to contain the path to your FairSoft installation, i.e.:
export SIMPATH=[path_to_fairsoft]
Not setting this variable (or FAIRROOTPATH, defined below) properly is a common
source of problems.
# 2. Installing CbmRoot
After installing FairSoft and FairRoot, to install CbmRoot first
create a local clone of the Git repository using:
git clone https://git.cbm.gsi.de/computing/cbmroot
Subsequently, create a build directory:
mkdir build_cbmroot
To proceed, you must set the environment variables SIMPATH and FAIRROOTPATH,
to the folders of your FairSoft and FairRoot installations, i.e.
export SIMPATH=[path_to_fairsoft]
export FAIRROOTPATH=[path_to_fairroot install]
From your build directory, then call
cmake [path_to_cbmroot]
make -j[number_of_cores]
After your build is complete, before running any part of CbmRoot from a shell,
a large number of environment variables must be set, which contain various
library and include paths. This is done automatically by executing the "config.sh"
or "config.csh" script from your CbmRoot build directory.
Please note, that you must supply the argument "-p" (prepend) or "-a" (append) to
these scripts, depending on whether you wish to add the new entries at the front or
back of existing environment variables. Failing to do so will cause the variables
to be overwritten, and may render your shell inoperable. This behavior may be desired
in some cases, e.g. on the Virgo cluster.
If you are using a Bash shell, you can add the following line to .bashrc to further
automate this step:
source ~/build_cbmroot/config.sh -a > /dev/null 2>&1
The problem with this automatisation is that it frequently results in
problems if you use more than one combination of FairSoft/FairRoot/Cbmroot.
If this isn't the case for you please proceed but keep in mind to unset this
automatism before installing any new versions of FairSoft, FairRoot.
# 3. Automatic installation
To make the installation more easy we provide a script which automatically
compiles and installs FairSoft, FairRoot, and CbmRoot in one go. The script
always combines the correct FairSoft and FairRoot versions. The full description
of this process is at
https://redmine.cbm.gsi.de/projects/cbmroot/wiki/InstallCbmRootAuto
To get the script and the needed CbmRoot source code to your local computer
you need to clone the CbmRoot repository from out Git repository using:
git clone https://git.cbm.gsi.de/computing/cbmroot
The needed skript is then available in the CbmRoot source directory and can
be executed from there by a one-line command
./autoinstall_framework.sh --fairsoft --fairroot --cbmroot
The command automatically install the defined production versions of
FairSoft and FairRoot. If you want to check for the avaible options you can
get the complete list with
./autoinstall_framework.sh --help
If any problems appear and the script stops with an error message please
redo the installation step by step to see where the problem appears.
./autoinstall_framework.sh --fairsoft
./autoinstall_framework.sh --fairsoft --fairroot
./autoinstall_framework.sh --fairsoft --fairroot --cbmroot
The same script can be used to only install any subset of the three packages. See
the Redmine page or the script itself for further details.
## 3.1 Tested systems
The current version of the script was tested for the following systems and
combinations of FairSoft and FairRoot
| OS | FairSoft | FairRoot |
|---------------|------------|----------|
| Ubuntu 20.04 | apr21p2 | v18.6.7 |
| OpenSuse 15.4 | apr21p2 | v18.6.7 |
| Fedora 35 | apr21p2 | v18.6.7 |
# 4. Recommended versions
GCC : `>= 7`
or
Clang: `>= 6`
FairSoft: `apr21p2`
FairRoot: `v18.6.7`
Clang-format: `v11.0`
Boost archives being only ensured to be `backward compatible` (and therefore not necessarily
`forward compatible`), care must be taken when writing data and/or parameter files with it
that the versions used when writing and when using/reading are compatible. \
More information in the [following document](docs/boost_serialization_version.md).
# 5. Further remarks
Compiling CbmRoot with multicore support using "make -j", without
specifying the number of threads, is known to cause MacOS and Ubuntu
20.04 LTS systems to freeze. Please explicitly choose a number of cores
which is suitable for your system.
# 6. CI and Code formatting
For information about our Merge-Request CI chain, including code formatting, please refere to this
[description page](docs/CiDescription.md)
cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR)
cmake_policy(VERSION 3.14...3.23)
if (NOT DEFINED CBM_ONLINE_STANDALONE)
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(CBM_ONLINE_STANDALONE ON)
project(CbmOnline)
else()
set(CBM_ONLINE_STANDALONE OFF)
endif()
endif()
if (CBM_ONLINE_STANDALONE)
message(STATUS "Building online standalone")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)
Set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
Set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin")
Set(INCLUDE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/include")
set(CMAKE_INSTALL_LIBDIR lib)
# Set default build type
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Build type" FORCE)
endif()
#Fairsoft Modules Path, SIMPATH must always be set
if (NOT DEFINED SIMPATH)
message(FATAL_ERROR "SIMPATH not set")
endif()
list(PREPEND CMAKE_PREFIX_PATH ${SIMPATH})
find_package(OpenMP REQUIRED)
find_package(Boost REQUIRED COMPONENTS serialization regex filesystem log log_setup container program_options thread iostreams)
find_package(ROOT CONFIG REQUIRED GenVector)
find_package(Vc 1.4.1 CONFIG REQUIRED)
find_package(fmt CONFIG REQUIRED)
include(ExternalProject)
# cmake is symlinked to ../cmake by the install script in the container
# We use the symlink because some cmake macros use relative path from the project root
# to locate files (e.g. Gen_Exe_Script).
# Thus we need the same path if the project root changes.
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
include(CbmMacros) # for 'download_project_if_needed', 'Gen_Exe_Script' macro
add_subdirectory(../external external)
endif()
add_subdirectory(kfp)
add_subdirectory(log)
add_subdirectory(data)
add_subdirectory(kf)
add_subdirectory(ca)
add_subdirectory(base)
#add_subdirectory(kfp) # For KFParticleOnline
# exclude unittests from being build inside the container
if (NOT CBM_ONLINE_STANDALONE)
add_subdirectory(test)
endif()
set(DEVICE_SRCS
base/gpu/DeviceImage.cxx
base/gpu/Params.cxx
detectors/sts/Hitfinder.cxx
)
set(SRCS
${DEVICE_SRCS}
base/ChainContext.cxx
base/DigiData.cxx
base/Options.cxx
base/MainConfig.cxx
base/RecoParams.cxx
base/System.cxx
base/compat/Algorithm.cxx
base/util/MemoryLogger.cxx
base/util/StlUtils.cxx
base/util/EnumDict.cxx
base/util/TimingsFormat.cxx
data/sts/HitfinderPars.cxx
data/sts/LandauTable.cxx
evbuild/Config.cxx
evbuild/EventBuilder.cxx
evbuild/EventBuilderConfig.cxx
evbuild/EventbuildChain.cxx
trigger/DigiTriggerConfig.cxx
trigger/HitMultTrigger.cxx
trigger/TimeClusterTrigger.cxx
trigger/V0Trigger.cxx
trigger/V0TriggerConfig.cxx
evselector/DigiEventSelector.cxx
evselector/DigiEventSelectorConfig.cxx
unpack/CommonUnpacker.cxx
detectors/bmon/Calibrate.cxx
detectors/bmon/Clusterizer.cxx
detectors/bmon/Hitfind.cxx
detectors/bmon/ReadoutConfig.cxx
detectors/bmon/Unpack.cxx
detectors/bmon/UnpackMS.cxx
detectors/sts/ChannelMaskSet.cxx
detectors/sts/ReadoutConfig.cxx
detectors/sts/HitfinderChain.cxx
detectors/sts/TrackingInterface.cxx
detectors/sts/Unpack.cxx
detectors/sts/UnpackMS.cxx
detectors/sts/WalkMap.cxx
detectors/much/ReadoutConfig.cxx
detectors/much/Unpack.cxx
detectors/much/UnpackMS.cxx
detectors/tof/HitFinder.cxx
detectors/tof/Calibrate.cxx
detectors/tof/Clusterizer.cxx
detectors/tof/ReadoutConfig.cxx
detectors/tof/Unpack.cxx
detectors/tof/UnpackMS.cxx
detectors/tof/Hitfind.cxx
detectors/tof/TrackingInterface.cxx
detectors/trd/Cluster.cxx
detectors/trd/Clusterizer.cxx
detectors/trd/Cluster2D.cxx
detectors/trd/Clusterizer2D.cxx
detectors/trd/DigiRec.cxx
detectors/trd/Hit.cxx
detectors/trd/Hitfind.cxx
detectors/trd/HitFactory2D.cxx
detectors/trd/HitFinder.cxx
detectors/trd/HitFinder2D.cxx
detectors/trd/HitMerger.cxx
detectors/trd/HitMerger2D.cxx
detectors/trd/ReadoutConfig.cxx
detectors/trd/TrackingInterface.cxx
detectors/trd/Unpack.cxx
detectors/trd/UnpackMS.cxx
detectors/trd2d/ReadoutConfig.cxx
detectors/trd2d/Unpack.cxx
detectors/trd2d/UnpackMS.cxx
detectors/rich/ReadoutConfig.cxx
detectors/rich/Unpack.cxx
detectors/rich/UnpackMS.cxx
global/ParFiles.cxx
global/StorableRecoResults.cxx
global/Reco.cxx
global/RecoResultsInputArchive.cxx
global/RecoResultsOutputArchive.cxx
qa/DigiEventQa.cxx
qa/Histo1D.cxx
qa/HistogramContainer.cxx
qa/CanvasConfig.cxx
qa/PadConfig.cxx
qa/QaData.cxx
qa/RecoGeneralQa.cxx
qa/QaManager.cxx
qa/hitfind/BmonHitfindQa.cxx
qa/hitfind/BmonHitfindQaParameters.cxx
qa/trigger/V0TriggerQa.cxx
qa/hitfind/TofHitfindQa.cxx
qa/hitfind/TofHitfindQaParameters.cxx
qa/unpack/StsDigiQa.cxx
ca/TrackingSetup.cxx
ca/TrackingChain.cxx
ca/qa/CaQa.cxx
kfp/KfpV0Finder.cxx
kfp/KfpV0FinderChain.cxx
kfp/KfpV0FinderConfig.cxx
kfp/KfpV0FinderQa.cxx
)
set(BUILD_INFO_CXX ${CMAKE_CURRENT_BINARY_DIR}/base/BuildInfo.cxx)
set(SRCS ${SRCS} ${BUILD_INFO_CXX})
add_custom_target(generateBuildInfo
COMMAND ${CMAKE_COMMAND}
-DBUILD_TYPE=${CMAKE_BUILD_TYPE}
-DXPU_DEBUG=${XPU_DEBUG}
-DINFILE=${CMAKE_CURRENT_SOURCE_DIR}/base/BuildInfo.cxx.in
-DOUTFILE=${BUILD_INFO_CXX}
-P ${CMAKE_SOURCE_DIR}/cmake/modules/GenerateBuildInfo.cmake
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/base/BuildInfo.cxx.in
${CMAKE_SOURCE_DIR}/cmake/modules/GenerateBuildInfo.cmake
BYPRODUCTS ${BUILD_INFO_CXX}
COMMENT "Generating build info"
)
add_library(Algo SHARED ${SRCS})
target_include_directories(Algo
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/data
${CMAKE_CURRENT_SOURCE_DIR}/base
${CMAKE_CURRENT_SOURCE_DIR}/evbuild
${CMAKE_CURRENT_SOURCE_DIR}/global
${CMAKE_CURRENT_SOURCE_DIR}/trigger
${CMAKE_CURRENT_SOURCE_DIR}/evselector
${CMAKE_CURRENT_SOURCE_DIR}/unpack
${CMAKE_CURRENT_SOURCE_DIR}/detectors
${CMAKE_CURRENT_SOURCE_DIR}/qa
${CMAKE_CURRENT_SOURCE_DIR}/qa/unpack
${CMAKE_CURRENT_SOURCE_DIR}/qa/hitfind
${CMAKE_CURRENT_SOURCE_DIR}/qa/trigger
${CMAKE_CURRENT_SOURCE_DIR}/kf
${CMAKE_CURRENT_SOURCE_DIR}/kf/core
${CMAKE_CURRENT_SOURCE_DIR}/kf/core/utils
${CMAKE_CURRENT_SOURCE_DIR}/kfp
${CMAKE_CURRENT_SOURCE_DIR}/ca
${CMAKE_CURRENT_SOURCE_DIR}/ca/qa
${CMAKE_CURRENT_SOURCE_DIR}/ca/core/data
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/core/data/global
)
target_link_libraries(Algo
PUBLIC OnlineData
KfCore
CaCore
ROOT::GenVector
GSL
fmt::fmt
Boost::program_options
Boost::filesystem
Boost::iostreams
Boost::headers
xpu
external::yaml-cpp
external::fles_logging
external::fles_ipc
external::fles_monitoring
cppzmq
poolstl
PRIVATE CbmKFParticleOnlineInterface
INTERFACE CbmYamlInterface
)
target_compile_definitions(Algo PUBLIC NO_ROOT)
xpu_attach(Algo ${DEVICE_SRCS})
# Link against OpenMP if available
if (OpenMP_CXX_FOUND)
target_link_libraries(Algo PUBLIC OpenMP::OpenMP_CXX)
endif()
# Try to enable parallel execution in c++17 if TBB is available
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
list(APPEND CMAKE_PREFIX_PATH "/opt/intel/oneapi/tbb/latest/")
find_package(TBB)
if (TBB_FOUND)
message(STATUS "Found TBB")
target_compile_definitions(Algo PUBLIC -DHAVE_TBB)
target_link_libraries(Algo PUBLIC TBB::tbb)
else()
message(STATUS "TBB not found")
endif()
endif()
if (CBM_ONLINE_STANDALONE)
# Add online binary
add_subdirectory(../reco/app/cbmreco cbmreco)
endif()
##### Offline version without the NO_ROOT in order to get standard logger! #############################################
if (NOT CBM_ONLINE_STANDALONE)
add_library(AlgoOffline SHARED ${SRCS})
target_include_directories(AlgoOffline
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/data
${CMAKE_CURRENT_SOURCE_DIR}/base
${CMAKE_CURRENT_SOURCE_DIR}/evbuild
${CMAKE_CURRENT_SOURCE_DIR}/global
${CMAKE_CURRENT_SOURCE_DIR}/trigger
${CMAKE_CURRENT_SOURCE_DIR}/evselector
${CMAKE_CURRENT_SOURCE_DIR}/unpack
${CMAKE_CURRENT_SOURCE_DIR}/detectors
${CMAKE_CURRENT_SOURCE_DIR}/qa
${CMAKE_CURRENT_SOURCE_DIR}/qa/unpack
${CMAKE_CURRENT_SOURCE_DIR}/qa/hitfind
${CMAKE_CURRENT_SOURCE_DIR}/qa/trigger
${CMAKE_CURRENT_SOURCE_DIR}/kf
${CMAKE_CURRENT_SOURCE_DIR}/kf/core
${CMAKE_CURRENT_SOURCE_DIR}/kf/core/utils
${CMAKE_CURRENT_SOURCE_DIR}/kfp
${CMAKE_CURRENT_SOURCE_DIR}/ca
${CMAKE_CURRENT_SOURCE_DIR}/ca/qa
${CMAKE_CURRENT_SOURCE_DIR}/ca/core/data
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/core/data/global
)
target_link_libraries(AlgoOffline
PUBLIC CbmData
KfCoreOffline
CaCoreOffline
ROOT::GenVector
GSL
fmt::fmt
Boost::program_options
Boost::filesystem
Boost::iostreams
Boost::headers
FairLogger::FairLogger
xpu
external::yaml-cpp
external::fles_ipc
external::fles_monitoring
cppzmq
poolstl
PRIVATE CbmKFParticleOnlineInterface
INTERFACE CbmYamlInterface
)
xpu_attach(AlgoOffline ${DEVICE_SRCS})
# Link against OpenMP if available
if (OpenMP_CXX_FOUND)
target_link_libraries(AlgoOffline PUBLIC OpenMP::OpenMP_CXX)
endif()
# Try to enable parallel execution in c++17 if TBB is available
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
list(APPEND CMAKE_PREFIX_PATH "/opt/intel/oneapi/tbb/latest/")
find_package(TBB)
if (TBB_FOUND)
message(STATUS "AlgoOffline: Found TBB")
target_compile_definitions(AlgoOffline PUBLIC -DHAVE_TBB)
target_link_libraries(AlgoOffline PUBLIC TBB::tbb)
else()
message(STATUS "Algo Offline: TBB not found")
endif()
endif()
install(TARGETS AlgoOffline DESTINATION lib)
endif()
########################################################################################################################
install(TARGETS Algo DESTINATION lib)
install(DIRECTORY base/compat TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
#install(DIRECTORY base/yaml TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY base/util TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY base/gpu TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY data/sts TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY detectors/bmon TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY detectors/much TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY detectors/sts TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY detectors/tof TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY detectors/trd TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY detectors/trd2d TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY detectors/rich TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY ca/qa TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY qa TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY qa/unpack TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY ca TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY kfp TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY evbuild TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(
FILES
base/ChainContext.h
base/Definitions.h
base/HistogramSender.h
base/Options.h
base/RecoParams.h
base/SubChain.h
base/System.h
base/PartitionedVector.h
base/PartitionedSpan.h
base/DigiData.h
base/PODVector.h
base/AlgoTraits.h
base/AuxDigiData.h
base/BuildInfo.h
base/Exceptions.h
base/MainConfig.h
evselector/DigiEventSelector.h
evselector/DigiEventSelectorConfig.h
trigger/DigiTriggerConfig.h
trigger/HitMultTrigger.h
trigger/TimeClusterTrigger.h
trigger/V0Trigger.h
trigger/V0TriggerConfig.h
unpack/CommonUnpacker.h
unpack/UnpackMSBase.h
global/Reco.h
global/RecoResults.h
global/RecoResultsInputArchive.h
global/RecoResultsOutputArchive.h
global/StorableRecoResults.h
qa/Histogram.h
ca/TrackingChain.h
ca/TrackingChainConfig.h
ca/TrackingDefs.h
ca/TrackingSetup.h
# NOTE: SZh 20.11.2023:
# The ca/qa directory depends on the online qa classes, so for now it has to be a part of the Algo library.
ca/qa/CaQa.h
DESTINATION
include/
)
/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#pragma once
#include <tuple>
#include <type_traits>
/**
* @file AlgoTraits.h
* @brief Type traits for online algorithms
*/
namespace cbm::algo::algo_traits
{
namespace detail
{
template<typename...>
struct ResultOf {
};
template<typename R, typename Algo, typename... Args>
struct ResultOf<R (Algo::*)(Args...) const> {
using type = R;
};
template<typename R, typename Algo, typename... Args>
struct ResultOf<R (Algo::*)(Args...)> {
using type = R;
};
template<typename Algo>
struct ResultOf<Algo> : ResultOf<decltype(&Algo::operator())> {
};
} // namespace detail
/**
* @brief Type alias for the return type produced by an algorithm when invoked via callable-operator
*/
template<typename Algo>
using ResultOf_t = typename detail::ResultOf<Algo>::type;
// Currently assume algorithms return std::tuple<R, M, A>
// where R is the output, M is the monitoring data and A is auxiliary data
/**
* @brief Type alias for the output type produced by an algorithm
*/
template<typename Algo>
using Output_t = typename std::tuple_element<0, ResultOf_t<Algo>>::type;
/**
* @brief Type alias for the monitoring type produced by an algorithm
*/
template<typename Algo>
using Monitor_t = typename std::tuple_element<1, ResultOf_t<Algo>>::type;
/**
* @brief Type alias for the auxiliary data type produced by an algorithm
*/
template<typename Algo>
using Aux_t = typename std::tuple_element<2, ResultOf_t<Algo>>::type;
} // namespace cbm::algo::algo_traits
/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file AuxDigiData.h
/// \date 10.06.2024
/// \brief Collection of auxiliary data from unpackers (header)
/// \author Sergei Zharko <s.zharko@gsi.de>
#pragma once
#include "CommonUnpacker.h"
#include "bmon/UnpackMS.h"
#include "much/UnpackMS.h"
#include "rich/UnpackMS.h"
#include "sts/UnpackMS.h"
#include "tof/UnpackMS.h"
#include "trd/UnpackMS.h"
#include "trd2d/UnpackMS.h"
#include <vector>
namespace cbm::algo
{
/// \struct AuxDigiData
/// \brief Collection of auxiliary digi objects from different module unpackers
struct AuxDigiData {
UnpackAux<bmon::UnpackAuxData> fBmon;
UnpackAux<much::UnpackAuxData> fMuch;
UnpackAux<rich::UnpackAuxData> fRich;
UnpackAux<sts::UnpackAuxData> fSts;
UnpackAux<tof::UnpackAuxData> fTof;
UnpackAux<trd::UnpackAuxData> fTrd;
UnpackAux<trd2d::UnpackAuxData> fTrd2d;
};
} // namespace cbm::algo
/* Copyright (C) 2022 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer]*/
#include "BuildInfo.h"
// GENERATED BY CMAKE.
// DON'T CHANGE BY HAND. MODIFY .in-File INSTEAD.
namespace cbm::algo::BuildInfo {
const std::string GIT_HASH = "@GIT_HASH@";
const std::string BUILD_TYPE = "@BUILD_TYPE@";
const bool GPU_DEBUG = @GPU_DEBUG@;
} // namespace cbm::algo::BuildInfo
/* Copyright (C) 2022 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer]*/
#ifndef CBM_ALGO_BUILD_INFO_H
#define CBM_ALGO_BUILD_INFO_H
#include <string>
#define MAKE_GCC_VERSION(major, minor, patch) ((major) *10000 + (minor) *100 + (patch))
#define GCC_VERSION MAKE_GCC_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#if __has_include(<execution>) && !defined(__CLING__)
#include <execution> // for feature test macro __cpp_lib_parallel_algorithm
#endif
#if defined(HAVE_TBB) && defined(__cpp_lib_parallel_algorithm)
#define HAVE_PARALLEL_STL_LIBTBB
#endif
// PoolSTL triggers an internal error in GCC 10, so only enable it for GCC 11 and later
#if GCC_VERSION >= MAKE_GCC_VERSION(11, 0, 0)
#define HAVE_PARALLEL_STL_POOLSTL
#endif
#if __has_include(<omp.h>)
#define HAVE_OMP
#endif
// Ensure we have the boost compression header AND flesnet is compiled with compression enabled
#if __has_include(<boost/iostreams/filter/zstd.hpp>) && defined(BOOST_IOS_HAS_ZSTD)
#define HAVE_ZSTD
#endif
namespace cbm::algo::BuildInfo
{
extern const std::string GIT_HASH;
extern const std::string BUILD_TYPE;
extern const bool GPU_DEBUG;
inline constexpr bool WITH_TBB =
#ifdef HAVE_TBB
true;
#else
false;
#endif
inline constexpr bool WITH_PARALLEL_STL =
#ifdef HAVE_PARALLEL_STL_LIBTBB
true;
#else
false;
#endif
inline constexpr bool WITH_OMP =
#ifdef HAVE_OMP
true;
#else
false;
#endif
inline constexpr bool WITH_ZSTD =
#ifdef HAVE_ZSTD
true;
#else
false;
#endif
} // namespace cbm::algo::BuildInfo
#endif // CBM_ALGO_BUILD_INFO_H
add_subdirectory(yaml)
/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#include "ChainContext.h"
#include <Monitor.hpp>
using namespace cbm::algo;
ChainContext::ChainContext() {}
ChainContext::~ChainContext() {}
/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#ifndef CBM_ALGO_BASE_CHAINCONTEXT_H
#define CBM_ALGO_BASE_CHAINCONTEXT_H
#include "Options.h"
#include "RecoParams.h"
#include <memory>
#include <optional>
namespace cbm
{
// cbm::Monitor must be forward declared. This prevents an issue in older ROOT versions,
// where cling would crash upon parsing the header file (in some stl header)
class Monitor;
} // namespace cbm
namespace cbm::algo
{
struct ChainContext {
// default constructor / destructor
// But have to be defined in the .cxx file, because of forward declaration of cbm::Monitor
ChainContext();
~ChainContext();
Options opts;
RecoParams recoParams;
std::unique_ptr<cbm::Monitor> monitor; //! Monitor
};
} // namespace cbm::algo
#endif
/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#ifndef CBM_BASE_TYPES_H
#define CBM_BASE_TYPES_H
#include "MicrosliceDescriptor.hpp" // For fles::Subsystem
#include "util/EnumDict.h"
#include <cstdint>
namespace cbm::algo
{
// typealias for Rust-like fixed size integer types
using i8 = std::int8_t;
using u8 = std::uint8_t;
using i16 = std::int16_t;
using u16 = std::uint16_t;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;
using f32 = float;
using f64 = double;
#ifdef CBM_ALGO_REAL64
using real = f64;
#else
using real = f32;
#endif
enum class Step
{
Unpack,
DigiTrigger,
LocalReco,
Tracking,
};
enum class RecoData
{
DigiTimeslice, //< Raw output from unpackers
DigiEvent, //< Digis after event building
Cluster,
Hit,
Track,
};
enum class Setup
{
mCBM2022,
mCBM2024_03,
mCBM2024_05,
mCBM2025_02,
};
enum class QaStep
{
BeamBmon,
UnpackBmon,
UnpackSts,
UnpackMvd,
UnpackRich,
UnpackTrd1d,
UnpackTrd2d,
UnpackMuch,
UnpackTof,
UnpackFsd,
EventBuilding,
RecoBmon,
RecoSts,
RecoMvd,
RecoRich,
RecoTrd1d,
RecoTrd2d,
RecoMuch,
RecoTof,
RecoFsd,
Tracking,
V0Finder,
V0Trigger,
};
} // namespace cbm::algo
CBM_ENUM_DICT(fles::Subsystem,
// CBM detectors
{"STS", fles::Subsystem::STS},
{"MVD", fles::Subsystem::MVD},
{"RICH", fles::Subsystem::RICH},
{"TRD", fles::Subsystem::TRD},
{"TRD2D", fles::Subsystem::TRD2D},
{"MUCH", fles::Subsystem::MUCH},
{"TOF", fles::Subsystem::TOF},
// Other detectors (experimental)
{"ECAL", fles::Subsystem::ECAL},
{"PSD", fles::Subsystem::PSD},
{"BMON", fles::Subsystem::BMON},
{"TRB3", fles::Subsystem::TRB3},
{"Hodoscope", fles::Subsystem::Hodoscope},
{"Cherenkov", fles::Subsystem::Cherenkov},
{"LeadGlass", fles::Subsystem::LeadGlass},
// FLES (pattern generators)
{"FLES", fles::Subsystem::FLES},
);
CBM_ENUM_DICT(cbm::algo::Step,
{"Unpack", Step::Unpack},
{"DigiTrigger", Step::DigiTrigger},
{"LocalReco", Step::LocalReco},
{"Tracking", Step::Tracking}
);
CBM_ENUM_DICT(cbm::algo::RecoData,
{"DigiTimeslice", RecoData::DigiTimeslice},
{"DigiEvent", RecoData::DigiEvent},
{"Cluster", RecoData::Cluster},
{"Hit", RecoData::Hit},
{"Track", RecoData::Track}
);
CBM_ENUM_DICT(cbm::algo::Setup,
{"mCBM2022", cbm::algo::Setup::mCBM2022},
{"mCBM2024_03", cbm::algo::Setup::mCBM2024_03},
{"mCBM2024_05", cbm::algo::Setup::mCBM2024_05},
{"mCBM2025_02", cbm::algo::Setup::mCBM2025_02}
);
CBM_ENUM_DICT(cbm::algo::QaStep,
{"BeamBmon", cbm::algo::QaStep::BeamBmon},
{"UnpackBmon", cbm::algo::QaStep::UnpackBmon},
{"UnpackSts", cbm::algo::QaStep::UnpackSts},
{"UnpackMvd", cbm::algo::QaStep::UnpackMvd},
{"UnpackRich", cbm::algo::QaStep::UnpackRich},
{"UnpackTrd1d", cbm::algo::QaStep::UnpackTrd1d},
{"UnpackTrd2d", cbm::algo::QaStep::UnpackTrd2d},
{"UnpackMuch", cbm::algo::QaStep::UnpackMuch},
{"UnpackTof", cbm::algo::QaStep::UnpackTof},
{"UnpackFsd", cbm::algo::QaStep::UnpackFsd},
{"EventBuilding", cbm::algo::QaStep::EventBuilding},
{"RecoBmon", cbm::algo::QaStep::RecoBmon},
{"RecoSts", cbm::algo::QaStep::RecoSts},
{"RecoMvd", cbm::algo::QaStep::RecoMvd},
{"RecoRich", cbm::algo::QaStep::RecoRich},
{"RecoTrd1d", cbm::algo::QaStep::RecoTrd1d},
{"RecoTrd2d", cbm::algo::QaStep::RecoTrd2d},
{"RecoMuch", cbm::algo::QaStep::RecoMuch},
{"RecoTof", cbm::algo::QaStep::RecoTof},
{"RecoFsd", cbm::algo::QaStep::RecoFsd},
{"Tracking", cbm::algo::QaStep::Tracking},
{"V0Finder", cbm::algo::QaStep::V0Finder},
{"V0Trigger", cbm::algo::QaStep::V0Trigger}
);
#endif
/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#include "DigiData.h"
using namespace cbm::algo;
// Ctor / Dtor defined in .cxx file so we can use forward declarations for digi types in the header
DigiData::DigiData() {}
DigiData::~DigiData() {}
DigiData::DigiData(const CbmDigiData& storable)
: fSts(ToPODVector(storable.fSts.fDigis))
, fMuch(ToPODVector(storable.fMuch.fDigis))
, fTof(ToPODVector(storable.fTof.fDigis))
, fBmon(ToPODVector(storable.fBmon.fDigis))
, fTrd(ToPODVector(storable.fTrd.fDigis))
, fTrd2d(ToPODVector(storable.fTrd2d.fDigis))
, fRich(ToPODVector(storable.fRich.fDigis))
, fPsd(ToPODVector(storable.fPsd.fDigis))
, fFsd(ToPODVector(storable.fFsd.fDigis))
{
}
size_t DigiData::Size(ECbmModuleId system) const
{
switch (system) {
case ECbmModuleId::kSts: return fSts.size();
case ECbmModuleId::kMuch: return fMuch.size();
case ECbmModuleId::kTof: return fTof.size();
case ECbmModuleId::kBmon: return fBmon.size();
case ECbmModuleId::kTrd: return fTrd.size();
case ECbmModuleId::kTrd2d: return fTrd2d.size();
case ECbmModuleId::kRich: return fRich.size();
case ECbmModuleId::kPsd: return fPsd.size();
case ECbmModuleId::kFsd: return fFsd.size();
default: throw std::runtime_error("DigiData: Invalid system Id " + ::ToString(system));
}
}
size_t DigiData::TotalSize() const
{
return fSts.size() + fMuch.size() + fTof.size() + fBmon.size() + fTrd.size() + fTrd2d.size() + fRich.size()
+ fPsd.size() + fFsd.size();
}
size_t DigiData::TotalSizeBytes() const
{
return sizeof(CbmStsDigi) * fSts.size() + sizeof(CbmMuchDigi) * fMuch.size() + sizeof(CbmTofDigi) * fTof.size()
+ sizeof(CbmBmonDigi) * fBmon.size() + sizeof(CbmTrdDigi) * fTrd.size() + sizeof(CbmTrdDigi) * fTrd2d.size()
+ sizeof(CbmRichDigi) * fRich.size() + sizeof(CbmPsdDigi) * fPsd.size() + sizeof(CbmFsdDigi) * fFsd.size();
}
CbmDigiData DigiData::ToStorable() const
{
return CbmDigiData{
.fBmon =
{
.fDigis = ToStdVector(fBmon),
},
.fSts =
{
.fDigis = ToStdVector(fSts),
},
.fMuch =
{
.fDigis = ToStdVector(fMuch),
},
.fRich =
{
.fDigis = ToStdVector(fRich),
},
.fTrd =
{
.fDigis = ToStdVector(fTrd),
},
.fTrd2d =
{
.fDigis = ToStdVector(fTrd2d),
},
.fTof =
{
.fDigis = ToStdVector(fTof),
},
.fPsd =
{
.fDigis = ToStdVector(fPsd),
},
.fFsd =
{
.fDigis = ToStdVector(fFsd),
},
};
}
std::vector<DigiEvent> DigiEvent::FromCbmDigiEvents(const std::vector<CbmDigiEvent>& events)
{
std::vector<DigiEvent> result;
result.reserve(events.size());
for (const auto& event : events) {
result.emplace_back(event);
}
return result;
}
std::vector<CbmDigiEvent> DigiEvent::ToCbmDigiEvents(const std::vector<DigiEvent>& events)
{
std::vector<CbmDigiEvent> result;
result.reserve(events.size());
for (const auto& event : events) {
result.emplace_back(event.ToStorable());
}
return result;
}
DigiEvent::DigiEvent(const CbmDigiEvent& storable)
: DigiData(storable.fData)
, fNumber(storable.fNumber)
, fTime(storable.fTime)
, fSelectionTriggers(storable.fSelectionTriggers)
{
}
CbmDigiEvent DigiEvent::ToStorable() const
{
return CbmDigiEvent{
.fData = DigiData::ToStorable(),
.fNumber = fNumber,
.fTime = fTime,
.fSelectionTriggers = fSelectionTriggers,
};
}
/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#ifndef CBM_ALGO_BASE_DIGI_DATA_H
#define CBM_ALGO_BASE_DIGI_DATA_H
#include "CbmBmonDigi.h"
#include "CbmDigiData.h"
#include "CbmDigiEvent.h"
#include "CbmEventTriggers.h"
#include "CbmFsdDigi.h"
#include "CbmMuchDigi.h"
#include "CbmPsdDigi.h"
#include "CbmRichDigi.h"
#include "CbmStsDigi.h"
#include "CbmTofDigi.h"
#include "CbmTrdDigi.h"
#include "PODVector.h"
namespace cbm::algo
{
/**
* @brief Collection of digis from all detector systems
*
* Very similar to CbmDigiData. CbmDigiData is meant for file storage,
* while this is used for the actual processing. Seperate classes
* allow for more flexibility and easier optimization.
*
* @see CbmDigiData
* @note Uses PODVector for storage, so memory is not initialized by default.
*/
struct DigiData {
PODVector<CbmStsDigi> fSts; ///< Unpacked STS digis
PODVector<CbmMuchDigi> fMuch; ///< Unpacked MUCH digis
PODVector<CbmTofDigi> fTof; ///< Unpacked TOF digis
PODVector<CbmBmonDigi> fBmon; ///< Unpacked Bmon digis
PODVector<CbmTrdDigi> fTrd; ///< Unpacked TRD digis
PODVector<CbmTrdDigi> fTrd2d; ///< Unpacked TRD2D digis
PODVector<CbmRichDigi> fRich; ///< Unpacked RICH digis
PODVector<CbmPsdDigi> fPsd; ///< Unpacked PSD digis
PODVector<CbmFsdDigi> fFsd; ///< Unpacked FSD digis
DigiData();
~DigiData();
explicit DigiData(const CbmDigiData& storable);
/**
* @brief Get the number of digis for a given subsystem
*
* @param system Subsystem to get the number of digis for
* @todo Should use fles::Subsystem instead ECbmModuleId
*/
size_t Size(ECbmModuleId system) const;
/**
* @brief Get the total number of digis across all subsystems.
*/
size_t TotalSize() const;
/**
* @brief Get the total number of bytes used by all digis.
*/
size_t TotalSizeBytes() const;
/**
* @brief Convert to CbmDigiData for file storage
*
* @note This is a very expensive operation, as it copies all data.
*/
CbmDigiData ToStorable() const;
};
/**
* @brief Event data with event number and trigger time
*
* @see CbmDigitEvent
* @note Uses PODVector for storage, so memory is not initialized by default.
*/
struct DigiEvent : public DigiData {
// FIXME: Event number not set yet!
uint64_t fNumber = -1; ///< Event identifier
double fTime = 0; ///< Event trigger time [ns]
CbmEventTriggers fSelectionTriggers;
static std::vector<DigiEvent> FromCbmDigiEvents(const std::vector<CbmDigiEvent>& events);
static std::vector<CbmDigiEvent> ToCbmDigiEvents(const std::vector<DigiEvent>& events);
DigiEvent() = default;
explicit DigiEvent(const CbmDigiEvent& storable);
/**
* @brief Convert to CbmDigiEvent for file storage
*
* @note This is a very expensive operation, as it copies all data.
*/
CbmDigiEvent ToStorable() const;
};
} // namespace cbm::algo
#endif // CBM_ALGO_BASE_DIGI_DATA_H
/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#ifndef CBM_ALGO_BASE_EXCEPTIONS_H
#define CBM_ALGO_BASE_EXCEPTIONS_H
#include <exception>
#include <string_view>
#include <fmt/format.h>
namespace cbm::algo
{
namespace detail
{
/**
* @brief Base class for exceptions.
*
* @note Should not be thrown directly. Use one of the derived classes instead.
*/
struct Exception : std::runtime_error {
template<typename... Args>
Exception(std::string_view fmt, Args&&... args)
: std::runtime_error(fmt::format(fmt, std::forward<Args>(args)...))
{
}
};
} // namespace detail
/**
* @brief Indicates an unrecoverable error. Should tear down the process.
*/
struct FatalError : detail::Exception {
using Exception::Exception;
};
/**
* Indicates an error during timeslice processing. Timeslice will be discarded.
* Processing can continue with new timeslice.
*/
struct ProcessingError : detail::Exception {
using Exception::Exception;
};
} // namespace cbm::algo
#endif
/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#ifndef CBM_ALGO_BASE_HISTOGRAM_SENDER_H
#define CBM_ALGO_BASE_HISTOGRAM_SENDER_H
#include <boost/archive/binary_oarchive.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#ifdef BOOST_IOS_HAS_ZSTD
#include <boost/iostreams/filter/zstd.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#endif
#include <boost/iostreams/stream.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/vector.hpp>
#include <string>
#include <string_view>
#include <zmq.hpp>
namespace cbm::algo
{
class HistogramSender {
public:
HistogramSender(std::string_view address, int32_t hwm = 1, bool compression = false)
: fHistComChan(address)
, fHistHighWaterMark(hwm)
, fbCompression(compression)
, fZmqContext(1)
, fZmqSocket(fZmqContext, zmq::socket_type::push)
{
fZmqSocket.set(zmq::sockopt::sndhwm, fHistHighWaterMark); // High-Water Mark, max nb updates kept in out buffer
fZmqSocket.connect(fHistComChan); // This side "connects" to socket => Other side should have "bind"!!!!
}
/** @brief Serialize object and send it to the histogram server
** @param obj: object to be serialized in the message, e.g. config pairs of strings or QaData
** @param flags: or'ed values from zmq::send_flags, typ. zmq::send_flags::sndmore to indicate multi-parts message
**/
template<typename Object>
void PrepareAndSendMsg(const Object& obj, zmq::send_flags flags)
{
/// Needed ressources (serializd string, boost inserter, boost stream, boost binary output archive)
namespace b_io = boost::iostreams;
namespace b_ar = boost::archive;
std::string serial_str;
b_io::back_insert_device<std::string> inserter(serial_str);
b_io::stream<b_io::back_insert_device<std::string>> bstream(inserter);
serial_str.clear();
if (fbCompression) {
#ifdef BOOST_IOS_HAS_ZSTD
std::unique_ptr<b_io::filtering_ostream> out_ = std::make_unique<b_io::filtering_ostream>();
out_->push(b_io::zstd_compressor(b_io::zstd::best_speed));
out_->push(bstream);
std::unique_ptr<b_ar::binary_oarchive> oarchive_ =
std::make_unique<b_ar::binary_oarchive>(*out_, b_ar::no_header);
*oarchive_ << obj;
#else
throw std::runtime_error("Unsupported ZSTD compression (boost) for histograms emissions channel");
#endif
}
else {
b_ar::binary_oarchive oa(bstream);
oa << obj;
}
bstream.flush();
zmq::message_t msg(serial_str.size());
std::copy_n(static_cast<const char*>(serial_str.data()), msg.size(), static_cast<char*>(msg.data()));
/// FIXME: read return value to catch EAGAIN indicating a failed emission, use it outside to skip histo reset
fZmqSocket.send(msg, flags | zmq::send_flags::dontwait);
}
private:
std::string fHistComChan = "tcp://127.0.0.1:56800";
int32_t fHistHighWaterMark = 1;
bool fbCompression = false;
zmq::context_t fZmqContext; ///< ZMQ context FIXME: should be only one context per binary!
zmq::socket_t fZmqSocket; ///< ZMQ socket to histogram server
};
} // namespace cbm::algo
#endif
/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Volker Friese [committer] */
#include "MainConfig.h"
#include <fstream>
#include <yaml-cpp/yaml.h>
namespace cbm::algo
{
// ----- Load configuration from YAML file --------------------------------
void MainConfig::LoadYaml(const std::string& filename)
{
YAML::Node config = YAML::LoadFile(filename);
// --- Digi trigger
fTriggerDet = ToCbmModuleIdCaseInsensitive(config["trigger"]["detector"].as<std::string>());
fTriggerWin = config["trigger"]["window"].as<double>();
fTriggerThreshold = config["trigger"]["threshold"].as<size_t>();
fTriggerDeadTime = config["trigger"]["deadtime"].as<double>();
// --- Event builder: (detector -> (tMin, tMax))
if (auto eventbuilder = config["eventbuilder"]) {
if (auto windows = eventbuilder["windows"]) {
for (YAML::const_iterator it = windows.begin(); it != windows.end(); ++it) {
auto det = ToCbmModuleIdCaseInsensitive(it->first.as<std::string>());
auto lower = it->second[0].as<double>();
auto upper = it->second[1].as<double>();
fEvtbuildWindows[det] = std::make_pair(lower, upper);
}
}
}
// --- Event selector parameters
fSelectMinStationsSts = config["selector"]["minStationsSts"].as<size_t>();
fSelectMinStationsTof = config["selector"]["minStationsTof"].as<size_t>();
fSelectMinDigisBmon = config["selector"]["minDigisBmon"].as<size_t>();
// --- Branch persistence in output file
fStoreTimeslice = config["store"]["timeslice"].as<bool>();
fStoreTrigger = config["store"]["triggers"].as<bool>();
fStoreEvents = config["store"]["events"].as<bool>();
// --- QA publishing
fHttpServerRefreshRate = config["qa"]["refreshrate"].as<int32_t>(fHttpServerRefreshRate);
}
// ----------------------------------------------------------------------------
// ----- Save configuration to YAML file ----------------------------------
void MainConfig::SaveYaml(const std::string& filename)
{
YAML::Node config;
// --- Digi trigger
config["trigger"]["detector"] = ToString(fTriggerDet);
config["trigger"]["window"] = fTriggerWin;
config["trigger"]["threshold"] = fTriggerThreshold;
config["trigger"]["deadtime"] = fTriggerDeadTime;
// --- Event builder: (detector -> (tMin, tMax))
for (const auto& [key, value] : fEvtbuildWindows) {
auto det = ToString(key);
config["eventbuilder"]["windows"][det].push_back(value.first);
config["eventbuilder"]["windows"][det].push_back(value.second);
};
// --- Event selector
config["selector"]["minStationsSts"] = fSelectMinStationsSts;
config["selector"]["minStationsTof"] = fSelectMinStationsTof;
config["selector"]["minDigisBmon"] = fSelectMinDigisBmon;
// --- Branch persistence in output file
config["store"]["timeslice"] = fStoreTimeslice;
config["store"]["triggers"] = fStoreTrigger;
config["store"]["events"] = fStoreEvents;
// --- QA publishing
config["qa"]["refreshrate"] = fHttpServerRefreshRate;
// ---
std::ofstream fout(filename);
fout << config;
}
// ----------------------------------------------------------------------------
} /* namespace cbm::algo */
/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Volker Friese [committer] */
#ifndef ALGO_BASE_MAINCONFIG_H_
#define ALGO_BASE_MAINCONFIG_H_
#include "CbmDefs.h"
#include <map>
namespace cbm::algo
{
/** @class MainConfig
** @brief Configuration of online data processing
** @author Volker Friese <v.friese@gsi.de>
** @since 10 July 2023
**/
class MainConfig {
public: // methods
/** @brief Constructor **/
MainConfig() = default;
/** @brief Constructor **/
~MainConfig() = default;
/** @brief Load from YAML file **/
void LoadYaml(const std::string& filename);
/** @brief Save to YAML file **/
void SaveYaml(const std::string& filename);
public: // data members
// --- Digi trigger
ECbmModuleId fTriggerDet = ECbmModuleId::kNotExist; // Trigger detector
double fTriggerWin = 0.; // Trigger window size [ns]
size_t fTriggerThreshold = 0; // Minimum number if digis in trigger window
double fTriggerDeadTime = 0.; // Minimal time between two trigger [ns]
// --- Event builder: (detector -> (tMin, tMax))
std::map<ECbmModuleId, std::pair<double, double>> fEvtbuildWindows = {};
// --- Event selector
size_t fSelectMinStationsSts = 0;
size_t fSelectMinStationsTof = 0;
size_t fSelectMinDigisBmon = 0;
// --- Branch persistence in output file
bool fStoreTimeslice = false;
bool fStoreTrigger = false;
bool fStoreEvents = false;
// --- QA publishing
int32_t fHttpServerRefreshRate = 100;
};
} /* namespace cbm::algo */
#endif /* ALGO_BASE_MAINCONFIG_H_ */
/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#include "Options.h"
#include "util/StlUtils.h"
#include <boost/program_options.hpp>
#include <iostream>
#include <iterator>
#include <unordered_map>
using namespace cbm::algo;
namespace po = boost::program_options;
using fles::Subsystem;
namespace std
{
template<class T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v)
{
copy(v.begin(), v.end(), std::ostream_iterator<T>(os, " "));
return os;
}
} // namespace std
#ifndef CBM_ONLINE_USE_FAIRLOGGER
void validate(boost::any& v, const std::vector<std::string>& values, severity_level*, int)
{
static const std::unordered_map<std::string, severity_level> levels{
{"trace", severity_level::trace}, {"debug", severity_level::debug}, {"status", severity_level::status},
{"info", severity_level::info}, {"warning", severity_level::warning}, {"error", severity_level::error},
{"fatal", severity_level::fatal}};
po::validators::check_first_occurrence(v);
const std::string& s = po::validators::get_single_string(values);
auto it = levels.find(s);
if (it == levels.end()) throw po::validation_error(po::validation_error::invalid_option_value);
v = it->second;
}
#endif // Not CBM_ONLINE_USE_FAIRLOGGER
Options::Options(int argc, char** argv)
{
po::options_description required("Required options");
// clang-format off
required.add_options()
("param-dir,p", po::value(&fParamsDir)->value_name("<folder>")->required(),
"read program options from this folder")
("input-locator,i", po::value(&fInputLocator)->value_name("<locator>")->required(),
"URI specifying input timeslice source")
;
// clang-format on
po::options_description generic("Other options");
// clang-format off
generic.add_options()
("output,o", po::value(&fOutputFile)->default_value("")->value_name("<file>"),
"write results to file")
("device,d", po::value(&fDevice)->default_value("cpu")->value_name("<device>"),
"select device (cpu, cuda0, cuda1, hip0, ...)")
#ifndef CBM_ONLINE_USE_FAIRLOGGER
("log-level,l", po::value(&fLogLevel)->default_value(info)->value_name("<level>"),
"set log level (debug, info, warning, error, fatal)")
#endif // Not CBM_ONLINE_USE_FAIRLOGGER
("monitor,m", po::value(&fMonitorUri)->value_name("<uri>")->implicit_value("file:cout"),
"URI specifying monitor output (e.g. file:/tmp/monitor.txt, influx1:login:8086:cbmreco_status). Prints to cout when no argument is given. Monitor is disabled when flag is not set.")
("histogram", po::value(&fHistogramUri)->value_name("<uri>"), "URI to specify histogram server")
("histoshwm", po::value(&fHistogramHwm)->default_value(1)->value_name("<num>"),
"High-Water Mark for ZMQ socket to histogram server in messages:\n"
" 0 = no buffering, num = nb updates kept in buffer if not pulled by server \n"
" Tune to avoid too high memory usage but also adapt to server load!")
("aux-data", po::value(&fCollectAuxData)->implicit_value(true), "Enables collecting of auxiliary data from algorithms")
("qa", po::value(&fQaSteps)->multitoken()->default_value({QaStep::UnpackSts, QaStep::EventBuilding, QaStep::Tracking})->value_name("<qa steps>"),
"space separated list of QA Steps to enable (BeamBmon, UnpackSts, EventBuilding, Tracking, ...)")
#ifdef BOOST_IOS_HAS_ZSTD
("hist-compr", po::bool_switch(&fCompressHistograms)->default_value(false),
"enables ZSTD compression of the outgoing histograms stream (decompression needed in target server!)")
#endif
("log-file,L", po::value(&fLogFile)->value_name("<file>"),
"write log messages to file")
("output-types,O", po::value(&fOutputTypes)->multitoken()->value_name("<types>"),
"space separated list of reconstruction output types (Hit, Tracks, DigiTimeslice, DigiEvent, ...)")
("compress-archive", po::bool_switch(&fCompressArchive)->default_value(false), "Enable compression for output archives")
("steps", po::value(&fRecoSteps)->multitoken()->default_value({Step::Unpack, Step::DigiTrigger, Step::LocalReco, Step::Tracking})->value_name("<steps>"),
"space separated list of reconstruction steps (unpack, digitrigger, localreco, ...)")
("event-reco", po::bool_switch(&fReconstructDigiEvents)->default_value(false), "runs digi event reconstruction (local reco, tracking, trigger)")
("systems,s", po::value(&fDetectors)->multitoken()->default_value({Subsystem::STS, Subsystem::TOF, Subsystem::BMON, Subsystem::MUCH, Subsystem::RICH, Subsystem::TRD, Subsystem::TRD2D})->value_name("<detectors>"),
"space separated list of detectors to process (sts, mvd, ...)")
("child-id,c", po::value(&fChildId)->default_value("00")->value_name("<id>"), "online process id on node")
("run-id,r", po::value(&fRunId)->default_value(2391)->value_name("<RunId>"), "Run ID, for now flesctl run index, later run start time")
("run-start", po::value(&fRunStartTime)->default_value(0)->value_name("<RunStart >"), "Run start time in ns, can be fles start or online start")
("num-ts,n", po::value(&fNumTimeslices)->default_value(-1)->value_name("<num>"),
"Stop after <num> timeslices (-1 = all)")
("skip-ts", po::value(&fSkipTimeslices)->default_value(0)->value_name("<num>"),
"Skip first <num> timeslices")
("omp", po::value(&fNumOMPThreads)->default_value(-1)->value_name("<num>"),
"Set number of OpenMP threads (-1 = use OMP_NUM_THREADS environment variable)")
("times,t", po::value(&fProfilingLevel)->default_value(ProfilingNone)->implicit_value(ProfilingPerTS),
"Print kernel times (Can opt. be given a value: Use none to disable or summary to only print aggregated times.)")
("timings-file", po::value(&fTimingsFile)->value_name("<file>"),
"Write profiling times to yaml file (only when '-t' is set)")
("dump-archive", po::bool_switch(&fDumpArchive)->default_value(false),
"Dump archive content to stdout and exit. Provide archive with '-i'. (This is a hack to quick check archive content until we have proper tooling.)")
("release-mode,R",po::value<bool>(&fReleaseMode)->implicit_value(true),
"Copy and release each timeslice immediately after receiving it")
("help,h",
"produce help message")
;
// clang-format on
po::options_description cmdline_options;
cmdline_options.add(required).add(generic);
po::variables_map vm;
po::command_line_parser parser{argc, argv};
parser.options(cmdline_options);
try {
auto result = parser.run();
po::store(result, vm);
}
catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
std::cerr << "Use '-h' to display all valid options." << std::endl;
std::exit(EXIT_FAILURE);
}
if (vm.count("help") > 0) {
std::cout << cmdline_options << std::endl;
std::exit(EXIT_SUCCESS);
}
try {
po::notify(vm);
}
catch (const po::required_option& e) {
std::cerr << "Error: " << e.what() << std::endl;
std::cerr << "Use '-h' to display all valid options." << std::endl;
std::exit(EXIT_FAILURE);
}
}
bool Options::HasOutput(RecoData recoData) const { return Contains(fOutputTypes, recoData); }
bool Options::Has(fles::Subsystem detector) const { return Contains(fDetectors, detector); }
bool Options::Has(Step step) const { return Contains(fRecoSteps, step); }
bool Options::Has(QaStep qastep) const { return Contains(fQaSteps, qastep); }
/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#ifndef CBM_ALGO_BASE_OPTIONS_H
#define CBM_ALGO_BASE_OPTIONS_H
#include "AlgoFairloggerCompat.h"
#include "Definitions.h"
#include "compat/Filesystem.h"
#include "util/ProfilingLevel.h"
#include <set>
#include <string>
#include <vector>
namespace cbm::algo
{
class Options {
public:
Options() = default;
Options(int argc, char** argv);
fs::path ParamsDir() const { return fParamsDir; }
const std::string& InputLocator() const { return fInputLocator; }
fs::path OutputFile() const { return fOutputFile; }
#ifndef CBM_ONLINE_USE_FAIRLOGGER
severity_level LogLevel() const { return fLogLevel; }
#endif // Not CBM_ONLINE_USE_FAIRLOGGER
fs::path LogFile() const { return fLogFile; }
const std::string& Device() const { return fDevice; }
const std::string& MonitorUri() const { return fMonitorUri; }
const std::string& HistogramUri() const { return fHistogramUri; }
const int32_t& HistogramHwm() const { return fHistogramHwm; }
bool CollectAuxData() const { return fCollectAuxData; }
const bool& CompressHistograms() const { return fCompressHistograms; }
bool CollectKernelTimes() const { return fProfilingLevel != ProfilingNone; }
ProfilingLevel Profiling() const { return fProfilingLevel; }
fs::path TimingsFile() const { return fTimingsFile; }
int NumTimeslices() const { return fNumTimeslices; }
int SkipTimeslices() const { return fSkipTimeslices; }
std::optional<int> NumOMPThreads() const
{
// omp doesn't allow negative number of threads, so we use -1 to indicate that the user didn't specify a number
// and omp should use OMP_NUM_THREADS environment variable or the default instead
return fNumOMPThreads > 0 ? std::make_optional(fNumOMPThreads) : std::nullopt;
}
const std::string& ChildId() const { return fChildId; }
uint64_t RunId() const { return fRunId; }
uint64_t RunStart() const { return fRunStartTime; }
bool DumpArchive() const { return fDumpArchive; }
bool ReleaseMode() const { return fReleaseMode; }
const std::vector<Step>& Steps() const { return fRecoSteps; }
const std::vector<RecoData>& OutputTypes() const { return fOutputTypes; }
bool HasOutput(RecoData recoData) const;
bool CompressArchive() const { return fCompressArchive; }
const std::vector<fles::Subsystem>& Detectors() const { return fDetectors; }
bool Has(fles::Subsystem detector) const;
bool Has(Step step) const;
bool Has(QaStep qastep) const;
bool ReconstructDigiEvents() const { return fReconstructDigiEvents; }
private: // members
std::string fParamsDir; // TODO: can we make this a std::path?
std::string fInputLocator;
std::string fOutputFile;
#ifndef CBM_ONLINE_USE_FAIRLOGGER
severity_level fLogLevel;
#endif // Not CBM_ONLINE_USE_FAIRLOGGER
std::string fLogFile;
std::string fDevice;
std::string fMonitorUri;
std::string fHistogramUri;
int32_t fHistogramHwm;
bool fCompressHistograms = false;
std::vector<QaStep> fQaSteps;
bool fDumpArchive = false;
bool fReleaseMode = false;
ProfilingLevel fProfilingLevel = ProfilingNone;
std::string fTimingsFile;
int fNumTimeslices = -1;
int fSkipTimeslices = 0;
int fNumOMPThreads = -1;
std::vector<Step> fRecoSteps;
std::vector<RecoData> fOutputTypes;
bool fCompressArchive = false;
std::vector<fles::Subsystem> fDetectors;
std::string fChildId = "00";
uint64_t fRunId = 2391;
uint64_t fRunStartTime = 0;
bool fCollectAuxData = false;
bool fReconstructDigiEvents = false;
};
} // namespace cbm::algo
#endif
/* Copyright (C) 2022 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#ifndef CBM_ALGO_BASE_POD_VECTOR_H
#define CBM_ALGO_BASE_POD_VECTOR_H
#include "util/PODAllocator.h"
#include <vector>
namespace cbm::algo
{
/**
* @brief PODVector is a std::vector that doesn't initialize its elements.
*/
template<class T>
using PODVector = std::vector<T, PODAllocator<T>>;
template<typename T>
std::vector<T> ToStdVector(const PODVector<T>& vec)
{
return std::vector<T>(vec.begin(), vec.end());
}
template<typename T>
PODVector<T> ToPODVector(const std::vector<T>& vec)
{
return PODVector<T>(vec.begin(), vec.end());
}
} // namespace cbm::algo
#endif // CBM_ALGO_BASE_POD_VECTOR_H
/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#ifndef CBM_ALGO_BASE_PARTITIONED_SPAN_H
#define CBM_ALGO_BASE_PARTITIONED_SPAN_H
#include "Definitions.h"
#include <array>
#include <gsl/span>
#include <stdexcept>
#include <vector>
namespace cbm::algo
{
template<typename T, typename Allocator>
class PartitionedVector;
namespace detail
{
template<typename U, typename T>
using EnableOnConst = std::enable_if_t<std::is_const_v<T> && std::is_same_v<U, std::remove_cv_t<T>>>;
template<typename U, typename T>
using EnableOnNonConst = std::enable_if_t<!std::is_const_v<T> && std::is_same_v<U, std::remove_cv_t<T>>>;
} // namespace detail
template<typename T>
class PartitionedSpan {
public:
PartitionedSpan() : fData(), fOffsets(NullOffset), fAdresses() { EnsureDimensions(); }
// Intellisense and clang workaround, fails on template deduction with stl containers for some reason
// #if defined(__INTELLISENSE__) || defined(__clang__)
template<typename Allocator>
PartitionedSpan(std::vector<T, Allocator>& container, gsl::span<const size_t> offsets,
gsl::span<const u32> addresses)
: fData(container)
, fOffsets(offsets)
, fAdresses(addresses)
{
EnsureDimensions();
}
// FIXME disable if T is non-const via SFINAE, otherwise get misleading compiler errors
template<typename Allocator>
PartitionedSpan(const std::vector<T, Allocator>& container, gsl::span<const size_t> offsets,
gsl::span<const u32> addresses)
: fData(container)
, fOffsets(offsets)
, fAdresses(addresses)
{
EnsureDimensions();
}
template<size_t N>
PartitionedSpan(std::array<T, N>& container, gsl::span<const size_t> offsets, gsl::span<const u32> addresses)
: fData(container)
, fOffsets(offsets)
, fAdresses(addresses)
{
EnsureDimensions();
}
// FIXME disable if T is non-const via SFINAE
template<size_t N>
PartitionedSpan(const std::array<T, N>& container, gsl::span<const size_t> offsets, gsl::span<const u32> addresses)
: fData(container)
, fOffsets(offsets)
, fAdresses(addresses)
{
EnsureDimensions();
}
// #endif
PartitionedSpan(gsl::span<T> data, gsl::span<const size_t> offsets, gsl::span<const u32> addresses)
: fData(data)
, fOffsets(offsets)
, fAdresses(addresses)
{
EnsureDimensions();
}
template<typename U, typename Allocator, typename = detail::EnableOnConst<U, T>>
PartitionedSpan(const PartitionedVector<U, Allocator>& container)
: fData(container.Data())
, fOffsets(container.Offsets())
, fAdresses(container.Addresses())
{
EnsureDimensions();
}
template<typename U, typename Allocator, typename = detail::EnableOnNonConst<U, T>>
PartitionedSpan(PartitionedVector<U, Allocator>& container)
: fData(container.Data())
, fOffsets(container.Offsets())
, fAdresses(container.Addresses())
{
EnsureDimensions();
}
template<typename U, typename = detail::EnableOnConst<U, T>>
PartitionedSpan(PartitionedSpan<U> other)
: fData(other.Data())
, fOffsets(other.Offsets())
, fAdresses(other.Addresses())
{
}
gsl::span<T> operator[](size_t i) const
{
EnsureBounds(i);
return UnsafePartitionSpan(i);
}
u32 Address(size_t i) const
{
EnsureBounds(i);
return fAdresses[i];
}
std::pair<gsl::span<T>, u32> Partition(size_t i) const
{
EnsureBounds(i);
return std::pair<gsl::span<T>, u32>(UnsafePartitionSpan(i), fAdresses[i]);
}
size_t NPartitions() const { return fAdresses.size(); }
size_t Size(size_t i) const
{
EnsureBounds(i);
return UnsafeSize(i);
}
size_t NElements() const { return fData.size(); }
gsl::span<T> Data() const { return fData; }
gsl::span<const u32> Addresses() const { return fAdresses; }
gsl::span<const size_t> Offsets() const { return fOffsets; }
private:
// Required for default constructor, don't use std::array to avoid additional dependency
static constexpr size_t NullOffset[1] = {0};
gsl::span<T> fData;
gsl::span<const size_t> fOffsets;
gsl::span<const u32> fAdresses;
// FIXME code duplication with PartitionedVector
void EnsureDimensions() const
{
if (fOffsets.size() - 1 != fAdresses.size()) {
throw std::runtime_error("PartitionedSpan: fOffsets.size() != fAdresses.size()");
}
if (fOffsets.front() != 0) throw std::runtime_error("PartitionedSpan: fOffsets.front() != 0");
if (fOffsets.back() != fData.size()) {
throw std::runtime_error("PartitionedSpan: fOffsets.back() != fData.size()");
}
}
void EnsureBounds(size_t i) const
{
if (i >= fAdresses.size()) throw std::out_of_range("PartitionedSpan: index out of bounds");
}
size_t UnsafeSize(size_t i) const { return fOffsets[i + 1] - fOffsets[i]; }
gsl::span<T> UnsafePartitionSpan(size_t i) const { return fData.subspan(fOffsets[i], UnsafeSize(i)); }
};
// template auto deduction
template<typename T, template<typename> class Container>
PartitionedSpan(Container<T>&, gsl::span<const size_t>, gsl::span<const u32>) -> PartitionedSpan<T>;
template<typename T, template<typename> class Container>
PartitionedSpan(const Container<T>&, gsl::span<const size_t>, gsl::span<const u32>) -> PartitionedSpan<const T>;
template<typename T, typename Allocator>
PartitionedSpan(PartitionedVector<T, Allocator>&) -> PartitionedSpan<T>;
template<typename T, typename Allocator>
PartitionedSpan(const PartitionedVector<T, Allocator>&) -> PartitionedSpan<const T>;
} // namespace cbm::algo
#endif