Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Detectors/Upgrades/ALICE3/TRKFT3/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
add_subdirectory(simulation)
add_subdirectory(reconstruction)
add_subdirectory(workflow)
add_subdirectory(macros)
17 changes: 17 additions & 0 deletions Detectors/Upgrades/ALICE3/TRKFT3/common/macros/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2019-2020 CERN and copyright holders of ALICE O2.
# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
# All rights not expressly granted are reserved.
#
# This software is distributed under the terms of the GNU General Public
# License v3 (GPL Version 3), copied verbatim in the file "COPYING".
#
# In applying this license CERN does not waive the privileges and immunities
# granted to it by virtue of its status as an Intergovernmental Organization
# or submit itself to any jurisdiction.


o2_add_test_root_macro(CheckTopologyDictionary.C
PUBLIC_LINK_LIBRARIES O2::TRKReconstruction
O2::DetectorsBase
O2::SimulationDataFormat
LABELS alice3 COMPILE_ONLY)

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ endif()
o2_add_library(TRKReconstruction
TARGETVARNAME targetName
SOURCES src/Clusterer.cxx
src/TopologyDictionary.cxx
src/BuildTopologyDictionary.cxx
$<$<BOOL:${Acts_FOUND}>:src/ClustererACTS.cxx>
PUBLIC_LINK_LIBRARIES
Microsoft.GSL::GSL
Expand All @@ -30,3 +32,8 @@ o2_add_library(TRKReconstruction
if(Acts_FOUND)
target_compile_definitions(${targetName} PUBLIC O2_WITH_ACTS)
endif()

o2_target_root_dictionary(TRKReconstruction
HEADERS include/TRKReconstruction/TopologyDictionary.h
include/TRKReconstruction/BuildTopologyDictionary.h
LINKDEF src/TRKReconstructionLinkDef.h)
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright 2019-2026 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

/// \file BuildTopologyDictionary.h
/// \brief Builds the TRK and FT3 topology dictionaries from MC clusters and their particles' crossings
///
/// Each cluster is accounted with its particle's crossing of the chip: the
/// ends of its path through the silicon. Per layer, build first scans the
/// depth: the local y, on a grid of depthStep, at which the residuals'
/// widths across and along, added in quadrature, are smallest. It then cuts
/// every crossing at that depth: a pattern with at least minCount residuals
/// gets its own entry; a group takes the widths of its rare patterns, else of
/// the rare patterns with the same span class on the axis, else of the layer.

#ifndef ALICEO2_TRKFT3_BUILDTOPOLOGYDICTIONARY_H
#define ALICEO2_TRKFT3_BUILDTOPOLOGYDICTIONARY_H

#include "TRKReconstruction/TopologyDictionary.h"
#include <cstdint>
#include <string>
#include <unordered_map>
#include <vector>

namespace o2::trkft3
{

template <int DetID>
class BuildTopologyDictionary
{
public:
using Dictionary = TopologyDictionary<DetID>;
using ClusterType = typename Dictionary::ClusterType;

struct Settings {
uint32_t minCount = 137; ///< residuals for an entry of its own: the width to 10 %
float depthStep = 0.5e-4f; ///< [cm]
int nThreads = 1; ///< for the depth scan
};

BuildTopologyDictionary(int nLayers, const Settings& settings);

/// A cluster and its particle's crossing of the chip, in O2's local frame [cm].
void accountCluster(const ClusterType& cluster, const unsigned char* pattern, const math_utils::Point3D<float>& start, const math_utils::Point3D<float>& end);

/// Builds every layer; throws std::runtime_error for a layer with too few residuals.
void build();

void setApplyOffsets(bool apply) noexcept { mDictionary.setApplyOffsets(apply); }
[[nodiscard]] const Dictionary& getDictionary() const noexcept { return mDictionary; }
/// Writes the dictionary as "ccdb_object".
void saveDictionaryRoot(const std::string& fileName) const;

private:
/// A cluster's crossing relative to its centre of gravity in the layer's flat frame [cm].
struct Crossing {
uint32_t pattern = 0; ///< index among the layer's patterns
float x0 = 0.f; ///< start - centre of gravity, across
float y0 = 0.f; ///< start, depth
float z0 = 0.f; ///< start - centre of gravity, along
float dx = 0.f; ///< end - start
float dy = 0.f;
float dz = 0.f;
};
struct LayerInput {
std::unordered_map<std::string, uint32_t> patternIndex; ///< the pattern's bytes -> index
std::vector<std::string> patterns;
std::vector<Crossing> crossings;
};

[[nodiscard]] float measureDepth(int layer, const LayerInput& input) const;
void makeEntries(int layer, const LayerInput& input, LayerDictionary& data) const;

Settings mSettings; //!
std::vector<LayerInput> mInput; //!
Dictionary mDictionary; //!
};

using TRKBuildTopologyDictionary = BuildTopologyDictionary<o2::detectors::DetID::TRK>;
using FT3BuildTopologyDictionary = BuildTopologyDictionary<o2::detectors::DetID::FT3>;

} // namespace o2::trkft3

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright 2019-2026 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

/// \file TopologyDictionary.h
/// \brief Positions and errors of TRK and FT3 clusters per layer and pixel pattern
///
/// As the ITS's topology dictionary, measured from MC, but per layer: the
/// layer's depth (the local y positions are taken at) and, per common pattern
/// and per group of rare ones, the width (normalised median absolute
/// deviation) and median of the residuals hit - centre of gravity across
/// (local x) and along (local z). Every pattern finds an entry: its own, else
/// its group's. On the VD the dictionary works in the flat frame of
/// SegmentationChip::curvedToFlat; getClusterCoordinates returns O2's curved
/// local coordinates.

#ifndef ALICEO2_TRKFT3_TOPOLOGYDICTIONARY_H
#define ALICEO2_TRKFT3_TOPOLOGYDICTIONARY_H

#include "DataFormatsTRKFT3/Cluster.h"
#include "DetectorsCommonDataFormats/DetID.h"
#include "MathUtils/Cartesian.h"
#include <Rtypes.h>
#include <algorithm>
#include <string>
#include <unordered_map>
#include <vector>

namespace o2::trkft3
{

template <int DetID>
class BuildTopologyDictionary;

/// A common pattern, or the group of the rare patterns with the same span
/// classes (spans 1 to 5, 6 or more) on both axes.
struct DictionaryEntry {
std::vector<unsigned char> pattern; ///< row span, column span, pixel bits as the clusteriser streams them; empty for a group
float xCOG = 0.f; ///< centre of gravity from the reference pixel across [pitches]
float zCOG = 0.f; ///< along [pitches]
float xWidth = 0.f; ///< the residuals' width across [cm]
float zWidth = 0.f; ///< along [cm]
float xOffset = 0.f; ///< the residuals' median across [cm]
float zOffset = 0.f; ///< along [cm]
bool isGroup = false;

ClassDefNV(DictionaryEntry, 1);
};

struct LayerDictionary {
float depth = 0.f; ///< the local y positions are taken at [cm]
std::vector<DictionaryEntry> entries; ///< the common patterns, most frequent first, then the groups
std::unordered_multimap<unsigned long, int> hashMap; ///< itsmft::ClusterTopology hash -> common pattern's entry

ClassDefNV(LayerDictionary, 1);
};

template <int DetID>
class TopologyDictionary
{
static_assert(DetID == o2::detectors::DetID::TRK || DetID == o2::detectors::DetID::FT3, "only TRK and FT3 dictionaries are supported");

public:
using ClusterType = Cluster<DetID>;

static constexpr int NSpanClasses = 6; ///< spans 1 to 5, 6 or more
static constexpr int NGroups = NSpanClasses * NSpanClasses; ///< one group per pair of span classes, row class major

static constexpr int spanClass(int span) noexcept { return std::min(span, NSpanClasses) - 1; }
static constexpr int groupOf(int rowSpan, int colSpan) noexcept { return spanClass(rowSpan) * NSpanClasses + spanClass(colSpan); }

/// A cluster's layer: TRK's VD layers, then ML/OT (GeometryTGeo::getLayerTRK); FT3's discs. -1 for none (a VD disc).
static int layerOf(const ClusterType& cluster) noexcept;
/// A point from O2's local frame to the layer's flat frame (the VD's unrolled; elsewhere the same).
static math_utils::Point3D<float> localToFlat(const ClusterType& cluster, const math_utils::Point3D<float>& local) noexcept;
/// The cluster's centre of gravity in the flat frame at y = 0. \a pattern: row span, column span, pixel bits.
static math_utils::Point3D<float> centreOfGravity(const ClusterType& cluster, const unsigned char* pattern) noexcept;

[[nodiscard]] int getNumberOfLayers() const noexcept { return static_cast<int>(mLayers.size()); }
[[nodiscard]] const LayerDictionary& getLayer(int layer) const { return mLayers.at(layer); }
[[nodiscard]] const DictionaryEntry& getEntry(int layer, int id) const { return mLayers.at(layer).entries.at(id); }

/// The pattern's entry on the layer: its own if it is common, else its group's.
[[nodiscard]] int findID(int layer, const unsigned char* pattern) const;

/// The position in the flat frame: the entry's centre of gravity, plus its offsets if applied, at the layer's depth.
[[nodiscard]] math_utils::Point3D<float> getFlatCoordinates(const ClusterType& cluster, const unsigned char* pattern, int id) const;
/// The same in O2's local frame: curved on the VD.
[[nodiscard]] math_utils::Point3D<float> getClusterCoordinates(const ClusterType& cluster, const unsigned char* pattern, int id) const;
[[nodiscard]] math_utils::Point3D<float> getClusterCoordinates(const ClusterType& cluster, const unsigned char* pattern) const
{
return getClusterCoordinates(cluster, pattern, findID(layerOf(cluster), pattern));
}

[[nodiscard]] bool getApplyOffsets() const noexcept { return mApplyOffsets; }
void setApplyOffsets(bool apply) noexcept { mApplyOffsets = apply; }

void print() const;

static TopologyDictionary* loadFrom(const std::string& fileName, const std::string& objName = "ccdb_object");

private:
friend class BuildTopologyDictionary<DetID>;

std::vector<LayerDictionary> mLayers;
bool mApplyOffsets = false;

ClassDefNV(TopologyDictionary, 1);
};

using TRKTopologyDictionary = TopologyDictionary<o2::detectors::DetID::TRK>;
using FT3TopologyDictionary = TopologyDictionary<o2::detectors::DetID::FT3>;

} // namespace o2::trkft3

#endif
Loading
Loading