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 2037 additions and 0 deletions
/* Copyright (C) 2022 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer], Sebastian Heinemann */
#ifndef CBM_ALGO_BASE_POD_ALLOCATOR_H
#define CBM_ALGO_BASE_POD_ALLOCATOR_H
#include <cstdlib>
#include <type_traits>
#include <utility>
namespace cbm::algo
{
/**
* @brief Allocator for plain old data types.
*
* Custom allocator for plain old data types (POD) that does not initialize the allocated memory.
*/
template<class T>
class PODAllocator {
public:
// Eventually we should enable this assert, but not all Digis have a trivial constructor yet.
// static_assert(std::is_trivially_constructible_v<T>, "PODAllocator only works for POD types");
// Ensure T has no vtable
static_assert(std::is_standard_layout_v<T>, "PODAllocator only works with types with standard layout");
using value_type = T;
T* allocate(size_t size) { return static_cast<T*>(std::malloc(size * sizeof(T))); }
void deallocate(T* p_t, size_t) { std::free(p_t); }
template<class... Args>
void construct([[maybe_unused]] T* obj, Args&&... args)
{
if constexpr (sizeof...(args) > 0) new (obj) T(std::forward<Args>(args)...);
}
// Required for std::move
bool operator==(const PODAllocator&) const { return true; }
bool operator!=(const PODAllocator&) const { return false; }
};
} // namespace cbm::algo
#endif // CBM_ALGO_BASE_POD_ALLOCATOR_H
/* 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 "EnumDict.h"
namespace cbm::algo
{
enum ProfilingLevel
{
ProfilingNone = 0, //< Disable profiling
ProfilingSummary = 1, //< Only print times aggregated over all timeslices
ProfilingPerTS = 2, //< Print times for each timeslice
};
} // namespace cbm::algo
CBM_ENUM_DICT(cbm::algo::ProfilingLevel,
{"None", cbm::algo::ProfilingNone},
{"Summary", cbm::algo::ProfilingSummary},
{"PerTS", cbm::algo::ProfilingPerTS},
);
/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#include "StlUtils.h"
using namespace cbm;
std::string cbm::Capitalize(std::string_view str)
{
if (str.empty()) {
return std::string(str);
}
std::string result(str);
result[0] = std::toupper(result[0]);
for (size_t i = 1; i < result.size(); ++i)
result[i] = std::tolower(result[i]);
return result;
}
/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#pragma once
/**
* @file StlUtils.h
*
* @brief This file contains utility functions for STL containers.
*/
#include <algorithm>
#include <string>
#include <string_view>
namespace cbm
{
template<class C, class T>
bool Contains(const C& container, const T& value)
{
return std::find(container.begin(), container.end(), value) != container.end();
}
/**
* @brief Capitalize the first letter of a string. The rest of the string is made lowercase.
*/
std::string Capitalize(std::string_view str);
} // namespace cbm
/* Copyright (C) 2023-2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#include "TimingsFormat.h"
#include <iomanip>
#include <sstream>
#include <fmt/format.h>
#include <xpu/host.h>
#include <yaml-cpp/emitter.h>
// Helper functions
namespace
{
// Remove the cbm::algo:: prefix from kernel names
std::string_view KernelNameStripped(const xpu::kernel_timings& kt)
{
constexpr std::string_view prefix = "cbm::algo::";
if (kt.name().compare(0, prefix.size(), prefix) == 0) {
return kt.name().substr(prefix.size());
}
else {
return kt.name();
}
}
void MakeReportYamlEntry(std::string_view name, double time, double throughput, YAML::Emitter& ss)
{
if (!std::isnormal(throughput)) {
throughput = 0;
}
ss << YAML::Key << std::string{name};
ss << YAML::Flow << YAML::Value;
ss << YAML::BeginMap;
ss << YAML::Key << "time" << YAML::Value << time;
ss << YAML::Key << "throughput" << YAML::Value << throughput;
ss << YAML::EndMap;
}
void MakeReportYamlTimer(const xpu::timings& t, YAML::Emitter& ss)
{
ss << YAML::BeginMap;
MakeReportYamlEntry("wall", t.wall(), t.throughput(), ss);
MakeReportYamlEntry("memcpy_h2d", t.copy(xpu::h2d), t.throughput_copy(xpu::h2d), ss);
MakeReportYamlEntry("memcpy_d2h", t.copy(xpu::d2h), t.throughput_copy(xpu::d2h), ss);
MakeReportYamlEntry("memset", t.memset(), t.throughput_memset(), ss);
for (const auto& st : t.children()) {
if (st.kernels().empty() && st.children().empty()) {
MakeReportYamlEntry(st.name(), st.wall(), st.throughput(), ss);
}
else {
ss << YAML::Key << std::string{st.name()} << YAML::Value;
MakeReportYamlTimer(st, ss);
}
}
for (const auto& kt : t.kernels()) {
MakeReportYamlEntry(KernelNameStripped(kt), kt.total(), kt.throughput(), ss);
}
ss << YAML::EndMap;
}
} // namespace
namespace cbm::algo
{
class TimingsFormat {
public:
void Begin(size_t align)
{
fAlign = align;
fSS = std::stringstream();
}
void Title(std::string_view title)
{
Indent();
fSS << fmt::format("{:<{}}\n", title, fAlign);
}
std::string Finalize() { return fSS.str(); }
void Fmt(const xpu::timings& t)
{
fIndent += 2;
Measurement("Memcpy(h2d)", t.copy(xpu::h2d), t.throughput_copy(xpu::h2d));
NewLine();
Measurement("Memcpy(d2h)", t.copy(xpu::d2h), t.throughput_copy(xpu::d2h));
NewLine();
Measurement("Memset", t.memset(), t.throughput_memset());
NewLine();
// Merge subtimers with identical names
// Useful eg in unpacking, where unpacker might be called multiple times per TS
std::unordered_map<std::string, xpu::timings> subtimers;
for (xpu::timings& st : t.children()) {
subtimers[std::string(st.name())].merge(st);
}
for (auto& [name, st] : subtimers) {
if (st.kernels().empty() && st.children().empty()) {
Measurement(name, st.wall(), st.throughput());
NewLine();
}
else {
Title(name);
Fmt(st);
NewLine();
}
}
for (xpu::kernel_timings& kt : t.kernels()) {
Measurement(KernelNameStripped(kt), kt.total(), kt.throughput());
NewLine();
}
if (!t.kernels().empty()) {
Measurement("Kernel time", t.kernel_time(), t.throughput_kernels());
NewLine();
}
Measurement("Wall time", t.wall(), t.throughput());
fIndent -= 2;
}
void FmtSubtimers(const xpu::timings& t)
{
const auto subtimes = t.children();
for (auto it = subtimes.begin(); it != subtimes.end(); ++it) {
Title(it->name());
Fmt(*it);
if (std::next(it) != subtimes.end()) {
NewLine();
}
}
}
void FmtSummary(const xpu::timings& t)
{
fIndent += 2;
Measurement("Memcpy(h2d)", t.copy(xpu::h2d), t.throughput_copy(xpu::h2d));
NewLine();
Measurement("Memcpy(d2h)", t.copy(xpu::d2h), t.throughput_copy(xpu::d2h));
NewLine();
Measurement("Memset", t.memset(), t.throughput_memset());
NewLine();
Measurement("Kernel time", t.kernel_time(), t.throughput_kernels());
NewLine();
Measurement("Wall time", t.wall(), t.throughput());
fIndent -= 2;
}
void NewLine() { fSS << "\n"; }
private:
void Measurement(std::string_view name, f64 time, f64 throughput)
{
Indent();
fSS << std::setw(fAlign) << std::setfill(' ') << std::left << fmt::format("{}:", name);
Real(time, 10, 3, "ms");
if (std::isnormal(throughput)) {
fSS << " (";
Real(throughput, 7, 3, "GB/s");
fSS << ")";
}
}
void Real(double x, int width, int precision, std::string_view unit)
{
fSS << std::setw(width) << std::setfill(' ') << std::right << std::fixed << std::setprecision(precision) << x
<< " " << unit;
}
void Indent() { fSS << std::setw(fIndent) << std::setfill(' ') << std::left << ""; }
size_t fAlign = 0;
size_t fIndent = 0;
std::stringstream fSS;
}; // class TimingsFormat
std::string MakeReport(std::string_view title, const xpu::timings& t, size_t align)
{
TimingsFormat tf;
tf.Begin(align);
tf.Title(title);
tf.Fmt(t);
return tf.Finalize();
}
std::string MakeReportSubtimers(std::string_view title, const xpu::timings& t, size_t align)
{
TimingsFormat tf;
tf.Begin(align);
tf.Title(title);
tf.FmtSubtimers(t);
return tf.Finalize();
}
std::string MakeReportSummary(std::string_view title, const xpu::timings& t, size_t align)
{
TimingsFormat tf;
tf.Begin(align);
tf.Title(title);
tf.FmtSummary(t);
return tf.Finalize();
}
std::string MakeReportYaml(const xpu::timings& t)
{
YAML::Emitter ss;
ss << YAML::BeginDoc;
ss << YAML::Precision(6);
ss << YAML::BeginMap;
for (const auto& subtimer : t.children()) {
ss << YAML::Key << std::string{subtimer.name()};
ss << YAML::Value;
MakeReportYamlTimer(subtimer, ss);
}
ss << YAML::EndMap;
ss << YAML::EndDoc;
return ss.c_str();
}
} // namespace cbm::algo
/* Copyright (C) 2023-2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer]*/
#ifndef CBM_ALGO_BASE_UTIL_TIMINGSFORMAT_H
#define CBM_ALGO_BASE_UTIL_TIMINGSFORMAT_H
#include "Definitions.h"
#include <string>
#include <string_view>
namespace xpu
{
class timings;
}
namespace cbm::algo
{
/**
* @brief Print timings from top-level times and subtimers.
*/
std::string MakeReport(std::string_view title, const xpu::timings& t, size_t align = 40);
/**
* @brief Print timings from subtimers.
*/
std::string MakeReportSubtimers(std::string_view title, const xpu::timings& t, size_t align = 40);
/**
* @brief Only print the top-level times (Elapsed time, total kernel time, memcpy and memset times). Disregard subtimers and kernel times.
*/
std::string MakeReportSummary(std::string_view, const xpu::timings& t, size_t align = 40);
/**
* @brief Print timings in YAML format.
*/
std::string MakeReportYaml(const xpu::timings& t);
} // 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] */
#include <Timeslice.hpp>
namespace cbm::algo::ts_utils
{
inline size_t SizeBytes(const fles::Timeslice& ts)
{
size_t size = 0;
for (size_t i = 0; i < ts.num_components(); i++) {
size += ts.size_component(i);
}
return size;
}
} // namespace cbm::algo::ts_utils
/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#ifndef CBM_YAML_BASETYPES_H
#define CBM_YAML_BASETYPES_H
#pragma once
#include "Definitions.h"
#include <array>
#include <map>
#include <set>
#include <string>
#include <tuple>
#include <unordered_set>
#include <vector>
namespace cbm::algo::yaml
{
// clang-format off
using FundamentalTypes = std::tuple< bool
, u8, i8
, u16, i16
, u32, i32
, u64, i64
, f32, f64
, std::string
// Clang on macOS somehow treats unsigned long as a different type than uint64_t
#ifdef __APPLE__
, unsigned long, long
#endif
>;
// clang-format on
template<typename T, typename Tuple>
struct has_type;
template<typename T, typename... Us>
struct has_type<T, std::tuple<Us...>> : std::disjunction<std::is_same<T, Us>...> {
};
template<typename T>
constexpr bool IsFundamental = has_type<T, FundamentalTypes>::value;
template<typename T>
constexpr bool IsEnum = std::is_enum_v<T>;
template<typename T>
constexpr bool IsScalar = IsFundamental<T> || IsEnum<T>;
template<typename T, typename = std::enable_if_t<IsFundamental<T>>>
constexpr std::string_view Typename()
{
if constexpr (std::is_same_v<bool, T>) {
return "bool";
}
else if constexpr (std::is_same_v<u8, T>) {
return "u8";
}
else if constexpr (std::is_same_v<i8, T>) {
return "i8";
}
else if constexpr (std::is_same_v<u16, T>) {
return "u16";
}
else if constexpr (std::is_same_v<i16, T>) {
return "i16";
}
else if constexpr (std::is_same_v<u32, T>) {
return "u32";
}
else if constexpr (std::is_same_v<i32, T>) {
return "i32";
}
else if constexpr (std::is_same_v<f32, T>) {
return "f32";
}
else if constexpr (std::is_same_v<f64, T>) {
return "f64";
}
else if constexpr (std::is_same_v<std::string, T>) {
return "string";
}
else {
return "unknown";
}
}
template<typename>
struct is_std_vector : std::false_type {
};
template<typename T, typename A>
struct is_std_vector<std::vector<T, A>> : std::true_type {
};
template<typename T>
constexpr bool IsVector = is_std_vector<T>::value;
template<typename>
struct is_std_array : std::false_type {
};
template<typename T, std::size_t N>
struct is_std_array<std::array<T, N>> : std::true_type {
};
template<typename T>
constexpr bool IsArray = is_std_array<T>::value;
template<typename>
struct is_std_map : std::false_type {
};
template<typename K, typename V, typename C, typename A>
struct is_std_map<std::map<K, V, C, A>> : std::true_type {
};
template<typename T>
constexpr bool IsMap = is_std_map<T>::value;
template<typename>
struct is_std_set : std::false_type {
};
template<typename K, typename C, typename A>
struct is_std_set<std::set<K, C, A>> : std::true_type {
};
template<typename>
struct is_std_unordered_set : std::false_type {
};
template<typename K, typename H, typename E, typename A>
struct is_std_unordered_set<std::unordered_set<K, H, E, A>> : std::true_type {
};
template<typename T>
constexpr bool IsSet = is_std_set<T>::value || is_std_unordered_set<T>::value;
} // namespace cbm::algo::yaml
#endif // CBM_YAML_BASETYPES_H
set(INCLUDE_DIRECTORIES
${CMAKE_SOURCE_DIR}/algo/base # For "algo/base/yaml/*.h" included as relative "yaml/?????.h" to fit install tree
)
add_library(CbmYamlInterface INTERFACE)
target_include_directories(CbmYamlInterface
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(CbmYamlInterface
INTERFACE GSL
xpu
fmt::fmt
external::yaml-cpp
)
install(
FILES
BaseTypes.h
Property.h
Yaml.h
DESTINATION
include/yaml/
)
/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
SPDX-License-Identifier: GPL-3.0-only
Authors: Felix Weiglhofer [committer] */
#ifndef CBM_YAML_PROPERTY_H
#define CBM_YAML_PROPERTY_H
#pragma once
#include "Definitions.h"
#include <optional>
#include <string_view>
#include <tuple>
#include <yaml-cpp/emittermanip.h>
namespace cbm::algo::yaml
{
template<typename Class, typename T>
class Property {
private:
T Class::*fMember;
std::string_view fKey;
std::string_view fDescription;
std::optional<YAML::EMITTER_MANIP> fFormat;
std::optional<YAML::EMITTER_MANIP> fFormatEntries;
public:
using ClassType = Class;
using ValueType = T;
Property() = delete;
constexpr Property(T Class::*member, std::string_view key, std::string_view description = "",
std::optional<YAML::EMITTER_MANIP> fmt = {}, std::optional<YAML::EMITTER_MANIP> fmtEntries = {})
: fMember(member)
, fKey(key)
, fDescription(description)
, fFormat(fmt)
, fFormatEntries(fmtEntries)
{
}
Property(const Property&) = delete;
Property& operator=(const Property&) = delete;
Property(Property&&) = default;
Property& operator=(Property&&) = default;
std::string_view Key() const { return fKey; }
std::string_view Description() const { return fDescription; }
std::optional<YAML::EMITTER_MANIP> Format() const { return fFormat; }
std::optional<YAML::EMITTER_MANIP> FormatEntries() const { return fFormatEntries; }
T& Get(Class& object) const { return object.*fMember; }
const T& Get(const Class& object) const { return object.*fMember; }
void Set(Class& object, const T& value) const { object.*fMember = value; }
};
template<typename Class, typename T>
Property(T Class::*member, std::string_view key, std::string_view description) -> Property<Class, T>;
} // namespace cbm::algo::yaml
#define CBM_YAML_PROPERTIES(...) \
public: \
static constexpr auto Properties = std::make_tuple(__VA_ARGS__)
/**
* @brief Optional tag to specify a formatting of the class (YAML::Flow vs YAML::Block)
*/
#define CBM_YAML_FORMAT(tag) \
public: \
static constexpr std::optional<YAML::EMITTER_MANIP> FormatAs = tag
/**
* @brief Optional flag to indicate that the class should be treated like a type
* of it's property. Only has an effect on classes with a single property.
*
* @note This is useful to make some config files more compact.
*/
#define CBM_YAML_MERGE_PROPERTY() \
public: \
static constexpr bool MergeProperty = true
#endif // CBM_YAML_PROPERTY_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_YAML_YAML_H
#define CBM_YAML_YAML_H
#pragma once
#include "Definitions.h"
#include "compat/Filesystem.h"
#include "util/EnumDict.h"
#include "yaml/BaseTypes.h"
#include "yaml/Property.h"
#include <sstream>
#include <string_view>
#include <fmt/format.h>
#include <yaml-cpp/yaml.h>
namespace cbm::algo::yaml
{
template<typename T>
T Read(const YAML::Node& node);
template<typename T, T... Values, typename Func>
constexpr void ForEach(std::integer_sequence<T, Values...>, Func&& func)
{
(func(std::integral_constant<T, Values>{}), ...);
}
template<typename T, typename = void>
struct GetFmtTag {
static constexpr std::optional<YAML::EMITTER_MANIP> value = {};
};
template<typename T>
struct GetFmtTag<T, std::void_t<decltype(T::FormatAs)>> {
static constexpr std::optional<YAML::EMITTER_MANIP> value = T::FormatAs;
};
template<typename T, typename = void>
struct ShouldMergeProperty {
static constexpr bool value = false;
};
template<typename T>
struct ShouldMergeProperty<T, std::void_t<decltype(T::MergeProperty)>> {
static constexpr bool value = T::MergeProperty;
};
template<typename T>
T ReadFromFile(fs::path path)
{
YAML::Node node = YAML::LoadFile(path.string());
return Read<T>(node);
}
template<typename T>
T Read(const YAML::Node& node)
{
// Disable uninitialized warning for the whole function.
// GCC 11.4 sometimes incorrectly warns about uninitialized variables in constexpr if branches.
// I'm fairly certain this is a compiler bug, because it only happens when
// explicitly instantiating the function template. And the error message
// references a variable 't' that doesn't exist in the function!
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
using Type = std::remove_cv_t<std::remove_reference_t<T>>;
static_assert(!IsEnum<T> || detail::EnumHasDict_v<T>, "Enum must have a dictionary to be deserializable");
// TODO: error handling
if constexpr (IsFundamental<Type>) {
return node.as<Type>();
}
else if constexpr (IsEnum<Type>) {
std::optional<T> maybet = FromString<T>(node.as<std::string>());
if (!maybet) {
throw std::runtime_error(fmt::format("Invalid enum value: {}", node.as<std::string>()));
}
return *maybet;
}
else if constexpr (IsVector<Type>) {
Type vector;
for (const auto& element : node) {
vector.push_back(Read<typename Type::value_type>(element));
}
return vector;
}
else if constexpr (IsArray<Type>) {
Type array = {};
auto vector = Read<std::vector<typename Type::value_type>>(node);
if (vector.size() != array.size()) {
throw std::runtime_error(fmt::format("Array size mismatch: expected {}, got {}", array.size(), vector.size()));
}
std::copy(vector.begin(), vector.end(), array.begin());
return array;
}
else if constexpr (IsSet<Type>) {
Type set;
for (const auto& element : node) {
set.insert(Read<typename Type::value_type>(element));
}
return set;
}
else if constexpr (IsMap<Type>) {
using Key_t = typename Type::key_type;
using Val_t = typename Type::mapped_type;
static_assert(IsScalar<Key_t>, "Map key must be a fundamental or enum type");
Type map{};
for (YAML::const_iterator it = node.begin(); it != node.end(); ++it) {
const auto& key = it->first;
const auto& value = it->second;
map[Read<Key_t>(key)] = Read<Val_t>(value);
}
return map;
}
else {
Type object{};
constexpr auto nProperties = std::tuple_size<decltype(Type::Properties)>::value;
if constexpr (nProperties == 1 && ShouldMergeProperty<T>::value) {
auto& property = std::get<0>(Type::Properties);
using ValueType = std::remove_cv_t<std::remove_reference_t<decltype(property.Get(std::declval<Type>()))>>;
ValueType& value = property.Get(object);
value = Read<ValueType>(node);
}
else {
ForEach(std::make_integer_sequence<std::size_t, nProperties>{}, [&](auto index) {
auto& property = std::get<index>(Type::Properties);
using ValueType = std::remove_cv_t<std::remove_reference_t<decltype(property.Get(object))>>;
ValueType& value = property.Get(object);
value = Read<ValueType>(node[std::string{property.Key()}]);
});
}
return object;
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
}
template<typename T>
std::string MakeDocString(int indent = 0)
{
using Type = std::remove_cv_t<std::remove_reference_t<T>>;
std::stringstream docString;
if constexpr (IsFundamental<Type>) {
docString << Typename<Type>();
}
else if constexpr (IsVector<Type> || IsArray<Type>) {
using ChildType = typename Type::value_type;
if constexpr (IsFundamental<ChildType>) {
docString << std::string(indent, ' ') << "list of " << Typename<ChildType>() << std::endl;
}
else {
docString << std::string(indent, ' ') << "list of" << std::endl;
docString << MakeDocString<ChildType>(indent + 2);
}
}
else {
constexpr auto nProperties = std::tuple_size<decltype(Type::Properties)>::value;
ForEach(std::make_integer_sequence<std::size_t, nProperties>{}, [&](auto index) {
using ChildType = std::remove_cv_t<
std::remove_reference_t<decltype(std::get<index>(Type::Properties).Get(std::declval<Type>()))>>;
auto& property = std::get<index>(Type::Properties);
if constexpr (IsFundamental<ChildType>) {
docString << std::string(indent, ' ') << property.Key() << ": " << property.Description() << " ["
<< Typename<ChildType>() << "]" << std::endl;
}
else {
docString << std::string(indent, ' ') << property.Key() << ": " << property.Description() << std::endl;
docString << MakeDocString<ChildType>(indent + 2);
}
});
}
return docString.str();
}
class Dump {
public:
template<typename T>
std::string operator()(const T& object, int floatPrecision = 6)
{
YAML::Emitter ss;
ss << YAML::BeginDoc;
ss << YAML::Precision(floatPrecision);
DoDump(object, ss);
ss << YAML::EndDoc;
return ss.c_str();
}
private:
template<typename T>
void DoDump(const T& object, YAML::Emitter& ss, std::optional<YAML::EMITTER_MANIP> formatEntries = {})
{
static_assert(!IsEnum<T> || detail::EnumHasDict_v<T>, "Enum must have a dictionary");
if constexpr (IsFundamental<T>) {
// Take care that i8 and u8 are printed as integers not as characters
if constexpr (std::is_same_v<T, i8> || std::is_same_v<T, u8>)
ss << i32(object);
else
ss << object;
}
else if constexpr (IsEnum<T>) {
ss << std::string{ToString<T>(object)};
}
else if constexpr (IsVector<T> || IsArray<T> || IsSet<T>) {
ss << YAML::BeginSeq;
// Special case for vector<bool> because it is not a real vector
// Clang does not the compile the generic version of the loop
// in this case.
if constexpr (std::is_same_v<T, std::vector<bool>>) {
for (bool element : object) {
if (formatEntries.has_value()) {
ss << formatEntries.value();
}
ss << element;
}
}
else {
for (const auto& element : object) {
if (formatEntries.has_value()) {
ss << formatEntries.value();
}
DoDump(element, ss);
}
}
ss << YAML::EndSeq;
}
else if constexpr (IsMap<T>) {
ss << YAML::BeginMap;
for (const auto& [key, value] : object) {
if (formatEntries.has_value()) {
ss << formatEntries.value();
}
ss << YAML::Key << key;
ss << YAML::Value;
DoDump(value, ss);
}
ss << YAML::EndMap;
}
else {
constexpr auto nProperties = std::tuple_size<decltype(T::Properties)>::value;
if (auto fmtTag = GetFmtTag<T>::value; fmtTag.has_value()) {
ss << fmtTag.value();
}
if constexpr (nProperties == 1 && ShouldMergeProperty<T>::value) {
auto& property = std::get<0>(T::Properties);
auto& value = property.Get(object);
auto format = property.Format();
if (format.has_value()) {
ss << format.value();
}
DoDump(value, ss, property.FormatEntries());
}
else {
ss << YAML::BeginMap;
ForEach(std::make_integer_sequence<std::size_t, nProperties>{}, [&](auto index) {
auto& property = std::get<index>(T::Properties);
auto& value = property.Get(object);
auto format = property.Format();
ss << YAML::Key << std::string{property.Key()};
if (format.has_value()) {
ss << format.value();
}
ss << YAML::Value;
DoDump(value, ss, property.FormatEntries());
});
ss << YAML::EndMap;
}
}
}
};
} // namespace cbm::algo::yaml
/**
* @brief Declare the external instantiation of the Read and Dump functions for a type.
* @param type The type to declare the external instantiation for.
* @note This macro should be used in a header file to declare the external instantiation of the Read and Dump.
* Must be paired with CBM_YAML_INSTANTIATE in a source file.
**/
#define CBM_YAML_EXTERN_DECL(type) \
extern template type cbm::algo::yaml::Read<type>(const YAML::Node& node); \
extern template std::string cbm::algo::yaml::Dump::operator()<type>(const type& value, int floatPrecision)
/**
* @brief Explicitly instantiate the Read and Dump functions for a type.
* @see CBM_YAML_EXTERN_DECL
*/
#define CBM_YAML_INSTANTIATE(type) \
template type cbm::algo::yaml::Read<type>(const YAML::Node& node); \
template std::string cbm::algo::yaml::Dump::operator()<type>(const type& value, int floatPrecision);
#endif // CBM_YAML_YAML_H
add_subdirectory(core) # libCaCore.so
/* Copyright (C) 2023-2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file TrackingChain.cxx
/// \date 14.09.2023
/// \brief A chain class to execute CA tracking algorithm in online reconstruction (implementation)
/// \author S.Zharko <s.zharko@gsi.de>
#include "TrackingChain.h"
#include "CaDefs.h"
#include "CaHit.h"
#include "CaInitManager.h"
#include "CaParameters.h"
#include "KfSetupBuilder.h"
#include "ParFiles.h"
#include "compat/OpenMP.h"
#include "yaml/Yaml.h"
#include <boost/archive/binary_oarchive.hpp>
#include <fstream>
#include <set>
#include <unordered_map>
#include <fmt/format.h>
#include <xpu/host.h>
using cbm::algo::TrackingChain;
using cbm::algo::ca::EDetectorID;
using cbm::algo::ca::Framework;
using cbm::algo::ca::HitTypes_t;
using cbm::algo::ca::InitManager;
using cbm::algo::ca::Parameters;
using cbm::algo::ca::Qa;
using cbm::algo::ca::Track;
using cbm::algo::ca::constants::clrs::CL; // clear text
using cbm::algo::ca::constants::clrs::GNb; // grin bald text
// ---------------------------------------------------------------------------------------------------------------------
//
TrackingChain::TrackingChain(ECbmRecoMode recoMode, const std::unique_ptr<cbm::algo::qa::Manager>& qaManager,
std::string_view name)
: fQa(Qa(qaManager, name))
, fRecoMode(recoMode)
{
}
// ---------------------------------------------------------------------------------------------------------------------
//
void TrackingChain::Init()
{
if (fpSetup.get() == nullptr) {
throw std::runtime_error("Tracking Chain: TrackingSetup object was not registered");
}
// ------ Read tracking chain parameters from the config
ParFiles parFiles(Opts().RunId());
fConfig = yaml::ReadFromFile<TrackingChainConfig>(Opts().ParamsDir() / parFiles.ca.mainConfig);
// ------ Read parameters from binary
auto geomCfgFile = (Opts().ParamsDir() / fConfig.fsGeomConfig).string();
auto setupCfgFile = (Opts().ParamsDir() / fConfig.fsSetupFilename).string();
auto mainCfgFile = (Opts().ParamsDir() / fConfig.fsMainConfig).string();
auto userCfgFile = fConfig.fsUserConfig;
L_(info) << "Tracking Chain: reading geometry from CA parameters file " << GNb << geomCfgFile << CL << '\n';
L_(info) << "Tracking Chain: reading geometry setup file " << GNb << setupCfgFile << CL << '\n';
L_(info) << "Tracking Chain: reading parameters from CA main config " << GNb << mainCfgFile << CL << '\n';
//* InitManager instantiation
auto manager = InitManager{};
manager.SetDetectorNames(ca::kDetName);
manager.SetConfigMain(mainCfgFile);
if (!userCfgFile.empty()) {
L_(info) << "Tracking Chain: applying user configuration from " << GNb << userCfgFile << CL << '\n';
manager.SetConfigUser(userCfgFile);
}
//* Read parameters object from the geomCfgFile to intialize tracking stations
{
manager.ReadParametersObject(geomCfgFile); // geometry setup
auto paramIn = manager.TakeParameters();
manager.ClearSetupInfo();
//* Read setup
auto geoSetup = kf::SetupBuilder::Load<ca::fvec>(setupCfgFile);
kf::Target<double> target(geoSetup.GetTarget());
//* Initialize tracking parameters
manager.SetFieldFunction([](const double(&)[3], double(&outB)[3]) {
outB[0] = 0.;
outB[1] = 0.;
outB[2] = 0.;
});
manager.SetTargetPosition(target.GetX(), target.GetY(), target.GetZ());
manager.InitTargetField(2.5 /*cm*/);
manager.AddStations(paramIn); // Initialize stations
manager.InitStationLayout();
manager.ReadInputConfigs();
manager.SetGeometrySetup(geoSetup);
manager.DevSetIsParSearchWUsed(false);
if (!manager.FormParametersContainer()) {
throw std::runtime_error("Initialization of CA parameters failed");
}
}
auto parameters = manager.TakeParameters();
L_(info) << "Tracking Chain: parameters object: \n" << parameters.ToString(1) << '\n';
// ------ Used detector subsystem flags
fbDetUsed.fill(false);
fbDetUsed[EDetectorID::kSts] = Opts().Has(fles::Subsystem::STS) && parameters.IsActive(EDetectorID::kSts);
fbDetUsed[EDetectorID::kTof] = Opts().Has(fles::Subsystem::TOF) && parameters.IsActive(EDetectorID::kTof);
fbDetUsed[EDetectorID::kTrd] = Opts().Has(fles::Subsystem::TRD) && parameters.IsActive(EDetectorID::kTrd);
// ------ Initialize CA framework
fCaMonitor.Reset();
if (ECbmRecoMode::Timeslice == fRecoMode) {
fCaFramework.SetNofThreads(Opts().NumOMPThreads() == std::nullopt ? openmp::GetMaxThreads()
: *(Opts().NumOMPThreads()));
}
else {
fCaFramework.SetNofThreads(1);
}
fCaFramework.ReceiveParameters(std::move(parameters));
fCaFramework.Init(ca::TrackingMode::kMcbm);
// ------ Initialize QA modules
if (fQa.IsActive()) {
fQa.RegisterParameters(&fCaFramework.GetParameters());
fQa.Init();
}
L_(info) << "TRACKING QA: " << fQa.IsActive();
}
// ---------------------------------------------------------------------------------------------------------------------
//
TrackingChain::Output_t TrackingChain::Run(Input_t recoResults)
{
xpu::scoped_timer t_("CA"); // TODO: pass timings to monitoring for throughput?
fCaMonitorData.Reset();
fCaMonitorData.StartTimer(ca::ETimer::TrackingChain);
// ----- Init input data ---------------------------------------------------------------------------------------------
fCaMonitorData.StartTimer(ca::ETimer::PrepareInputData);
this->PrepareInput(recoResults);
fCaMonitorData.StopTimer(ca::ETimer::PrepareInputData);
// ----- Run reconstruction ------------------------------------------------------------------------------------------
fCaFramework.SetMonitorData(fCaMonitorData);
fCaFramework.FindTracks();
fCaMonitorData = fCaFramework.GetMonitorData();
// ----- Init output data --------------------------------------------------------------------------------------------
return PrepareOutput();
}
// ---------------------------------------------------------------------------------------------------------------------
//
void TrackingChain::Finalize()
{
L_(info) << fCaMonitor.ToString();
if (fConfig.fbStoreMonitor) {
auto fileName = "./" + fConfig.fsMoniOutName;
std::ofstream ofs(fileName);
boost::archive::binary_oarchive oa(ofs);
oa << fCaMonitor;
}
}
// ---------------------------------------------------------------------------------------------------------------------
//
void TrackingChain::PrepareInput(Input_t recoResults)
{
fNofHitKeys = 0;
int nHitsTot = recoResults.stsHits.NElements() + recoResults.tofHits.NElements() + recoResults.trdHits.NElements();
L_(debug) << "Tracking chain: input has " << nHitsTot << " hits";
fCaDataManager.ResetInputData(nHitsTot);
faHitExternalIndices.clear();
faHitExternalIndices.reserve(nHitsTot);
if (fbDetUsed[EDetectorID::kSts]) {
fCaMonitorData.StartTimer(ca::ETimer::PrepareStsHits);
ReadHits<EDetectorID::kSts>(recoResults.stsHits);
fCaMonitorData.StopTimer(ca::ETimer::PrepareStsHits);
}
if (fbDetUsed[EDetectorID::kTrd]) {
fCaMonitorData.StartTimer(ca::ETimer::PrepareTrdHits);
ReadHits<EDetectorID::kTrd>(recoResults.trdHits);
fCaMonitorData.StopTimer(ca::ETimer::PrepareTrdHits);
}
if (fbDetUsed[EDetectorID::kTof]) {
fCaMonitorData.StartTimer(ca::ETimer::PrepareTofHits);
ReadHits<EDetectorID::kTof>(recoResults.tofHits);
fCaMonitorData.StopTimer(ca::ETimer::PrepareTofHits);
}
faHitExternalIndices.shrink_to_fit();
fCaDataManager.SetNhitKeys(fNofHitKeys);
L_(debug) << "Tracking chain: " << fCaDataManager.GetNofHits() << " hits will be passed to the ca::Framework";
fCaMonitorData.StartTimer(ca::ETimer::InputDataTransmission);
fCaFramework.ReceiveInputData(fCaDataManager.TakeInputData());
fCaMonitorData.StopTimer(ca::ETimer::InputDataTransmission);
}
// ---------------------------------------------------------------------------------------------------------------------
//
TrackingChain::Output_t TrackingChain::PrepareOutput()
{
Output_t output;
output.tracks = std::move(fCaFramework.fRecoTracks);
int nTracks = output.tracks.size();
output.stsHitIndices.reset(nTracks);
output.tofHitIndices.reset(nTracks);
output.trdHitIndices.reset(nTracks);
int trackFirstHit = 0;
for (int iTrk = 0; iTrk < nTracks; ++iTrk) {
output.stsHitIndices[iTrk].clear();
output.tofHitIndices[iTrk].clear();
output.trdHitIndices[iTrk].clear();
int nHits = output.tracks[iTrk].fNofHits;
for (int iHit = 0; iHit < nHits; ++iHit) {
int iHitInternal = fCaFramework.GetInputData().GetHit(fCaFramework.fRecoHits[trackFirstHit + iHit]).Id();
const auto [detID, iPartition, iPartHit] = faHitExternalIndices[iHitInternal];
switch (detID) {
// FIXME: store a global hit index instead of (partition, hit)
case ca::EDetectorID::kSts: output.stsHitIndices[iTrk].push_back(std::make_pair(iPartition, iPartHit)); break;
case ca::EDetectorID::kTof: output.tofHitIndices[iTrk].push_back(std::make_pair(iPartition, iPartHit)); break;
case ca::EDetectorID::kTrd: output.trdHitIndices[iTrk].push_back(std::make_pair(iPartition, iPartHit)); break;
default: break;
}
}
fCaMonitorData.IncrementCounter(ca::ECounter::RecoStsHit, output.stsHitIndices[iTrk].size());
fCaMonitorData.IncrementCounter(ca::ECounter::RecoTofHit, output.tofHitIndices[iTrk].size());
fCaMonitorData.IncrementCounter(ca::ECounter::RecoTrdHit, output.trdHitIndices[iTrk].size());
trackFirstHit += nHits;
}
if (ECbmRecoMode::Timeslice == fRecoMode) {
L_(info) << "TrackingChain: Timeslice contains " << fCaMonitorData.GetCounterValue(ca::ECounter::RecoTrack)
<< " tracks, with " << fCaMonitorData.GetCounterValue(ca::ECounter::RecoStsHit) << " sts hits, "
<< fCaMonitorData.GetCounterValue(ca::ECounter::RecoTofHit) << " tof hits, "
<< fCaMonitorData.GetCounterValue(ca::ECounter::RecoTrdHit) << " trd hits"
<< "; the FindTracks routine ran " << fCaMonitorData.GetTimer(ca::ETimer::FindTracks).GetTotal() << " s";
}
// QA
if (fQa.IsActive()) {
fCaMonitorData.StartTimer(ca::ETimer::Qa);
fQa.RegisterInputData(&fCaFramework.GetInputData());
fQa.RegisterTracks(&output.tracks);
fQa.RegisterRecoHitIndices(&fCaFramework.fRecoHits);
fQa.Exec();
fCaMonitorData.StopTimer(ca::ETimer::Qa);
}
fCaMonitorData.StopTimer(ca::ETimer::TrackingChain);
if constexpr (kDEBUG) { // Monitor data per TS
if (fCaFramework.GetNofThreads() == 1 && fCaFramework.GetNofThreads() == 10) {
int tsIndex = fCaMonitor.GetCounterValue(ca::ECounter::TrackingCall);
auto fileName = fmt::format("./ca_monitor_nth_{}_ts{}.dat", fCaFramework.GetNofThreads(), tsIndex);
std::ofstream ofs(fileName);
boost::archive::binary_oarchive oa(ofs);
ca::TrackingMonitor monitorPerTS;
monitorPerTS.AddMonitorData(fCaMonitorData);
oa << monitorPerTS;
}
}
fCaMonitor.AddMonitorData(fCaMonitorData);
output.monitorData = fCaMonitorData;
return output;
}
// ---------------------------------------------------------------------------------------------------------------------
//
template<EDetectorID DetID>
void TrackingChain::ReadHits(PartitionedSpan<const ca::HitTypes_t::at<DetID>> hits)
{
int nSt = fCaFramework.GetParameters().GetNstationsActive();
using Hit_t = ca::HitTypes_t::at<DetID>;
constexpr bool IsMvd = (DetID == EDetectorID::kMvd);
constexpr bool IsSts = (DetID == EDetectorID::kSts);
constexpr bool IsMuch = (DetID == EDetectorID::kMuch);
constexpr bool IsTrd = (DetID == EDetectorID::kTrd);
constexpr bool IsTof = (DetID == EDetectorID::kTof);
xpu::t_add_bytes(hits.NElements() * sizeof(Hit_t)); // Assumes call from Run, for existence of timer!
int64_t dataStreamDet = static_cast<int64_t>(DetID) << 60; // detector part of the data stream
int64_t dataStream = 0;
for (size_t iPartition = 0; iPartition < hits.NPartitions(); ++iPartition, ++dataStream) {
const auto& [vHits, extHitAddress] = hits.Partition(iPartition);
// ---- Define data stream and station index
//int64_t dataStream = dataStreamDet | extHitAddress;
int iStLocal = fpSetup->GetTrackingStation<ca::ToFlesSubsystem<DetID>()>(extHitAddress);
if (iStLocal < 0) {
continue; // Station is not used for tracking (e.g. TOF SMtype 5)
}
int iStActive = fCaFramework.GetParameters().GetStationIndexActive(iStLocal, DetID);
//size_t iOffset = hits.Offsets()[iPartition];
if (iStActive < 0) {
continue; // legit
}
if (iStActive >= nSt) {
L_(error) << "TrackingChain: found hit with wrong active station index above the upper limit: " << iStActive
<< ", detector: " << ca::kDetName[DetID];
continue;
}
double lastTime = -1e9;
//double prevTime = -1;
ca::HitKeyIndex_t firstHitKey = fNofHitKeys;
for (size_t iPartHit = 0; iPartHit < vHits.size(); ++iPartHit) {
const auto& hit = vHits[iPartHit];
//if constexpr (IsTrd) {
// switch (extHitAddress) {
// case 0x5:
// if (!(fabs(hit.Z() - 116.77) < 10)) {
// L_(info) << "DBG! " << extHitAddress << ' ' << hit.Z();
// }
// break;
// case 0x15:
// if (!(fabs(hit.Z() - 163.8) < 10)) {
// L_(info) << "DBG! " << extHitAddress << ' ' << hit.Z();
// }
// break;
// case 0x25:
// if (!(fabs(hit.Z() - 190.8) < 10)) {
// L_(info) << "DBG! " << extHitAddress << ' ' << hit.Z();
// }
// break;
// }
//}
//int iHitExt = iOffset + iPartHit;
// ---- Fill ca::Hit
fCaMonitorData.StartTimer(ca::ETimer::CaHitCreation);
ca::Hit caHit;
if constexpr (IsSts) {
caHit.SetFrontKey(firstHitKey + hit.fFrontClusterId);
caHit.SetBackKey(firstHitKey + hit.fBackClusterId);
//L_(info) << ", hit=" << iHitExt << ", f=" << hit.fFrontClusterId << ", b=" << hit.fBackClusterId;
}
else {
caHit.SetFrontKey(firstHitKey + iPartHit);
caHit.SetBackKey(caHit.FrontKey());
}
if constexpr (IsTof) {
// Cut the BMon hits (if any)
if (hit.Z() < 0.1) {
// FIXME: Provide BMon addresses explicitly in all the parameter files
continue;
}
}
caHit.SetX(hit.X());
caHit.SetY(hit.Y());
caHit.SetZ(hit.Z());
caHit.SetT(hit.Time());
caHit.SetDx2(hit.Dx() * hit.Dx() + fCaFramework.GetParameters().GetMisalignmentXsq(DetID));
caHit.SetDy2(hit.Dy() * hit.Dy() + fCaFramework.GetParameters().GetMisalignmentYsq(DetID));
if constexpr (IsSts) caHit.SetDxy(hit.fDxy);
caHit.SetDt2(hit.TimeError() * hit.TimeError() + fCaFramework.GetParameters().GetMisalignmentTsq(DetID));
/// FIXME: Define ranges from the hit, when will be available
//out << iStLocal << " " << extHitAddress << " " << hit.Z() << '\n';
caHit.SetRangeX(3.5 * hit.Dx());
caHit.SetRangeY(3.5 * hit.Dy());
caHit.SetRangeT(3.5 * hit.TimeError());
if constexpr (IsTrd) {
if (iStLocal == 0) {
caHit.SetRangeX(1.7);
caHit.SetRangeY(3.5);
caHit.SetRangeT(200.);
}
else if (iStLocal == 1) {
caHit.SetRangeY(sqrt(3.) * hit.Dy());
}
else {
caHit.SetRangeX(sqrt(3.) * hit.Dx());
}
}
caHit.SetStation(iStActive);
caHit.SetId(fCaDataManager.GetNofHits());
if (caHit.Check()) {
if (ECbmRecoMode::Timeslice == fRecoMode) {
if ((caHit.T() < lastTime - 1000.) && (dataStream < 100000)) {
dataStream++;
}
lastTime = caHit.T();
fCaDataManager.PushBackHit(caHit, dataStreamDet | dataStream);
}
else {
fCaDataManager.PushBackHit(caHit); // A single data stream in event-by-event mode
}
faHitExternalIndices.push_back(std::make_tuple(DetID, iPartition, iPartHit));
if (fNofHitKeys <= caHit.FrontKey()) {
fNofHitKeys = caHit.FrontKey() + 1;
}
if (fNofHitKeys <= caHit.BackKey()) {
fNofHitKeys = caHit.BackKey() + 1;
}
}
else {
if constexpr (IsMvd) {
fCaMonitorData.IncrementCounter(ca::ECounter::UndefinedMvdHit);
}
if constexpr (IsSts) {
fCaMonitorData.IncrementCounter(ca::ECounter::UndefinedStsHit);
}
if constexpr (IsMuch) {
fCaMonitorData.IncrementCounter(ca::ECounter::UndefinedMuchHit);
}
if constexpr (IsTrd) {
fCaMonitorData.IncrementCounter(ca::ECounter::UndefinedTrdHit);
}
if constexpr (IsTof) {
fCaMonitorData.IncrementCounter(ca::ECounter::UndefinedTofHit);
}
}
fCaMonitorData.StopTimer(ca::ETimer::CaHitCreation);
//prevTime = caHit.T();
// ---- Update number of hit keys
} // iPartHit
} // iPartition
}
/* Copyright (C) 2023-2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file TrackingChain.h
/// \date 13.09.2023
/// \brief A chain class to execute CA tracking algorithm in online reconstruction (header)
/// \author S.Zharko <s.zharko@gsi.de>
#pragma once
#include "CaDataManager.h"
#include "CaFramework.h"
#include "CaQa.h"
#include "CaTrack.h"
#include "CaTrackingMonitor.h"
#include "CaVector.h"
#include "PartitionedSpan.h"
#include "RecoResults.h"
#include "SubChain.h"
#include "TrackingChainConfig.h"
#include "TrackingDefs.h"
#include "TrackingSetup.h"
#include "sts/Hit.h"
#include "tof/Hit.h"
#include <memory>
#include <vector>
namespace cbm::algo::qa
{
class Manager;
}
namespace cbm::algo
{
/// \class cbm::algo::TrackingChain
/// \brief A chain for tracking algorithm
///
/// The class executes a tracking algorithm in the online data reconstruction chain.
class TrackingChain : public SubChain {
public:
/// \brief Constructor from parameters
/// \param recoMode Reconstruction mode
/// \param pManager a QA-manager
/// \param name A name of the task (histograms directory)
TrackingChain(ECbmRecoMode recoMode, const std::unique_ptr<cbm::algo::qa::Manager>& qaManager = nullptr,
std::string_view name = "");
/// \struct Input_t
/// \brief Input to the TrackingChain
struct Input_t {
PartitionedSpan<sts::Hit> stsHits;
PartitionedSpan<tof::Hit> tofHits;
PartitionedSpan<trd::Hit> trdHits;
};
/// \struct Output_t
/// \brief Output from the TrackingChain
struct Output_t {
/// \brief Reconstructed tracks
ca::Vector<ca::Track> tracks;
/// \brief STS hit indices
/// \note Indexing: [trackID][localHit], value: (partitionID, hitIDinPartition)
ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> stsHitIndices;
/// \brief TOF hit indices
/// \note Indexing: [trackID][localHit], value: (partitionID, hitIDinPartition)
ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> tofHitIndices;
/// \brief TRD hit indices
/// \note Indexing: [trackID][localHit], value: (partitionID, hitIDinPartition)
ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>> trdHitIndices;
/// \brief Monitor data
ca::TrackingMonitorData monitorData;
};
/// \brief Gets internal monitor
const ca::TrackingMonitor& GetCaMonitor() const { return fCaMonitor; }
/// \brief Provides action in the initialization of the run
void Init();
/// \brief Registers tracking setup
void RegisterSetup(std::shared_ptr<TrackingSetup> pSetup) { fpSetup = pSetup; }
/// \brief Provides action for a given time-slice
/// \param recoResults Structure of reconstruction results
/// \return A pair (vector of tracks, tracking monitor)
Output_t Run(Input_t recoResults);
/// \brief Provides action in the end of the run
void Finalize();
private:
// *********************
// ** Utility functions
/// \brief Prepares input data
/// \param recoResults Structure of reconstruction results
void PrepareInput(Input_t recoResults);
/// \brief Prepares output data
Output_t PrepareOutput();
/// \brief Reads from different detector subsystems
/// \tparam DetID Detector ID
/// \param hits Hits vector
template<ca::EDetectorID DetID>
void ReadHits(PartitionedSpan<const ca::HitTypes_t::at<DetID>> hits);
// *************************
// ** Framework variables
ca::TrackingMonitor fCaMonitor{}; ///< CA internal monitor (debug purposes)
ca::TrackingMonitorData fCaMonitorData{}; ///< CA monitor data object
ca::Framework fCaFramework{}; ///< CA framework instance
ca::DataManager fCaDataManager{}; ///< CA data manager
ca::Qa fQa; ///< CA QA builder
std::shared_ptr<TrackingSetup> fpSetup = nullptr; ///< setup interface
ca::DetIdArray_t<bool> fbDetUsed; ///< Flags of detector subsystems used in tracking
// ************************
// ** Auxilary variables
TrackingChainConfig fConfig; ///< Tracking config
ca::HitKeyIndex_t fNofHitKeys = 0; ///< Current number of hit keys (aux)
/// \brief External indices of used hits
/// \note Indexing: [globalHitID], value: (DetID, partitionID, hitID)
ca::Vector<std::tuple<ca::EDetectorID, uint32_t, uint32_t>> faHitExternalIndices{"faHitExternalIndices"};
ECbmRecoMode fRecoMode{ECbmRecoMode::Undefined}; ///< Reconstruction mode
static constexpr bool kDEBUG = false; ///< Debug mode
};
} // namespace cbm::algo
/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file TrackingChainConfig.h
/// \date 18.02.2024
/// \brief A configuration reader for the TrackingChain class
/// \author Sergei Zharko <s.zharko@gsi.de>
#pragma once
#include "yaml/Property.h"
#include <string>
#include <tuple>
namespace cbm::algo
{
/// \struct TrackingChainConfig
/// \brief Configuration reader for the TrackingChain class
struct TrackingChainConfig {
std::string
fsGeomConfig; ///< Tracking geometry file name (TMP: includes all other settings, but the settings are rewritten)
std::string fsSetupFilename; ///< Geometry setup input file
std::string fsMainConfig; ///< Main configuration file (rel path in online parameters directory)
std::string fsUserConfig; ///< User configuration file (full path)
std::string fsMoniOutName; ///< Monitor output file name
bool fbStoreMonitor; ///< Stores monitor snapshot
CBM_YAML_PROPERTIES(
yaml::Property(&TrackingChainConfig::fsGeomConfig, "GeomConfigName", "CA geometry input"),
yaml::Property(&TrackingChainConfig::fsSetupFilename, "SetupFilename", "CA geometry setup"),
yaml::Property(&TrackingChainConfig::fsMainConfig, "MainConfigName", "Main cofniguration"),
yaml::Property(&TrackingChainConfig::fsUserConfig, "UserConfigName", "User cofniguration"),
yaml::Property(&TrackingChainConfig::fsMoniOutName, "MoniOutName", "Monitor output"),
yaml::Property(&TrackingChainConfig::fbStoreMonitor, "StoreMonitor", "If store monitor"));
};
} // namespace cbm::algo
/* Copyright (C) 2023-2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file TrackingDefs.h
/// \date 22.10.2023
/// \brief Definitions for tracking in the online reconstruction
/// \author S.Zharko <s.zharko@gsi.de>
#pragma once
#include "CaEnumArray.h"
#include "CbmDefs.h"
#include "MicrosliceDescriptor.hpp" // For fles::Subsystem
#include <tuple>
namespace cbm::algo
{
namespace mvd
{
class Hit;
}
namespace sts
{
struct Hit;
}
namespace much
{
class Hit;
}
namespace trd
{
class Hit;
}
namespace tof
{
struct Hit;
}
namespace ca
{
template<fles::Subsystem subsys>
constexpr EDetectorID FromFlesSubsystem()
{
if constexpr (subsys == fles::Subsystem::STS) {
return EDetectorID::kSts;
}
else if constexpr (subsys == fles::Subsystem::MVD) {
return EDetectorID::kMvd;
}
else if constexpr (subsys == fles::Subsystem::MUCH) {
return EDetectorID::kMuch;
}
else if constexpr (subsys == fles::Subsystem::TRD) {
return EDetectorID::kTrd;
}
if constexpr (subsys == fles::Subsystem::TOF) {
return EDetectorID::kTof;
}
else {
return EDetectorID::END;
}
}
template<EDetectorID detID>
constexpr fles::Subsystem ToFlesSubsystem()
{
if constexpr (detID == EDetectorID::kMvd) {
return fles::Subsystem::MVD;
}
else if constexpr (detID == EDetectorID::kSts) {
return fles::Subsystem::STS;
}
else if constexpr (detID == EDetectorID::kMuch) {
return fles::Subsystem::MUCH;
}
else if constexpr (detID == EDetectorID::kTrd) {
return fles::Subsystem::TRD;
}
else if constexpr (detID == EDetectorID::kTof) {
return fles::Subsystem::TOF;
}
else if constexpr (detID == EDetectorID::END) {
return fles::Subsystem::FLES; // Default ()
}
}
/// \brief Alias to array, indexed by the EDetectorID enum
/// \note To be used only in CBM-specific code
template<typename T>
using DetIdArray_t = EnumArray<EDetectorID, T>;
/// \struct DetIdTypeArr_t
/// \brief Array of types, indexed by EDetectorID
template<class... Types>
struct DetIdTypeArr_t {
template<EDetectorID DetID>
using at = std::tuple_element_t<static_cast<std::size_t>(DetID), std::tuple<Types...>>;
static constexpr std::size_t size = sizeof...(Types);
};
/// \brief Hit vector types
using MvdHit = ::cbm::algo::mvd::Hit;
using StsHit = ::cbm::algo::sts::Hit;
using MuchHit = ::cbm::algo::much::Hit;
using TrdHit = ::cbm::algo::trd::Hit;
using TofHit = ::cbm::algo::tof::Hit;
using HitTypes_t = DetIdTypeArr_t<MvdHit, StsHit, MuchHit, TrdHit, TofHit>;
/// \brief Detector subsystem names
constexpr DetIdArray_t<const char*> kDetName = {{"MVD", "STS", "MUCH", "TRD", "TOF"}};
} // namespace ca
} // namespace cbm::algo
/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file TrackingSetup.h
/// \date 19.04.2024
/// \brief A detector setup interface used for tracking input data initialization (source)
/// \author Sergei Zharko <s.zharko@gsi.de>
#include "TrackingSetup.h"
#include "Definitions.h"
using cbm::algo::TrackingSetup;
using fles::Subsystem;
// ---------------------------------------------------------------------------------------------------------------------
//
void TrackingSetup::Init()
{
if (fbUseSts) {
fSts.SetContext(this->GetContext());
fSts.Init();
}
if (fbUseTrd) {
fTrd.SetContext(this->GetContext());
fTrd.Init();
}
if (fbUseTof) {
fTof.SetContext(this->GetContext()); // can be nullptr
fTof.Init();
}
}
/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file TrackingSetup.h
/// \date 19.04.2024
/// \brief A detector setup interface used for tracking input data initialization (header)
/// \author Sergei Zharko <s.zharko@gsi.de>
#pragma once
#include "SubChain.h"
#include "sts/TrackingInterface.h"
#include "tof/TrackingInterface.h"
#include "trd/TrackingInterface.h"
#include <type_traits>
// TODO: SZh 19.04.2024: Provide interfaces for other subsystems and redefine access
namespace cbm::algo
{
/// \class TrackingSetup
/// \brief A detector setup interface class for tracking input data initialization
class TrackingSetup : public SubChain {
public:
/// \brief Default constructor
TrackingSetup() = default;
/// \brief Copy constructor
TrackingSetup(const TrackingSetup&) = delete;
/// \brief Move constructor
TrackingSetup(TrackingSetup&&) = delete;
/// \brief Destructor
~TrackingSetup() = default;
/// \brief Initializer function
void Init();
/// \brief Returns tracking station index by the detector element address
/// \param address Unique address of an element
/// \return Local index of tracking station
template<fles::Subsystem DetID>
int GetTrackingStation(uint32_t address) const
{
if constexpr (DetID == fles::Subsystem::STS) {
return fSts.GetTrackingStation(address);
}
else if constexpr (DetID == fles::Subsystem::TRD) {
return fTrd.GetTrackingStation(address);
}
else if constexpr (DetID == fles::Subsystem::TOF) {
return fTof.GetTrackingStation(address);
}
return -1; // Default: no station is assigned, hit will be skept !
}
/// \brief Set detector subsystem usage
/// \param det Detector ID (fles::Subsystem)
/// \param flag (not) use the subsystem
void Use(fles::Subsystem det, bool flag = true)
{
using fles::Subsystem;
switch (det) {
case Subsystem::STS: fbUseSts = flag; break;
case Subsystem::MVD: break;
case Subsystem::MUCH: break;
case Subsystem::TRD: fbUseTrd = flag; break;
case Subsystem::TOF: fbUseTof = flag; break;
default: break;
}
}
private:
sts::TrackingInterface fSts; ///< STS tracking interface
trd::TrackingInterface fTrd; ///< TRD tracking interface
tof::TrackingInterface fTof; ///< TOF tracking interface
bool fbUseSts = false;
bool fbUseTrd = false;
bool fbUseTof = false;
};
} // namespace cbm::algo
set(INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/utils
${CMAKE_CURRENT_SOURCE_DIR}/pars
${CMAKE_CURRENT_SOURCE_DIR}/qa
${CMAKE_CURRENT_SOURCE_DIR}/data
${CMAKE_CURRENT_SOURCE_DIR}/tracking
)
set(SRCS
${CMAKE_CURRENT_SOURCE_DIR}/data/CaDataManager.cxx
${CMAKE_CURRENT_SOURCE_DIR}/data/CaInputData.cxx
${CMAKE_CURRENT_SOURCE_DIR}/data/CaTrack.cxx
${CMAKE_CURRENT_SOURCE_DIR}/data/CaGrid.cxx
${CMAKE_CURRENT_SOURCE_DIR}/data/CaHit.cxx
${CMAKE_CURRENT_SOURCE_DIR}/data/CaTriplet.cxx
${CMAKE_CURRENT_SOURCE_DIR}/data/CaWindowData.cxx
${CMAKE_CURRENT_SOURCE_DIR}/data/CaTimesliceHeader.cxx
${CMAKE_CURRENT_SOURCE_DIR}/pars/CaConfigReader.cxx
${CMAKE_CURRENT_SOURCE_DIR}/pars/CaInitManager.cxx
${CMAKE_CURRENT_SOURCE_DIR}/pars/CaIteration.cxx
${CMAKE_CURRENT_SOURCE_DIR}/pars/CaParameters.cxx
${CMAKE_CURRENT_SOURCE_DIR}/pars/CaSearchWindow.cxx
${CMAKE_CURRENT_SOURCE_DIR}/pars/CaStation.cxx
${CMAKE_CURRENT_SOURCE_DIR}/pars/CaStationInitializer.cxx
${CMAKE_CURRENT_SOURCE_DIR}/utils/CaUtils.cxx
${CMAKE_CURRENT_SOURCE_DIR}/tracking/CaCloneMerger.cxx
${CMAKE_CURRENT_SOURCE_DIR}/tracking/CaFramework.cxx
${CMAKE_CURRENT_SOURCE_DIR}/tracking/CaTrackExtender.cxx
${CMAKE_CURRENT_SOURCE_DIR}/tracking/CaTrackFinder.cxx
${CMAKE_CURRENT_SOURCE_DIR}/tracking/CaTrackFinderWindow.cxx
${CMAKE_CURRENT_SOURCE_DIR}/tracking/CaTrackFitter.cxx
${CMAKE_CURRENT_SOURCE_DIR}/tracking/CaTripletConstructor.cxx
)
SET_SOURCE_FILES_PROPERTIES(${SRCS} PROPERTIES COMPILE_FLAGS "-O3")
If(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
ADD_DEFINITIONS(-Wall -Wextra -Wsign-promo -Wctor-dtor-privacy -Wreorder -Wno-deprecated -Wno-parentheses) # -Weffc++ -Wnon-virtual-dtor -Woverloaded-virtual -Wold-style-cast : wait for other parts of cbmroot\root.
Else()
ADD_DEFINITIONS(-Wall -Wextra -Wsign-promo -Wno-pmf-conversions -Wctor-dtor-privacy -Wreorder -Wno-deprecated -Wstrict-null-sentinel -Wno-non-template-friend -Wno-parentheses -Wmissing-field-initializers) # -Weffc++ -Wnon-virtual-dtor -Woverloaded-virtual -Wold-style-cast : wait for other parts of cbmroot\root.
EndIf()
add_library(CaCore SHARED ${SRCS})
list(APPEND HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/utils/CaSimd.h)
target_include_directories(CaCore
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/data
${CMAKE_CURRENT_SOURCE_DIR}/utils
${CMAKE_CURRENT_SOURCE_DIR}/pars
${CMAKE_CURRENT_SOURCE_DIR}/qa
${CMAKE_CURRENT_SOURCE_DIR}/tracking
)
target_compile_definitions(CaCore PUBLIC NO_ROOT)
target_link_libraries(CaCore
PUBLIC KfCore
Boost::serialization
OnlineDataLog # needed for the logger
external::fles_logging # needed for the logger
external::fles_ipc # needed for the logger
external::yaml-cpp
)
##### Offline version without the NO_ROOT in order to get standard logger! #############################################
if (NOT CBM_ONLINE_STANDALONE)
add_library(CaCoreOffline SHARED ${SRCS})
target_include_directories(CaCoreOffline
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/data
${CMAKE_CURRENT_SOURCE_DIR}/utils
${CMAKE_CURRENT_SOURCE_DIR}/pars
${CMAKE_CURRENT_SOURCE_DIR}/qa
${CMAKE_CURRENT_SOURCE_DIR}/tracking
${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(CaCoreOffline
PUBLIC KfCoreOffline
Boost::serialization
external::yaml-cpp
)
install(TARGETS CaCoreOffline DESTINATION lib)
endif()
########################################################################################################################
install(TARGETS CaCore DESTINATION lib)
install(DIRECTORY utils TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY data TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY tracking TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(DIRECTORY pars TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
install(
FILES
data/CaDataManager.h
data/CaGridEntry.h
data/CaHit.h
data/CaInputData.h
data/CaTrack.h
data/CaWindowData.h
pars/CaConfigReader.h
data/CaGridEntry.h
data/CaGrid.h
data/CaGridArea.h
data/CaTriplet.h
data/CaBranch.h
data/CaWindowData.h
data/CaTimesliceHeader.h
pars/CaDefs.h
pars/CaInitManager.h
pars/CaIteration.h
pars/CaParameters.h
pars/CaSearchWindow.h
pars/CaStation.h
pars/CaStationInitializer.h
utils/CaTrackingMonitor.h
utils/CaEnumArray.h
utils/CaMonitor.h
utils/CaMonitorData.h
utils/CaObjectInitController.h
utils/CaSimd.h
utils/CaTimer.h
utils/CaVector.h
utils/CaDefines.h
utils/CaUtils.h
tracking/CaCloneMerger.h
tracking/CaFramework.h
tracking/CaTrackExtender.h
tracking/CaTrackFinder.h
tracking/CaTrackFinderWindow.h
tracking/CaTrackFitter.h
tracking/CaTripletConstructor.h
DESTINATION
include/
)
/* Copyright (C) 2007-2020 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Ivan Kisel, Sergey Gorbunov [committer], Maksym Zyzak, Valentina Akishina */
/// @file CaBranch.h
/// @author Sergey Gorbunov
#pragma once // include this header only once per compilation unit
#include "CaHit.h"
#include "CaVector.h"
namespace cbm::algo::ca
{
/// The class describes a combinatorial branch of the CA tracker
///
class Branch {
public:
/// default constructor
Branch() { fHits.reserve(25); }
///------------------------------
/// Setters and getters
void SetStation(int iStation) { fStation = iStation; }
void SetChi2(fscal chi2) { fChi2 = chi2; }
void SetId(int Id) { fId = Id; }
void SetAlive(bool isAlive) { fIsAlive = isAlive; }
void AddHit(ca::HitIndex_t hitIndex) { fHits.push_back(hitIndex); }
void ResetHits() { fHits.clear(); }
int NofHits() const { return fHits.size(); }
int Station() const { return fStation; }
fscal Chi2() const { return fChi2; }
int Id() const { return fId; }
bool IsAlive() const { return fIsAlive; }
const Vector<ca::HitIndex_t>& Hits() const { return fHits; }
Vector<ca::HitIndex_t>& RefHits() { return fHits; }
///------------------------------
/// Methods
bool IsBetterThan(const Branch& b) const
{
if (NofHits() != b.NofHits()) return (NofHits() > b.NofHits());
if (Station() != b.Station()) return (Station() < b.Station());
return (Chi2() <= b.Chi2());
}
private:
///------------------------------
/// Data members
int fStation{0};
fscal fChi2{0.};
int fId{0};
bool fIsAlive{0};
Vector<ca::HitIndex_t> fHits{"Branch::fHits"};
};
} // namespace cbm::algo::ca