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 2324 additions and 0 deletions
/* Copyright (C) 2022-2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergey Gorbunov, Sergei Zharko [committer] */
/// \file CaDataManager.h
/// \brief Input-output data manager for L1 tracking algorithm
/// \since 08.08.2022
/// \author S.Zharko <s.zharko@gsi.de>
#include "CaDataManager.h"
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <fstream>
using cbm::algo::ca::DataManager;
using cbm::algo::ca::InputData;
// ---------------------------------------------------------------------------------------------------------------------
//
InputData&& DataManager::TakeInputData()
{
// Init the input data
InitData();
// Check the input data
// TODO: Provide assertion
// if (CheckInputData<constants::control::InputDataQaLevel>()) {
// pAlgo->ReceiveInputData(std::move(fInputData));
//
// }
return std::move(fInputData);
}
// ---------------------------------------------------------------------------------------------------------------------
//
void DataManager::ReadInputData(const std::string& fileName)
{
// Reset input data object
ResetInputData();
LOG(info) << "L1: Input data will be read from file \"" << fileName << "\"";
// Open input binary file
std::ifstream ifs(fileName, std::ios::binary);
if (!ifs) {
LOG(fatal) << "L1: input data reader: data file \"" << fileName << "\" was not found";
}
// Get InputData object
try {
boost::archive::binary_iarchive ia(ifs);
ia >> fInputData;
}
catch (const std::exception&) {
LOG(fatal) << "L1: input data reader: data file \"" << fileName << "\" has incorrect data format or was corrupted";
}
}
// ---------------------------------------------------------------------------------------------------------------------
//
void DataManager::ResetInputData(HitIndex_t nHits) noexcept
{
InputData tmp;
fInputData.Swap(tmp);
fLastStreamId = -1;
fInputData.fvStreamStartIndices.reserve(2000); // TODO: What are these numbers? Please, put them into constants.h
fInputData.fvStreamStopIndices.reserve(2000);
fInputData.fvHits.reserve(nHits);
}
// ---------------------------------------------------------------------------------------------------------------------
//
void DataManager::InitData()
{
// set the end pointers to data streams
// TODO: SZh 14.08.2023: Move the max allowed number of streams to the constants.h
int nStreams = fInputData.fvStreamStartIndices.size();
if (!nStreams) { // No data streams provided
fInputData.fvStreamStartIndices.push_back(0);
fInputData.fvStreamStopIndices.push_back(fInputData.fvHits.size());
}
else {
if (nStreams > 3000) {
LOG(warning) << "ca::DataManager: unexpected order of input data: too many data streams!!! ";
fInputData.fvStreamStartIndices.shrink(3000);
}
fInputData.fvStreamStopIndices.reset(nStreams);
for (int i = 0; i < nStreams - 1; i++) {
fInputData.fvStreamStopIndices[i] = fInputData.fvStreamStartIndices[i + 1];
}
fInputData.fvStreamStopIndices[nStreams - 1] = fInputData.fvHits.size();
}
}
// ---------------------------------------------------------------------------------------------------------------------
//
void DataManager::WriteInputData(const std::string& fileName) const
{
// Check current data object for consistency
if constexpr (constants::control::InputDataQaLevel > 0) {
if (!CheckInputData<constants::control::InputDataQaLevel>()) {
LOG(error) << "ca::DataManager: input data writer: attempt to write invalid input data object to file \""
<< fileName << "\"";
return;
}
}
// Open output binary file
std::ofstream ofs(fileName, std::ios::binary);
if (!ofs) {
LOG(error) << "ca::DataManager: input data writer: failed opening file \"" << fileName
<< " for writing input data\"";
return;
}
// Serialize InputData object and write
boost::archive::binary_oarchive oa(ofs);
oa << fInputData;
}
/* Copyright (C) 2022-2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergey Gorbunov, Sergei Zharko [committer] */
/// \file CaDataManager.h
/// \brief Input-output data manager for L1 tracking algorithm
/// \since 05.08.2022
/// \author S.Zharko <s.zharko@gsi.de>
#pragma once // include this header only once per compilation unit
#include "CaDefs.h"
#include "CaInputData.h"
namespace cbm::algo::ca
{
/// \class cbm::algo::ca::DataManager
/// \brief A manager for the input-output data of the CA tracking algorithm
///
class alignas(constants::misc::Alignment) DataManager {
public:
/// \brief Default constructor
DataManager() = default;
/// \brief Destructor
~DataManager() = default;
/// \brief Copy constructor
DataManager(const DataManager& other) = delete;
/// \brief Move constructor
DataManager(DataManager&& other) = delete;
/// \brief Copy assignment operator
DataManager& operator=(const DataManager& other) = delete;
/// \brief Move assignment operator
DataManager& operator=(DataManager&& other) = delete;
/// \brief Gets number of hits stored
/// \return Number of hits
int GetNofHits() { return fInputData.fvHits.size(); }
/// \brief Reads input data object from boost-serialized binary file
/// \param fileName Name of input file
void ReadInputData(const std::string& fileName);
/// \brief Reserve number of hits
/// \param nHits Number of hits to be stored
/// \note If one does not call this method, the underlying vector of hits will be filled with the time penalty
void ReserveNhits(HitIndex_t nHits) { fInputData.fvHits.reserve(nHits); }
/// \brief Resets the input data block
/// \param nHits Number of hits to reserve
void ResetInputData(HitIndex_t nHits = 0) noexcept;
/// \brief Pushes back a hit (with a data stream info)
/// \param hit An ca::Hit object
/// \param streamId Index of a data stream
void PushBackHit(const Hit& hit, int64_t streamId)
{
if (fInputData.fvStreamStartIndices.size() == 0 || fLastStreamId != streamId) { // new data stream
fLastStreamId = streamId;
fInputData.fvStreamStartIndices.push_back(fInputData.fvHits.size());
// for a case.. it is fixed later in InitData()
fInputData.fvStreamStopIndices.push_back(fInputData.fvHits.size());
}
fInputData.fvHits.push_back(hit);
}
/// \brief Pushes back a hit
/// \param hit An ca::Hit object
void PushBackHit(const Hit& hit) { fInputData.fvHits.push_back(hit); }
/// \brief Sets the number of hit keys
/// \param nKeys Number of hit keys
void SetNhitKeys(int nKeys) { fInputData.fNhitKeys = nKeys; }
/// \brief Takes (moves) the instance of the input data object
InputData&& TakeInputData();
/// \brief Writes input data object to boost-serialized binary file
/// \param fileName Name of input file
void WriteInputData(const std::string& fileName) const;
private:
/// \brief Initializes data object
///
/// Sorts hits by stations (complexity O(n)) and defines bordering hit index for station
void InitData();
/// Provides quick QA for input data
/// \tparam Level The level of the checks. The values of the parameter:
/// - 0: no checks will be done
/// - 1: only number of hits and strips as well as validity of hits first and last indexes will be checked
/// - 2: hits sorting is checked
/// - 3: every hit is checked for consistency
/// \note The larger Level corresponds to more precise checks, but is followed by larger time penalty
template<int Level>
bool CheckInputData() const;
// ***************************
// ** Member variables list **
// ***************************
InputData fInputData{}; ///< Object of input data
int64_t fLastStreamId{-1}; ///< data stream Id of the last hit added
};
// *************************************
// ** Inline functions implementation **
// *************************************
// -------------------------------------------------------------------------------------------------------------------
//
// TODO: Complete this function
template<int Level>
inline bool DataManager::CheckInputData() const
{
if constexpr (Level == 0) {
return true;
} // Level = 0 -> do nothing
else if constexpr (Level > 0) { // Level = 1 and higher
// ----- Check if the hits container is not empty ----------------------------------------------------------------
if (fInputData.fvHits.size() == 0) {
LOG(warn) << "DataManager [check input]: Sample contains empty hits, tracking will not be executed";
return false;
}
// ----- Checks if the number of hit keys is valid ---------------------------------------------------------------
if (fInputData.fNhitKeys < 1) {
LOG(error) << "DataManager [check input]: Incorrect number of keys passed (" << fInputData.fNhitKeys
<< "), tracking will not be executed";
return false;
}
// ----- Checks the indexes of first and last hits in stations
// TODO: Add one of the two following checks for fvStartHitIn
if constexpr (Level > 1) { // Level = 2 and higher
// ----- Checks for hits sorting -------------------------------------------------------------------------------
// TODO...
if constexpr (Level > 2) { // Level = 3 and higher
// ----- Checks for consistency of the particular hit --------------------------------------------------------
// TODO...
}
}
return true;
}
return true;
}
} // namespace cbm::algo::ca
/* Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Maksym Zyzak [committer], Valentina Akishina */
/// \file L1Grid.cxx
/// \brief Class for storing 2d objects in a grid
#include "CaGrid.h"
#include "CaHit.h"
#include <algorithm>
#include <cstring>
namespace cbm::algo::ca
{
void Grid::BuildBins(fscal xMin, fscal xMax, fscal yMin, fscal yMax, fscal binWidthX, fscal binWidthY)
{
fMinX = std::min(xMin, xMax);
fMinY = std::min(yMin, yMax);
xMax = std::max(xMin, xMax);
yMax = std::max(yMin, yMax);
fBinWidthX = binWidthX;
fBinWidthY = binWidthY;
// some sanity checks
if (fBinWidthX < 0.001) {
fBinWidthX = 0.001;
}
if (fBinWidthY < 0.001) {
fBinWidthY = 0.001;
}
fBinWidthXinv = 1. / fBinWidthX;
fBinWidthYinv = 1. / fBinWidthY;
fNx = static_cast<int>(std::ceil((xMax - fMinX) / fBinWidthX));
fNy = static_cast<int>(std::ceil((yMax - fMinY) / fBinWidthY));
// some sanity checks
if (fNx < 1) fNx = 1;
if (fNy < 1) fNy = 1;
fN = fNx * fNy;
fEntries.clear();
fFirstBinEntryIndex.reset(fN + 1, 0);
fNofBinEntries.reset(fN + 1, 0);
}
void Grid::StoreHits(const Vector<ca::Hit>& hits, ca::HitIndex_t hitStartIndex, ca::HitIndex_t nHits,
const Vector<unsigned char>& hitKeyFlags)
{
fFirstBinEntryIndex.reset(fN + 1, 0);
fNofBinEntries.reset(fN + 1, 0);
int nEntries = 0;
for (ca::HitIndex_t ih = 0; ih < nHits; ih++) {
const ca::Hit& hit = hits[hitStartIndex + ih];
if (!(hitKeyFlags[hit.FrontKey()] || hitKeyFlags[hit.BackKey()])) {
fNofBinEntries[GetBin(hit.X(), hit.Y())]++;
nEntries++;
}
}
fEntries.reset(nEntries);
for (int bin = 0; bin < fN; bin++) {
fFirstBinEntryIndex[bin + 1] = fFirstBinEntryIndex[bin] + fNofBinEntries[bin];
fNofBinEntries[bin] = 0;
}
fNofBinEntries[fN] = 0;
fMaxRangeX = 0.;
fMaxRangeY = 0.;
fMaxRangeT = 0.;
for (ca::HitIndex_t ih = 0; ih < nHits; ih++) {
const ca::Hit& hit = hits[hitStartIndex + ih];
if (!(hitKeyFlags[hit.FrontKey()] || hitKeyFlags[hit.BackKey()])) {
int bin = GetBin(hit.X(), hit.Y());
fEntries[fFirstBinEntryIndex[bin] + fNofBinEntries[bin]].Set(hit, hitStartIndex + ih);
fNofBinEntries[bin]++;
fMaxRangeX = std::max(fMaxRangeX, hit.RangeX());
fMaxRangeY = std::max(fMaxRangeY, hit.RangeY());
fMaxRangeT = std::max(fMaxRangeT, hit.RangeT());
}
}
}
void Grid::RemoveUsedHits(const Vector<ca::Hit>& hits, const Vector<unsigned char>& hitKeyFlags)
{
int nEntries = 0;
fMaxRangeX = 0.;
fMaxRangeY = 0.;
fMaxRangeT = 0.;
for (int bin = 0; bin < fN; bin++) {
ca::HitIndex_t firstEntryOld = fFirstBinEntryIndex[bin];
fFirstBinEntryIndex[bin] = nEntries;
fNofBinEntries[bin] = 0;
for (ca::HitIndex_t i = firstEntryOld; i < fFirstBinEntryIndex[bin + 1]; i++) {
auto entry = fEntries[i];
const ca::Hit& hit = hits[entry.GetObjectId()];
if (!(hitKeyFlags[hit.FrontKey()] || hitKeyFlags[hit.BackKey()])) {
fEntries[nEntries] = entry;
nEntries++;
fNofBinEntries[bin]++;
fMaxRangeX = std::max(fMaxRangeX, entry.RangeX());
fMaxRangeY = std::max(fMaxRangeY, entry.RangeY());
fMaxRangeT = std::max(fMaxRangeT, entry.RangeT());
}
}
}
fFirstBinEntryIndex[fN] = nEntries;
fNofBinEntries[fN] = 0;
fEntries.shrink(nEntries);
}
} // namespace cbm::algo::ca
/* Copyright (C) 2010-2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Igor Kulakov [committer], Sergey Gorbunov */
/// \file CaGrid.h
/// \brief A class to store hit information in a backet-sorted way on 2D grid
///
/// This code is based on the code of the ALICE HLT Project
///
#pragma once // include this header only once per compilation unit
#include "CaGridEntry.h"
#include "CaHit.h"
#include "CaSimd.h"
#include "CaVector.h"
namespace cbm::algo::ca
{
/// \class Grid
/// \brief Class for storing 2d objects in a grid
/// It creates 2-dimensional backet-sorted grid of pointers to 2-dimensional objects.
///
/// The class provides an access to the objects in selected 2D bin without touching the rest of the data.
/// To loop over the objects in arbitrary XY-area one can use the ca::GridArea class.
///
/// The class is used by CaTracker to speed-up the hit search operations
/// The grid axis are named X and Y
///
class Grid {
public:
/// \brief Default constructor
Grid() = default;
/// \brief Destructor
~Grid() = default;
/// \brief Build the grid
/// \param xMin - minimal X value
/// \param xMax - maximal X value
/// \param yMin - minimal Y value
/// \param yMax - maximal Y value
/// \param binWidthX - bin width in X
/// \param binWidthY - bin width in Y
void BuildBins(fscal xMin, fscal xMax, fscal yMin, fscal yMax, fscal binWidthX, fscal binWidthY);
/// \brief Store objects in the grid
// TODO: write the method with a template input
/// void StoreData(...);
/// \brief Store ca::Hits in the grid
/// \param hits - vector of hits to store
/// \param hitStartIndex - index of the first hit to store
/// \param nHits - number of hits to store starting from the hitStartIndex
/// \param hitKeyFlags - vector of flags to recognise used hits and skip them
void StoreHits(const ca::Vector<ca::Hit>& hits, ca::HitIndex_t hitStartIndex, ca::HitIndex_t nHits,
const ca::Vector<unsigned char>& hitKeyFlags);
/// \brief Remove grid entries that correspond to the used hits
void RemoveUsedHits(const ca::Vector<ca::Hit>& hits, const ca::Vector<unsigned char>& hitKeyFlags);
/// \brief Get bin index for (X,Y) point with boundary check
/// \param X - point x coordinate
/// \param Y - point y coordinate
/// \return bin index in the range [0, fN-1]
int GetBin(fscal X, fscal Y) const;
/// \brief Get bin X index with boundary check
/// \param X - x coordinate
/// \return binX index
int GetBinX(fscal X) const;
/// \brief Get bin Y index with boundary check
/// \param Y - y coordinate
/// \return binY index
int GetBinY(fscal Y) const;
/// \brief Get bin bounds along X
/// \param iBin - bin index
/// \return pair of (Xmin, Xmax) bounds
std::tuple<fscal, fscal> GetBinBoundsX(int iBin) const;
/// \brief Get bin bounds along Y
/// \param iBin - bin index
/// \return pair of (Ymin, Ymax) bounds
std::tuple<fscal, fscal> GetBinBoundsY(int iBin) const;
/// Get number of bins
int GetNofBins() const { return fN; }
/// Get number of bins along X
int GetNofBinsX() const { return fNx; }
/// Get number of bins along Y
int GetNofBinsY() const { return fNy; }
/// Get index of the first bin entry in fHitsInBin array
ca::HitIndex_t GetFirstBinEntryIndex(int bin) const { return fFirstBinEntryIndex[(bin < fN) ? bin : fN]; }
/// Get number of entries in the bin
//ca::HitIndex_t GetNofBinEntries(int bin) const { return fNofBinEntries[bin < fN ? bin : fN]; }
/// Get entries
const ca::Vector<ca::GridEntry>& GetEntries() const { return fEntries; }
/// Get minimal X value
fscal GetMinX() const { return fMinX; }
/// Get minimal Y value
fscal GetMinY() const { return fMinY; }
/// Get bin width in X
fscal GetBinWidthX() const { return fBinWidthX; }
/// Get bin width in Y
fscal GetBinWidthY() const { return fBinWidthY; }
/// Get maximal entry range in X
fscal GetMaxRangeX() const { return fMaxRangeX; }
/// Get maximal entry range in Y
fscal GetMaxRangeY() const { return fMaxRangeY; }
/// Get maximal entry range in T
fscal GetMaxRangeT() const { return fMaxRangeT; }
private:
/// --- Data members ---
int fN{0}; ///< total N bins
int fNx{0}; ///< N bins in X
int fNy{0}; ///< N bins in Y
fscal fMinX{0.}; ///< minimal X value
fscal fMinY{0.}; ///< minimal Y value
fscal fBinWidthX{0.}; ///< bin width in X
fscal fBinWidthY{0.}; ///< bin width in Y
fscal fBinWidthXinv{0.}; ///< inverse bin width in X
fscal fBinWidthYinv{0.}; ///< inverse bin width in Y
fscal fMaxRangeX{0.}; ///< maximal entry range in X
fscal fMaxRangeY{0.}; ///< maximal entry range in Y
fscal fMaxRangeT{0.}; ///< maximal entry range in T
ca::Vector<ca::HitIndex_t> fFirstBinEntryIndex{"Grid::fFirstBinEntryIndex", 1,
0}; ///< index of the first entry in the bin
ca::Vector<ca::HitIndex_t> fNofBinEntries{"Grid::fNofBinEntries", 1, 0}; ///< number of hits in the bin
ca::Vector<ca::GridEntry> fEntries{
"Ca::Grid::fEntries"}; ///< grid entries with references to the hit index in fWindowHits
};
/// --- Inline methods ---
inline int Grid::GetBin(fscal X, fscal Y) const
{
//
return GetBinY(Y) * fNx + GetBinX(X);
}
inline int Grid::GetBinX(fscal X) const
{
int binX = static_cast<int>((X - fMinX) * fBinWidthXinv);
return std::max(0, std::min(fNx - 1, binX));
}
inline int Grid::GetBinY(fscal Y) const
{
int binY = static_cast<int>((Y - fMinY) * fBinWidthYinv);
return std::max(0, std::min(fNy - 1, binY));
}
inline std::tuple<fscal, fscal> Grid::GetBinBoundsX(int iBin) const
{
fscal Xmin = fMinX + (iBin % fNx) * fBinWidthX;
return std::make_tuple(Xmin, Xmin + fBinWidthX);
}
inline std::tuple<fscal, fscal> Grid::GetBinBoundsY(int iBin) const
{
fscal Ymin = fMinY + (iBin / fNx) * fBinWidthY;
return std::make_tuple(Ymin, Ymin + fBinWidthY);
}
} // namespace cbm::algo::ca
/* Copyright (C) 2012-2020 Frankfurt Institute for Advanced Studies, Goethe-Universitaet Frankfurt, Frankfurt
SPDX-License-Identifier: GPL-3.0-only
Authors: Maksym Zyzak, Igor Kulakov [committer] */
/// \file CaGrid.h
#pragma once // include this header only once per compilation unit
#include "CaGrid.h"
#include "CaHit.h"
#include "CaSimd.h"
namespace cbm::algo::ca
{
/// \brief Class for accessing objects in the 2D area that are stored in ca::Grid
///
class GridArea {
public:
/// \brief Constructor
/// \param grid - the grid to work with
/// \param x - X coordinate of the center of the area
/// \param y - Y coordinate of the center of the area
/// \param dx - half-width of the area in X
/// \param dy - half-width of the area in Y
GridArea(const ca::Grid& grid, fscal x, fscal y, fscal dx, fscal dy);
/// \brief look up the next grid entry in the requested area
/// \return ind - the entry index in the grid.GetEntries() vector
/// \return true if the entry is found, false if there are no more entries in the area
bool GetNextGridEntry(ca::HitIndex_t& ind);
/// \brief look up the next object id in the requested area
/// \return objectId - the id of the object
/// \return true if the object is found, false if there are no more pbjects in the area
bool GetNextObjectId(ca::HitIndex_t& objectId);
/// \brief debug mode: loop over the entire GetEntries() vector ignoring the search area
void DoLoopOverEntireGrid();
private:
const ca::Grid& fGrid;
int fAreaLastBinY{0}; // last Y bin of the area
int fAreaNbinsX{0}; // number of area bins in X
int fAreaFirstBin{0}; // first bin of the area (left-down corner of the area)
int fAreaCurrentBinY{0}; // current Y bin (incremented while iterating)
ca::HitIndex_t fCurentEntry{0}; // index of the current entry in fGrid.GetEntries()
ca::HitIndex_t fEntriesXend{0}; // end of the hit indices in current y-row
int fGridNbinsX{0}; // Number of grid bins in X (copy of fGrid::GetNofBinsX())
};
inline GridArea::GridArea(const ca::Grid& grid, fscal x, fscal y, fscal dx, fscal dy)
: fGrid(grid)
, fGridNbinsX(fGrid.GetNofBinsX())
{
int binXmin = fGrid.GetBinX(x - dx);
int binXmax = fGrid.GetBinX(x + dx);
int binYmin = fGrid.GetBinY(y - dy);
int binYmax = fGrid.GetBinY(y + dy);
fAreaLastBinY = binYmax;
fAreaNbinsX = (binXmax - binXmin + 1); // bin index span in x direction
fAreaFirstBin = (binYmin * fGridNbinsX + binXmin);
fAreaCurrentBinY = binYmin;
fCurentEntry = fGrid.GetFirstBinEntryIndex(fAreaFirstBin);
fEntriesXend = fGrid.GetFirstBinEntryIndex(fAreaFirstBin + fAreaNbinsX);
}
inline bool GridArea::GetNextGridEntry(ca::HitIndex_t& ind)
{
bool xIndexOutOfRange = (fCurentEntry >= fEntriesXend); // current entry is not in the area
// jump to the next y row if fCurentEntry is outside of the X area
while (kfutils::IsUnlikely(xIndexOutOfRange)) {
if (kfutils::IsUnlikely(fAreaCurrentBinY >= fAreaLastBinY)) {
return false;
}
fAreaCurrentBinY++; // get new y-line
fAreaFirstBin += fGridNbinsX; // move the left-down corner of the area to the next y-line
fCurentEntry = fGrid.GetFirstBinEntryIndex(fAreaFirstBin); // get first hit in cell, if y-line is new
fEntriesXend = fGrid.GetFirstBinEntryIndex(fAreaFirstBin + fAreaNbinsX);
xIndexOutOfRange = (fCurentEntry >= fEntriesXend);
}
ind = fCurentEntry; // return value
fCurentEntry++; // go to next
return true;
}
inline bool GridArea::GetNextObjectId(ca::HitIndex_t& objectId)
{
ca::HitIndex_t entryIndex = 0;
bool ok = GetNextGridEntry(entryIndex);
if (ok) {
objectId = fGrid.GetEntries()[entryIndex].GetObjectId();
}
return ok;
}
inline void GridArea::DoLoopOverEntireGrid()
{
fCurentEntry = 0;
fEntriesXend = fGrid.GetEntries().size();
fAreaLastBinY = 0;
fAreaNbinsX = 0;
fAreaFirstBin = 0;
fAreaCurrentBinY = 0;
}
} // namespace cbm::algo::ca
/* Copyright (C) 2010-2020 Frankfurt Institute for Advanced Studies, Goethe-Universitaet Frankfurt, Frankfurt
SPDX-License-Identifier: GPL-3.0-only
Authors: Valentina Akishina, Igor Kulakov [committer], Maksym Zyzak */
#pragma once // include this header only once per compilation unit
#include "CaDefs.h"
#include "CaHit.h"
#include "CaSimd.h"
namespace cbm::algo::ca
{
/// \brief A class to store hit information on the ca::Grid
///
struct GridEntry {
GridEntry() = default;
GridEntry(const ca::Hit& hit, ca::HitIndex_t id) { Set(hit, id); };
void Set(const ca::Hit& hit, ca::HitIndex_t id)
{
fObjectId = id;
x = hit.X();
y = hit.Y();
z = hit.Z();
t = hit.T();
rangeX = hit.RangeX();
rangeY = hit.RangeY();
rangeT = hit.RangeT();
}
ca::HitIndex_t GetObjectId() const { return fObjectId; }
fscal Z() const { return z; }
fscal T() const { return t; }
fscal X() const { return x; }
fscal Y() const { return y; }
fscal RangeX() const { return rangeX; }
fscal RangeY() const { return rangeY; }
fscal RangeT() const { return rangeT; }
private:
constexpr static fscal kUndef = 0.; // TODO: test with constants::Undef<fscal>
ca::HitIndex_t fObjectId{0}; ///< hit id in L1Algo::fWindowHits array
fscal x{kUndef}; // x coordinate of the hit
fscal y{kUndef}; // y coordinate of the hit
fscal z{kUndef}; // z coordinate of the hit
fscal t{kUndef}; // t coordinate of the hit
fscal rangeX{kUndef}; // x range of the hit
fscal rangeY{kUndef}; // y range of the hit
fscal rangeT{kUndef}; // t range of the hit
};
} // namespace cbm::algo::ca
/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file CaHit.cxx
/// \date 23.10.2023
/// \brief A generic hit for the CA tracker (header) (implementation)
/// \author S.Zharko <s.zharko@gsi.de>
#include "CaHit.h"
#include <iomanip>
#include <sstream>
using cbm::algo::ca::Hit;
std::string Hit::ToString() const
{
std::stringstream ss;
ss << "Hit " << fId << " station " << fStation << " front key " << fFrontKey << " back key " << fBackKey << " X "
<< fX << " Y " << fY << " Z " << fZ << " T " << fT << " dX2 " << fDx2 << " dY2 " << fDy2 << " dXY " << fDxy
<< " dT2 " << fDt2 << " rangeX " << fRangeX << " rangeY " << fRangeY << " rangeT " << fRangeT;
return ss.str();
}
std::string Hit::ToString(int verbose, bool bHeader) const
{
if (verbose < 1) {
return "";
}
using std::setw;
constexpr int widthF = 12;
constexpr int widthI = 4;
std::stringstream msg;
if (bHeader) {
msg << setw(widthI) << "IDe" << ' ';
msg << setw(widthI) << "st." << ' ';
if (verbose > 1) {
msg << setw(widthI) << "keyF" << ' ';
msg << setw(widthI) << "keyB" << ' ';
}
msg << setw(widthF) << "x [cm]" << ' ';
msg << setw(widthF) << "y [cm]" << ' ';
msg << setw(widthF) << "z [cm]" << ' ';
msg << setw(widthF) << "t [ns]" << ' ';
if (verbose > 1) {
msg << setw(widthF) << "dx2 [cm2]" << ' ';
msg << setw(widthF) << "dy2 [cm2]" << ' ';
msg << setw(widthF) << "dxy [cm2]" << ' ';
msg << setw(widthF) << "dt2 [ns2]" << ' ';
if (verbose > 2) {
msg << setw(widthF) << "rangeX [cm]" << ' ';
msg << setw(widthF) << "rangeY [cm]" << ' ';
msg << setw(widthF) << "rangeT [ns]" << ' ';
}
}
}
else {
msg << setw(widthI) << fId << ' ';
msg << setw(widthI) << fStation << ' ';
if (verbose > 1) {
msg << setw(widthI) << fFrontKey << ' ';
msg << setw(widthI) << fBackKey << ' ';
}
msg << setw(widthF) << fX << ' ';
msg << setw(widthF) << fY << ' ';
msg << setw(widthF) << fZ << ' ';
msg << setw(widthF) << fT << ' ';
if (verbose > 1) {
msg << setw(widthF) << fDx2 << ' ';
msg << setw(widthF) << fDy2 << ' ';
msg << setw(widthF) << fDxy << ' ';
msg << setw(widthF) << fDt2 << ' ';
if (verbose > 2) {
msg << setw(widthF) << fRangeX << ' ';
msg << setw(widthF) << fRangeY << ' ';
msg << setw(widthF) << fRangeT << ' ';
}
}
}
return msg.str();
}
/* Copyright (C) 2007-2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Valentina Akishina, Igor Kulakov, Sergey Gorbunov [committer], Maksym Zyzak */
/// \file CaHit.h
/// \brief A generic hit for the CA tracker (header)
/// \date 2007-2023
#pragma once // include this header only once per compilation unit
#include "CaSimd.h"
#include <boost/serialization/access.hpp>
#include <string>
namespace cbm::algo::ca
{
struct CaHitTimeInfo {
fscal fEventTimeMin{-std::numeric_limits<fscal>::max() / 2.};
fscal fEventTimeMax{std::numeric_limits<fscal>::max() / 2.};
fscal fMaxTimeBeforeHit{0.}; //< max event time for hits [0 .. hit] in the station hit array
fscal fMinTimeAfterHit{0.}; //< min event time for hits [hit ... ] in the station hit array
};
// FIXME: Move typedefs to another header (potential problems with dependencies)
using HitIndex_t = unsigned int; ///< Index of ca::Hit
using HitKeyIndex_t = unsigned int; ///< Index of the hit key (e.g. front / back cluster id for STS)
/// \brief ca::Hit class describes a generic hit for the CA tracker
///
class Hit {
friend class boost::serialization::access;
public:
/// Default constructor
Hit() = default;
/// \brief Checks, if the hit is defined
/// \return true Hit is defined
/// \return false Hit is undefined and will be skipped
bool Check() const;
///-----------------------------------------------------------------------------
/// setters
/// Set the front key index
void SetFrontKey(HitKeyIndex_t key) { fFrontKey = key; }
/// Set the back key index
void SetBackKey(HitKeyIndex_t key) { fBackKey = key; }
/// Set the X coordinate
void SetX(fscal x) { fX = x; }
/// Set the Y coordinate
void SetY(fscal y) { fY = y; }
/// Set the Z coordinate
void SetZ(fscal z) { fZ = z; }
/// Set the time
void SetT(fscal t) { fT = t; }
/// Set the uncertainty of X coordinate
void SetDx2(fscal dx2) { fDx2 = dx2; }
/// Set the uncertainty of Y coordinate
void SetDy2(fscal dy2) { fDy2 = dy2; }
/// Set the X/Y covariance
void SetDxy(fscal dxy) { fDxy = dxy; }
/// Set the uncertainty of time
void SetDt2(fscal dt2) { fDt2 = dt2; }
/// Set the +/- range of uncertainty of X coordinate
void SetRangeX(fscal rangeX) { fRangeX = rangeX; }
/// Set the +/- range of uncertainty of Y coordinate
void SetRangeY(fscal rangeY) { fRangeY = rangeY; }
/// Set the +/- range of uncertainty of time
void SetRangeT(fscal rangeT) { fRangeT = rangeT; }
/// Set the hit id
void SetId(HitIndex_t id) { fId = id; }
/// Set the station index
void SetStation(int station) { fStation = station; }
///-----------------------------------------------------------------------------
/// getters
/// Get the front key index
HitKeyIndex_t FrontKey() const { return fFrontKey; }
/// Get the back key index
HitKeyIndex_t BackKey() const { return fBackKey; }
/// Get the X coordinate
fscal X() const { return fX; }
/// Get the Y coordinate
fscal Y() const { return fY; }
/// Get the Z coordinate
fscal Z() const { return fZ; }
/// Get the time
fscal T() const { return fT; }
/// Get the uncertainty of X coordinate
fscal dX2() const { return fDx2; }
/// Get the uncertainty of Y coordinate
fscal dY2() const { return fDy2; }
/// Get the X/Y covariance
fscal dXY() const { return fDxy; }
/// Get the uncertainty of time
fscal dT2() const { return fDt2; }
/// Get the +/- range of uncertainty of X coordinate
fscal RangeX() const { return fRangeX; }
/// Get the +/- range of uncertainty of Y coordinate
fscal RangeY() const { return fRangeY; }
/// Get the +/- range of uncertainty of time
fscal RangeT() const { return fRangeT; }
/// Get the hit id
HitIndex_t Id() const { return fId; }
/// Get the station index
int Station() const { return fStation; }
/// \brief Simple string representation of the hit class
std::string ToString() const;
/// \brief String representation of the hit class
/// \param verbose Verbosity level
/// \param bHeader If true, prints the header
std::string ToString(int verbose, bool bHeader) const;
private:
///-----------------------------------------------------------------------------
/// data members
/// NOTE: For STS f and b correspond to the indexes of the front and back clusters of the hit in a dataset. For other
/// tracking detectors (MVD, MuCh, TRD, TOF) f == b and corresponds to the index of the hit. Indexes f and b
/// do not intersect between different detector stations.
HitKeyIndex_t fFrontKey{0}; ///< front hit key index
HitKeyIndex_t fBackKey{0}; ///< back hit key index
fscal fX{0.}; ///< measured X coordinate [cm]
fscal fY{0.}; ///< measured Y coordinate [cm]
fscal fZ{0.}; ///< fixed Z coordinate [cm]
fscal fT{0.}; ///< measured time [ns]
fscal fDx2{0.}; ///< rms^2 of uncertainty of X coordinate [cm2]
fscal fDy2{0.}; ///< rms^2 of uncertainty of Y coordinate [cm2]
fscal fDxy{0.}; ///< X/Y covariance [cm2]
fscal fDt2{0.}; ///< measured uncertainty of time [ns2]
fscal fRangeX{0.}; ///< +/- range of uncertainty of X coordinate [cm]
fscal fRangeY{0.}; ///< +/- range of uncertainty of Y coordinate [cm]
fscal fRangeT{0.}; ///< +/- range of uncertainty of time [ns]
HitIndex_t fId{0}; ///< id of the hit
int fStation{-1}; ///< index of station in the active stations array
private:
/// Serialization method, used to save ca::Hit objects into binary or text file in a defined order
template<class Archive>
void serialize(Archive& ar, const unsigned int /*version*/)
{
ar& fFrontKey;
ar& fBackKey;
ar& fX;
ar& fY;
ar& fZ;
ar& fT;
ar& fDx2;
ar& fDy2;
ar& fDxy;
ar& fDt2;
ar& fRangeX;
ar& fRangeY;
ar& fRangeT;
ar& fId;
ar& fStation;
}
};
// -------------------------------------------------------------------------------------------------------------------
//
inline bool Hit::Check() const
{
bool res = true;
res &= std::isfinite(fX);
res &= std::isfinite(fY);
res &= std::isfinite(fZ);
res &= std::isfinite(fT);
res &= std::isfinite(fDx2);
res &= std::isfinite(fDy2);
res &= std::isfinite(fDxy);
res &= std::isfinite(fDt2);
res &= (fDx2 || fDy2 || fDxy || fDt2); // TODO: research
res &= (fT < 1.e+9);
return res;
}
} // namespace cbm::algo::ca
/* Copyright (C) 2022-2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergey Gorbunov, Sergei Zharko [committer] */
/// \file CaInputData.cxx
/// \brief Structure for input data to the L1 tracking algorithm (implementation)
/// \since 08.08.2022
/// \author Sergei Zharko <s.zharko@gsi.de>
#include "CaInputData.h"
using cbm::algo::ca::InputData;
// ---------------------------------------------------------------------------------------------------------------------
//
InputData::InputData() {}
// ---------------------------------------------------------------------------------------------------------------------
//
InputData::InputData(const InputData& other)
: fvHits(other.fvHits)
, fvStreamStartIndices(other.fvStreamStartIndices)
, fvStreamStopIndices(other.fvStreamStopIndices)
, fNhitKeys(other.fNhitKeys)
{
}
// ---------------------------------------------------------------------------------------------------------------------
//
InputData::InputData(InputData&& other) noexcept { this->Swap(other); }
// ---------------------------------------------------------------------------------------------------------------------
//
InputData& InputData::operator=(const InputData& other)
{
if (this != &other) {
InputData(other).Swap(*this);
}
return *this;
}
// ---------------------------------------------------------------------------------------------------------------------
//
InputData& InputData::operator=(InputData&& other) noexcept
{
if (this != &other) {
InputData tmp(std::move(other));
this->Swap(tmp);
}
return *this;
}
/* Copyright (C) 2022-2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergey Gorbunov, Sergei Zharko [committer] */
/// \file CaInputData.h
/// \brief Structure for input data to the L1 tracking algorithm (declaration)
/// \since 08.08.2022
/// \author Sergei Zharko <s.zharko@gsi.de>
#pragma once // include this header only once per compilation unit
#include "CaDefs.h"
#include "CaHit.h"
#include "CaVector.h"
#include <boost/serialization/access.hpp>
#include <boost/serialization/array.hpp>
namespace cbm::algo::ca
{
/// Class InputData represents a block of the input data to the L1 tracking algorithm per event or time slice.
/// Filling of the InputData is carried out with L1IODataManager class
///
class alignas(constants::misc::Alignment) InputData {
public:
friend class DataManager; ///< Class which fills the InputData object for each event or time slice
friend class boost::serialization::access;
/// \brief Default constructor
InputData();
/// \brief Destructor
~InputData() = default;
/// \brief Copy constructor
InputData(const InputData& other);
/// \brief Move constructor
InputData(InputData&&) noexcept;
/// \brief Copy assignment operator
InputData& operator=(const InputData& other);
/// \brief Move assignment operator
InputData& operator=(InputData&& other) noexcept;
/// \brief Gets hits sample size
HitIndex_t GetSampleSize() const { return fvHits.size(); }
/// \brief Gets number of data streams
int GetNdataStreams() const { return fvStreamStartIndices.size(); }
/// \brief Gets reference to hit by its index
/// \param index Index of hit in the hits sample
const Hit& GetHit(HitIndex_t index) const { return fvHits[index]; }
/// \brief Gets reference to hits vector
const Vector<Hit>& GetHits() const { return fvHits; }
/// \brief Gets number of hits in the hits vector
HitIndex_t GetNhits() const { return fvHits.size(); }
/// \brief Gets total number of stored keys
int GetNhitKeys() const { return fNhitKeys; }
/// \brief Gets index of the first hit in the sorted hits vector
/// \param iStream Index of the data stream
HitIndex_t GetStreamStartIndex(int iStream) const { return fvStreamStartIndices[iStream]; }
/// \brief Gets index of (the last + 1) hit in the sorted hits vector
/// \param iStream Index of the data stream
HitIndex_t GetStreamStopIndex(int iStream) const { return fvStreamStopIndices[iStream]; }
/// \brief Gets n hits for the data stream
/// \param iStream Index of the data stream
HitIndex_t GetStreamNhits(int iStream) const
{
return fvStreamStopIndices[iStream] - fvStreamStartIndices[iStream];
}
private:
/// \brief Swap method
void Swap(InputData& other) noexcept;
/// \brief Data serialization method
template<class Archive>
void serialize(Archive& ar, const unsigned int /*versino*/)
{
ar& fvHits;
ar& fvStreamStartIndices;
ar& fvStreamStopIndices;
ar& fNhitKeys;
}
// ***************************
// ** Member variables list **
// ***************************
/// \brief Sample of input hits
Vector<Hit> fvHits{"InputData::fHits"};
/// \brief Index of the first hit in the sorted hits vector for a given data stream
Vector<HitIndex_t> fvStreamStartIndices{"InputData::fStreamStartIndices"};
Vector<HitIndex_t> fvStreamStopIndices{"InputData::fStreamStopIndices"};
/// \brief Number of hit keys used for rejecting fake STS hits
int fNhitKeys = -1;
};
// ********************************************
// ** Inline member functions initialization **
// *********************************************
// -------------------------------------------------------------------------------------------------------------------
//
[[gnu::always_inline]] inline void InputData::Swap(InputData& other) noexcept
{
std::swap(fvHits, other.fvHits);
std::swap(fvStreamStartIndices, other.fvStreamStartIndices);
std::swap(fvStreamStopIndices, other.fvStreamStopIndices);
std::swap(fNhitKeys, other.fNhitKeys);
}
} // namespace cbm::algo::ca
/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file CaTimesliceHeader.cxx
/// \brief A structure to keep all the common information on the timeslice coming from tracking (implementation)
/// \since 15.02.2024
/// \author Sergei Zharko <s.zharko@gsi.de>
#include "CaTimesliceHeader.h"
#include <sstream>
using cbm::algo::ca::TimesliceHeader;
// ---------------------------------------------------------------------------------------------------------------------
//
std::string TimesliceHeader::ToString() const
{
std::stringstream msg;
msg << "TimesliceHeader: start = " << fStart << " [ns], end = " << fEnd << " [ns]";
return msg.str();
}
/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file CaTimesliceHeader.h
/// \brief A structure to keep all the common information on the timeslice coming from tracking
/// \since 15.02.2024
/// \author Sergei Zharko <s.zharko@gsi.de>
#pragma once
#include <string>
namespace cbm::algo::ca
{
/// \class TimesliceHeader
/// \brief Structure for keeping the current information on the timeslice
class TimesliceHeader {
public:
/// \brief Accesses the end of timeslice [ns]
float& End() { return fEnd; }
float End() const { return fEnd; }
/// \brief Accesses the start of timeslice [ns]
float& Start() { return fStart; }
float Start() const { return fStart; }
/// \brief String representation of the contents
std::string ToString() const;
/// \brief Converts time from ns to tau
float ConvToTau(float time) const { return (time - fStart) / (fEnd - fStart); }
/// \brief Converts time from tau to ns
float ConvToNs(float tau) const { return fStart + tau * (fEnd - fStart); }
private:
float fStart; ///< Start of timeslice
float fEnd; ///< End of timeslice
};
} // namespace cbm::algo::ca
/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file CaTrack.h
/// \brief source file for the ca::Track class
/// \since 02.06.2022
/// \author S.Zharko <s.zharko@gsi.de>
#include "CaTrack.h"
/* Copyright (C) 2010-2023 Frankfurt Institute for Advanced Studies, Goethe-Universitaet Frankfurt, Frankfurt
SPDX-License-Identifier: GPL-3.0-only
Authors: Ivan Kisel, Sergey Gorbunov, Maksym Zyzak, Igor Kulakov [committer], Sergei Zharko */
/// \file CaTrack.h
/// \brief header file for the ca::Track class
/// \since 02.06.2022
/// \author S.Zharko <s.zharko@gsi.de>
#ifndef CA_CORE_CaTrack_h
#define CA_CORE_CaTrack_h 1
#include "CaDefs.h"
#include "CaSimd.h"
#include "KfTrackParam.h"
#include <boost/serialization/access.hpp>
namespace cbm::algo::ca
{
/// \class cbm::algo::ca::Track
/// \brief Class representing an output track in the CA tracking algorithm
///
/// Track parameters vector: {x, y, tx, ty, q/p, z, t, vi}
/// Covariation matrix: C[20] (C55) corresponds to the time variance
///
class Track {
public:
using TrackParam_t = cbm::algo::kf::TrackParamS;
friend class boost::serialization::access;
Track() = default;
template<class Archive>
void serialize(Archive& ar, const unsigned int /*version*/)
{
ar& fNofHits;
ar& fParFirst;
ar& fParLast;
ar& fParPV;
}
public:
int fNofHits{kfdefs::Undef<int>}; ///< Number of hits in track
TrackParam_t fParFirst; ///< Track parameters on the first station
TrackParam_t fParLast; ///< Track parameters on the last station
TrackParam_t fParPV; ///< Track parameters in the primary vertex
};
} // namespace cbm::algo::ca
#endif // CA_CORE_CaTrack_h
/* Copyright (C) 2019-2020 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Valentina Akishina, Sergey Gorbunov[committer] */
#include "CaTriplet.h"
#include <sstream>
#include <string>
std::string cbm::algo::ca::Triplet::ToString(int indentLevel) const
{
/// print the triplet parameters
std::stringstream ss{};
constexpr char indentChar = '\t';
std::string indent(indentLevel, indentChar);
ss << indent << "Triplet: station L/M/R " << GetLSta() << "/" << GetMSta() << "/" << GetRSta() << "\n"
<< indent << " hit L/M/R " << fHitL << "/" << fHitM << "/" << fHitR << "\n"
<< indent << " level " << fLevel << " first neighbor " << fFirstNeighbour << " Nneighbors "
<< fNneighbours << "\n"
<< indent << " qp " << fQp << " Cqp " << fCqp << " chi2 " << fChi2 << "\n"
<< indent << " tx " << fTx << " Ctx " << fCtx << " ty " << fTy << " Cty " << fCty << std::endl;
return ss.str();
}
/* Copyright (C) 2019-2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Valentina Akishina, Sergey Gorbunov[committer] */
/// \file CaTriplet.h
/// \author Sergey Gorbunov
/// \author Valentina Akishina
/// \date 2021-05-18
#pragma once // include this header only once per compilation unit
#include "CaHit.h"
#include "CaSimd.h"
#include <string>
namespace cbm::algo::ca
{
/// \brief Triplet class represents a short 3-hits track segment called a "triplet".
///
class Triplet {
public:
/// Default constructor
Triplet() = default;
/// Constructor
Triplet(ca::HitIndex_t iHitL, ca::HitIndex_t iHitM, ca::HitIndex_t iHitR, unsigned int iStaL, unsigned int iStaM,
unsigned int iStaR, unsigned char Level, unsigned int firstNeighbour, char nNeighbours, fscal Chi2,
fscal Qp, fscal Cqp, fscal tx, fscal Ctx, fscal ty, fscal Cty, bool isMomentumFitted)
: fChi2(Chi2)
, fQp(Qp)
, fCqp(Cqp)
, fTx(tx)
, fCtx(Ctx)
, fTy(ty)
, fCty(Cty)
, fFirstNeighbour(firstNeighbour)
, fHitL(iHitL)
, fHitM(iHitM)
, fHitR(iHitR)
, fNneighbours(nNeighbours)
, fLevel(Level)
, fSta((iStaL << 4) + ((iStaM - iStaL - 1) << 2) + (iStaR - iStaL - 2))
, fIsMomentumFitted(isMomentumFitted)
{
}
/// Setters and getters
void SetLevel(unsigned char Level) { fLevel = Level; }
unsigned char GetLevel() const { return fLevel; }
ca::HitIndex_t GetLHit() const { return fHitL; }
ca::HitIndex_t GetMHit() const { return fHitM; }
ca::HitIndex_t GetRHit() const { return fHitR; }
void SetNNeighbours(int n) { fNneighbours = n; }
int GetNNeighbours() const { return fNneighbours; }
void SetFNeighbour(unsigned int n) { fFirstNeighbour = n; }
unsigned int GetFNeighbour() const { return fFirstNeighbour; }
fscal GetQp() const { return fQp; }
fscal GetChi2() const { return fChi2; }
fscal GetTime() const { return -111.; }
int GetLSta() const { return fSta >> 4; }
int GetMSta() const { return ((fSta % 16) >> 2) + GetLSta() + 1; }
int GetRSta() const { return (fSta % 4) + GetLSta() + 2; }
fscal GetCqp() const { return fCqp; }
fscal GetTx() const { return fTx; }
fscal GetCtx() const { return fCtx; }
fscal GetTy() const { return fTy; }
fscal GetCty() const { return fCty; }
bool IsMomentumFitted() const { return fIsMomentumFitted; }
void SetIsMomentumFitted(bool val) { fIsMomentumFitted = val; }
/// String representation of class contents
/// \param indentLevel number of indent characters in the output
std::string ToString(int indentLevel = 0) const;
private:
///-----------------------------------------------------------------------------------------------
/// Data members
fscal fChi2{0.}; ///< chi^2
fscal fQp{0.}; ///< q/p
fscal fCqp{0.}; ///< RMS^2 of q/p
fscal fTx{0.}; ///< tx at the left hit
fscal fCtx{0.}; ///< RMS^2 of tx
fscal fTy{0.}; ///< ty at the left hit
fscal fCty{0.}; ///< RMS^2 of ty
unsigned int fFirstNeighbour{0}; ///< ID of the first neighbouring triplet
ca::HitIndex_t fHitL{0}; ///< left hit index (16b) in vHits array
ca::HitIndex_t fHitM{0}; ///< middle hit index (16b)
ca::HitIndex_t fHitR{0}; ///< right hit index (16b)
int fNneighbours{0}; ///< n of neighbouring triplets
/// Triplet level - its possible position on the longest track candidate it belongs to.
/// level 0 = rightmost triplet of a track candidate
/// level k = k-ths triplet along the track counting upstream, from right to left.
unsigned char fLevel{0};
unsigned short fSta{0}; ///< packed station numbers: staL (12b), staM-1-staL (2b), staR-2-staL (2b)
bool fIsMomentumFitted{0}; ///< if the triplet momentum is fitted
};
} // namespace cbm::algo::ca
/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file CaWindowData.h
/// \author Sergei Zharko <s.zharko@gsi.de>
/// \brief Container for all data, which are processed within a single sub-timeslice (implementation)
/// \since 29.01.2024
#include "CaWindowData.h"
using cbm::algo::ca::WindowData;
// ---------------------------------------------------------------------------------------------------------------------
//
void WindowData::ResetHitData(int nHits)
{
fvHits.reset(nHits);
fvbHitSuppressed.reset(nHits, 0);
}
/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file CaWindowData.h
/// \author Sergei Zharko <s.zharko@gsi.de>
/// \brief Container for all data, which are processed within a single sub-timeslice
/// \since 29.01.2024
#pragma once
#include "CaDefs.h"
#include "CaGrid.h"
#include "CaHit.h"
#include "CaIteration.h"
#include "CaTrack.h"
#include "KfFieldRegion.h"
#include "KfMeasurementXy.h"
#include <array>
namespace cbm::algo::ca
{
/// \class WindowData
/// \brief Container for internal data, processed on a single time window
class WindowData {
public:
/// \brief Constructor
WindowData() = default;
/// \brief Destructor
~WindowData() = default;
/// \brief Gets grid for station index
/// \param iStation Index of the tracking station
[[gnu::always_inline]] ca::Grid& Grid(int iStation) { return fvGrid[iStation]; }
/// \brief Gets grid for station index
/// \param iStation Index of the tracking station
[[gnu::always_inline]] const ca::Grid& Grid(int iStation) const { return fvGrid[iStation]; }
/// \brief Gets hit by index
/// \param iHit Hit index
[[gnu::always_inline]] ca::Hit& Hit(int iHit) { return fvHits[iHit]; }
/// \brief Gets hit by index
/// \param iHit Hit index
[[gnu::always_inline]] const ca::Hit& Hit(int iHit) const { return fvHits[iHit]; }
/// \brief Gets hit vector
[[gnu::always_inline]] Vector<ca::Hit>& Hits() { return fvHits; }
/// \brief Gets hit vector
[[gnu::always_inline]] const Vector<ca::Hit>& Hits() const { return fvHits; }
/// \brief Gets hit suppression flag
/// \param iHit Hit index
[[gnu::always_inline]] uint8_t IsHitSuppressed(int iHit) const { return fvbHitSuppressed[iHit]; }
/// \brief Resets hit data
/// \param nHits Number of hits in the sample
void ResetHitData(int nHits);
/// \brief Reset suppressed hit flags
[[gnu::always_inline]] void ResetHitSuppressionFlags() { fvbHitSuppressed.reset(fvHits.size(), 0); }
/// \brief Set hit suppression flag
[[gnu::always_inline]] void SuppressHit(int iHit) { fvbHitSuppressed[iHit] = 1; }
/// \brief Index of the first hit on the station
/// \param iStation Index of the tracking station
[[gnu::always_inline]] HitIndex_t& HitStartIndexOnStation(int iStation)
{
return fvHitStartIndexOnStation[iStation];
}
/// \brief Hit key flag: if this hit or cluster was already used
/// \param iKey Index of the key (index of the hit or the cluster)
[[gnu::always_inline]] unsigned char IsHitKeyUsed(HitKeyIndex_t iKey) const { return fvbHitKeyFlags[iKey]; }
/// \brief Hit key flag: if this hit or cluster was already used
/// \param iKey Index of the key (index of the hit or the cluster)
[[gnu::always_inline]] unsigned char& IsHitKeyUsed(HitKeyIndex_t iKey) { return fvbHitKeyFlags[iKey]; }
/// \brief Access to the hit key flags container
[[gnu::always_inline]] Vector<unsigned char>& HitKeyFlags() { return fvbHitKeyFlags; }
/// \brief Index of the first hit on the station
/// \param iStation Index of the tracking station
[[gnu::always_inline]] HitIndex_t HitStartIndexOnStation(int iStation) const
{
return fvHitStartIndexOnStation[iStation];
}
/// \brief Number of hits on station
/// \param iStation Index of the tracking station
[[gnu::always_inline]] HitIndex_t& NofHitsOnStation(int iStation) { return fvNofHitsOnStation[iStation]; }
/// \brief Number of hits on station
/// \param iStation Index of the tracking station
[[gnu::always_inline]] HitIndex_t NofHitsOnStation(int iStation) const { return fvNofHitsOnStation[iStation]; }
/// \brief Accesses indices of hits, used by reconstructed tracks
[[gnu::always_inline]] Vector<HitIndex_t>& RecoHitIndices() { return fvRecoHitIndices; }
/// \brief Accesses indices of hits
[[gnu::always_inline]] const Vector<HitIndex_t>& RecoHitIndices() const { return fvRecoHitIndices; }
/// \brief Accesses index of hit in the input data
/// \param iHit Index of reconstructed hit, used in reconstructed tracks
/// \return Index of reconstructed hit in the algorithm input data object
[[gnu::always_inline]] HitIndex_t& RecoHitIndex(int iHit) { return fvRecoHitIndices[iHit]; }
/// \brief Accesses index of hit in the input data
/// \param iHit Index of reconstructed hit, used in reconstructed tracks
/// \return Index of reconstructed hit in the algorithm input data object
[[gnu::always_inline]] HitIndex_t RecoHitIndex(int iHit) const { return fvRecoHitIndices[iHit]; }
/// \brief Accesses reconstructed track by index
/// \param iTrack Track index
[[gnu::always_inline]] Track& RecoTrack(int iTrack) { return fvRecoTracks[iTrack]; }
/// \brief Accesses reconstructed track by index
/// \param iTrack Track index
[[gnu::always_inline]] const Track& RecoTrack(int iTrack) const { return fvRecoTracks[iTrack]; }
/// \brief Accesses reconstructed track container
[[gnu::always_inline]] Vector<Track>& RecoTracks() { return fvRecoTracks; }
/// \brief Accesses reconstructed track container
[[gnu::always_inline]] const Vector<Track>& RecoTracks() const { return fvRecoTracks; }
/// \brief Maps hit index from the time window to the time slice
/// \param iSt Index of tracking station
/// \param iHit Index of hit in the window
[[gnu::always_inline]] HitIndex_t TsHitIndex(int iSt, int iHit) const { return fvTsHitIndices[iSt][iHit]; }
/// \brief Accesses container of hit index map from the time window to the time slice
/// \param iSt Index of tracking station
[[gnu::always_inline]] Vector<HitIndex_t>& TsHitIndices(int iSt) { return fvTsHitIndices[iSt]; }
/// \brief Accesses container of hit index map from the time window to the time slice
/// \param iSt Index of tracking station
[[gnu::always_inline]] const Vector<HitIndex_t>& TsHitIndices(int iSt) const { return fvTsHitIndices[iSt]; }
/// \brief Accesses current iteration
[[gnu::always_inline]] void SetCurrentIteration(const Iteration* ptr) { fpCurrentIteration = ptr; }
/// \brief Accesses current iteration
[[gnu::always_inline]] const Iteration* CurrentIteration() const { return fpCurrentIteration; }
/// \brief Accesses magnetic field in starting point (target or first station)
[[gnu::always_inline]] kf::FieldValue<fvec>& TargB() { return fTargB; }
/// \brief Accesses magnetic field in starting point (target or first station)
[[gnu::always_inline]] const kf::FieldValue<fvec>& TargB() const { return fTargB; }
/// \brief Measurement of the target with the uncertainty
[[gnu::always_inline]] kf::MeasurementXy<fvec>& TargetMeasurement() { return fTargetMeasurement; }
/// \brief Measurement of the target with the uncertainty
[[gnu::always_inline]] const kf::MeasurementXy<fvec>& TargetMeasurement() const { return fTargetMeasurement; }
private:
static constexpr int kMaxNofStations = constants::size::MaxNstations; ///< Alias to max number of stations
/// \brief Grid vs. station index
std::array<ca::Grid, kMaxNofStations> fvGrid;
/// \brief Hits of the current time window
///
/// It is a portion of fInputData to process in the current time window
/// hit.Id is replaced by the hit index in fInputData
Vector<ca::Hit> fvHits{"WindowData::fHits"};
/// \brief List of used hit keys
/// \note Global for all the time windows within one thread
Vector<unsigned char> fvbHitKeyFlags{"WindowData::fvbHitKeyFlags"};
/// \brief Flag, if the hit is suppressed for tracking
Vector<unsigned char> fvbHitSuppressed{"WindowData::fvbHitSuppressed"};
/// \brief First hit index of the station
std::array<HitIndex_t, kMaxNofStations + 1> fvHitStartIndexOnStation = {0};
/// \brief Number of hits on the station
std::array<HitIndex_t, kMaxNofStations + 1> fvNofHitsOnStation = {0};
/// \brief Sample of reconstructed tracks
Vector<Track> fvRecoTracks{"WindowData::fvRecoTracks"};
/// \brief Sample of reconstructed hit indices
Vector<HitIndex_t> fvRecoHitIndices{"WindowData::fvRecoHitIndices"};
/// \brief Map of hit indices from the time window to the time slice
std::array<Vector<HitIndex_t>, kMaxNofStations> fvTsHitIndices{"WindowData::fvFullDSHitIndex"};
/// \brief Current track-finder iteration
const Iteration* fpCurrentIteration = nullptr;
kf::FieldValue<fvec> fTargB{}; ///< field in the target point (modifiable, do not touch!!)
kf::MeasurementXy<fvec> fTargetMeasurement{}; ///< target constraint
} _fvecalignment;
} // namespace cbm::algo::ca
/* Copyright (C) 2022-2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file ConfigReader.h
/// \brief Configuration parameter file reader/writer for L1 tracking algorithm (implementation)
/// \author S.Zharko <s.zharko@gsi.de>
/// \since 18.07.2022
#include "CaConfigReader.h"
#include "CaDefs.h"
#include "CaInitManager.h"
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <numeric>
#include <sstream>
#include <unordered_map>
#include <yaml-cpp/yaml.h>
using cbm::algo::ca::ConfigReader;
using cbm::algo::ca::EDetectorID;
using cbm::algo::ca::InitManager;
using cbm::algo::ca::Iteration;
// ---------------------------------------------------------------------------------------------------------------------
//
ConfigReader::ConfigReader(InitManager* pInitManager, int verbose) : fpInitManager(pInitManager), fVerbose(verbose) {}
// ---------------------------------------------------------------------------------------------------------------------
//
// TODO: switch to the Yaml library by Felix
YAML::Node ConfigReader::GetNode(std::function<YAML::Node(YAML::Node)> fn, bool optional) const
{
auto node = YAML::Node(YAML::NodeType::Undefined);
if (fUserConfigNode) {
node = fn(fUserConfigNode);
}
if (!node) {
node = fn(fMainConfigNode);
}
if (!node && !optional) {
std::stringstream msg;
msg << "requested node was not found ";
if (fUserConfigNode) {
msg << "either in user config (path: " << fsUserConfigPath << ") or ";
}
msg << "in main config (path: " << fsMainConfigPath << ")";
throw std::runtime_error(msg.str());
}
return node;
}
// ---------------------------------------------------------------------------------------------------------------------
//
std::vector<std::string> ConfigReader::GetNodeKeys(const YAML::Node& node) const
{
std::vector<std::string> res;
res.reserve(node.size());
try {
for (const auto& item : node) {
res.push_back(item.first.as<std::string>());
}
}
catch (const YAML::InvalidNode& exc) {
LOG(warn)
<< "L1 config: attempt to call ConfigReader::GetNodeKeys for node, keys of which could not be represented "
<< "with strings. An empty vector will be returned";
std::vector<std::string>().swap(res);
}
return res;
}
// ---------------------------------------------------------------------------------------------------------------------
//
void ConfigReader::Read()
{
// TODO: Remove fbGeometryLock as soon as the legacy geometry variables are removed from the ca::Parameters class
if (!fbGeometryLock) { // Unset inactive tracking stations
if (fVerbose >= 1) {
LOG(info) << "- disabling inactive tracking stations";
}
auto inactiveMap = this->ReadInactiveStationMap();
if (std::any_of(inactiveMap.begin(), inactiveMap.end(), [](const auto& s) { return (s.size() != 0); })) {
for (auto& station : fpInitManager->GetStationInfo()) {
int iDet = static_cast<int>(station.GetDetectorID());
int iStLoc = station.GetStationID();
if (inactiveMap[iDet].find(iStLoc) != inactiveMap[iDet].end()) {
station.SetTrackingStatus(false);
}
}
// Since we disabled some stations, we have to rerun the layout initialization again, thus the station scheme is
// kept consistent
fpInitManager->InitStationLayout();
}
}
{ // Init CA iterations in L1InitManager
if (fVerbose >= 1) {
LOG(info) << "- reading track finder iterations";
}
auto iters = this->ReadCAIterationVector();
assert(iters.size());
fpInitManager->ClearCAIterations();
fpInitManager->SetCAIterationsNumberCrosscheck(iters.size());
std::for_each(iters.begin(), iters.end(), [&](auto& iter) { fpInitManager->PushBackCAIteration(iter); });
}
// Init parameters, independnent from the tracking iteration
if (fVerbose >= 1) {
LOG(info) << "- reading miscellaneous parameters";
}
fpInitManager->SetRandomSeed(
GetNode([](YAML::Node n) { return n["core"]["common"]["random_seed"]; }).as<unsigned int>());
fpInitManager->SetGhostSuppression(
GetNode([](YAML::Node n) { return n["core"]["track_finder"]["is_ghost_suppression"]; }).as<bool>());
fpInitManager->SetMaxDoubletsPerSinglet(
GetNode([](YAML::Node n) { return n["core"]["track_finder"]["max_doublets_per_singlet"]; }).as<unsigned int>());
fpInitManager->SetMaxTripletPerDoublets(
GetNode([](YAML::Node n) { return n["core"]["track_finder"]["max_triplets_per_doublet"]; }).as<unsigned int>());
ReadMisalignmentTolerance();
if (fVerbose >= 1) {
LOG(info) << "- reading developement parameters";
}
// Dev flags
fpInitManager->DevSetIgnoreHitSearchAreas(
GetNode([](YAML::Node n) { return n["core"]["dev"]["ignore_hit_search_areas"]; }).as<bool>());
fpInitManager->DevSetUseOfOriginalField(
GetNode([](YAML::Node n) { return n["core"]["dev"]["use_of_original_field"]; }).as<bool>());
fpInitManager->DevSetIsMatchDoubletsViaMc(
GetNode([](YAML::Node n) { return n["core"]["dev"]["match_doublets_via_mc"]; }).as<bool>());
fpInitManager->DevSetIsMatchTripletsViaMc(
GetNode([](YAML::Node n) { return n["core"]["dev"]["match_triplets_via_mc"]; }).as<bool>());
fpInitManager->DevSetIsExtendTracksViaMc(
GetNode([](YAML::Node n) { return n["core"]["dev"]["extend_tracks_via_mc"]; }).as<bool>());
fpInitManager->DevSetIsSuppressOverlapHitsViaMc(
GetNode([](YAML::Node n) { return n["core"]["dev"]["suppress_overlap_hits_via_mc"]; }).as<bool>());
}
// ---------------------------------------------------------------------------------------------------------------------
//
std::vector<Iteration> ConfigReader::ReadCAIterationVector()
{
std::vector<Iteration> res;
// Read iterations store
std::unordered_map<std::string, Iteration> mPossibleIterations;
{
auto currentNode = fMainConfigNode["possible_iterations"];
assert(currentNode);
for (const auto& iterNode : currentNode) {
std::string thisIterName = iterNode["name"].as<std::string>("");
std::string baseIterName = iterNode["base_iteration"].as<std::string>("");
if (baseIterName.size()) { // Create iteration from previously defined one
if (mPossibleIterations.find(baseIterName) == mPossibleIterations.end()) {
std::stringstream msg;
msg << "A CA iteration \"" << thisIterName << "\" requires a base iteration with name \"" << baseIterName
<< "\", which was not registered yet. Please, place an entry with the requested base iteration above "
<< "in the possible_iterations node";
throw std::runtime_error(std::move(msg.str()));
}
mPossibleIterations[thisIterName] = ReadSingleCAIteration(iterNode, mPossibleIterations.at(baseIterName));
}
else {
mPossibleIterations[thisIterName] = ReadSingleCAIteration(iterNode, Iteration());
}
}
}
// Read actual iteration sequence
//
if (fUserConfigNode) {
if (fVerbose >= 1) {
LOG(info) << "- Reading user iterations ";
}
auto currentNode = fUserConfigNode["core"]["track_finder"]["iterations"];
if (currentNode) {
for (const auto& iterNode : currentNode) {
std::string thisIterName = iterNode["name"].as<std::string>("");
std::string baseIterName = iterNode["base_iteration"].as<std::string>("");
if (fVerbose >= 2) {
LOG(info) << "- Reading user iteration " << thisIterName << "(" << baseIterName << ")";
}
if (mPossibleIterations.find(thisIterName) != mPossibleIterations.end()) {
// This is an update of existing possible iteration
if (fVerbose >= 2) {
LOG(info) << "- Select A";
}
res.push_back(ReadSingleCAIteration(iterNode, mPossibleIterations.at(thisIterName)));
}
else if (mPossibleIterations.find(baseIterName) != mPossibleIterations.end()) {
// This is a user iteration based on the existing possible iteration
if (fVerbose >= 2) {
LOG(info) << "- Select B";
}
res.push_back(ReadSingleCAIteration(iterNode, mPossibleIterations.at(baseIterName)));
}
else {
// Try to find a base iteration from user-defined
auto itFound = std::find_if(res.begin(), res.end(), [&](auto& i) { return i.GetName() == baseIterName; });
if (itFound != res.end()) {
if (fVerbose >= 2) {
LOG(info) << "- Select C";
}
res.push_back(ReadSingleCAIteration(iterNode, *itFound));
}
else {
if (fVerbose >= 2) {
LOG(info) << "- Select D";
}
res.push_back(ReadSingleCAIteration(iterNode, Iteration()));
}
}
}
}
}
if (res.size() == 0) {
auto currentNode = fMainConfigNode["core"]["track_finder"]["iteration_sequence"];
assert(currentNode);
assert(currentNode.size());
for (const auto& iterNode : currentNode) {
std::string thisIterName = iterNode.as<std::string>();
if (mPossibleIterations.find(thisIterName) == mPossibleIterations.end()) {
std::stringstream msg;
msg << "Unknow iteration in the iteration sequence, defined in main config file: " << thisIterName;
throw std::runtime_error(std::move(msg.str()));
}
res.push_back(mPossibleIterations.at(thisIterName));
}
}
return res;
}
// ---------------------------------------------------------------------------------------------------------------------
//
std::vector<std::set<int>> ConfigReader::ReadInactiveStationMap()
{
// Check, if the "skip_stations" branch exists either in the user config or in the main config
std::string sNodePath = "ca/core/common/inactive_stations";
auto node = GetNode([](YAML::Node n) { return n["core"]["common"]["inactive_stations"]; }, true);
if (!node) {
return std::vector<std::set<int>>{};
}
// Fill map of inactive stations
std::vector<std::set<int>> vGeoIdToTrackingStatus(constants::size::MaxNdetectors);
if (node && node.size()) {
std::unordered_map<std::string, int> mDetNameToID;
for (int iDet = 0; iDet < constants::size::MaxNdetectors; ++iDet) {
auto detName = boost::algorithm::to_lower_copy(fpInitManager->GetDetectorName(static_cast<EDetectorID>(iDet)));
if (!detName.size()) {
continue;
}
mDetNameToID[detName] = iDet;
}
for (const auto& item : node) {
std::string stName = item.as<std::string>();
if (!stName.size()) {
continue;
}
//
// Check name for spaces
if (std::any_of(stName.begin(), stName.end(), [](auto c) { return c == ' ' || c == '\t' || c == '\n'; })) {
std::stringstream msg;
msg << "Illegal station name in the configuration branch \"" << sNodePath << "\": \"" << stName
<< "\" contains illegal characters";
throw std::runtime_error(msg.str());
}
//
// Split stName into a detector name and a station number
std::vector<std::string> vNames;
boost::algorithm::split(vNames, stName, boost::is_any_of(":"));
if (vNames.size() > 2) {
std::stringstream msg;
msg << "Illegal station name in the configuration branch \"" << sNodePath << "\": \"" << stName
<< "\" contains more then one colon character";
throw std::runtime_error(msg.str());
}
//
// Parse detector name
const auto& detName = boost::algorithm::to_lower_copy(vNames.front());
auto it = mDetNameToID.find(detName);
if (it == mDetNameToID.end()) {
std::stringstream msg;
msg << "ConfigReader: legal but undefined name of the detector \"" << detName << "\" (originally \"" << stName
<< "\") was passed to the " << sNodePath << " config "
<< "branch";
throw std::runtime_error(msg.str());
}
int nStations = fpInitManager->GetNstationsGeometry(static_cast<EDetectorID>(it->second));
if (vNames.size() == 2) { // Disable one particular station
try {
int iStLoc = std::stoi(vNames.back());
if (iStLoc < 0 || iStLoc >= nStations) {
throw std::runtime_error("illegal local station index");
}
vGeoIdToTrackingStatus[it->second].insert(iStLoc);
}
catch (const std::exception&) {
std::stringstream msg;
msg << "Illegal station name in the configuration branch \"" << sNodePath << "\": \"" << stName
<< "\" contains expression after the colon symbol, which cannot be translated "
<< "to a local number of station";
throw std::runtime_error(msg.str());
}
}
else { // Disable all stations for this detector
for (int iStLoc = 0; iStLoc < nStations; ++iStLoc) {
vGeoIdToTrackingStatus[it->second].insert(iStLoc);
}
}
}
std::stringstream msg;
msg << "\033[1;31m ConfigReader: the next tracking stations will be disabled from the configuration file:\n";
for (int iDet = 0; iDet < static_cast<int>(mDetNameToID.size()); ++iDet) {
const auto& detName = fpInitManager->GetDetectorName(static_cast<EDetectorID>(iDet));
int nStations = fpInitManager->GetNstationsGeometry(static_cast<EDetectorID>(iDet));
for (int iStLoc = 0; iStLoc < nStations; ++iStLoc) {
if (vGeoIdToTrackingStatus[iDet].find(iStLoc) != vGeoIdToTrackingStatus[iDet].end()) {
msg << "\t- " << detName << iStLoc << '\n';
}
}
}
msg << "\033[0m";
LOG(warn) << msg.str();
}
return vGeoIdToTrackingStatus;
}
// ---------------------------------------------------------------------------------------------------------------------
//
void ConfigReader::ReadMisalignmentTolerance()
{
// Check, if the "misalignment_tolerance" branch exists either in the user config or in the main config
std::string sNodePath = "ca/core/common/misalignment_tolerance";
YAML::Node node(YAML::NodeType::Undefined);
try {
node = this->GetNode([](YAML::Node n) { return n["core"]["common"]["misalignment_tolerance"]; });
}
catch (const std::exception&) {
}
if (!node) {
std::stringstream msg;
msg << "Ca ConfigReader: misalignment_tolerance node was not found\n ";
if (fUserConfigNode) {
msg << " either in the user config (path: " << fsUserConfigPath;
msg << " or ";
}
else {
msg << " ";
}
msg << "in the main config (path: " << fsMainConfigPath << ")";
LOG(info) << msg.str();
LOG(info) << "Ca ConfigReader: run with zero misalignment tolerance";
return;
}
std::unordered_map<std::string, int> mDetNameToID;
for (int iDet = 0; iDet < constants::size::MaxNdetectors; ++iDet) {
auto detName = boost::algorithm::to_lower_copy(fpInitManager->GetDetectorName(static_cast<EDetectorID>(iDet)));
if (!detName.empty()) {
mDetNameToID[detName] = iDet;
}
}
for (const auto& item : node) {
std::string stName = boost::algorithm::to_lower_copy(item.first.as<std::string>());
auto it = mDetNameToID.find(stName);
if (it == mDetNameToID.end()) {
std::stringstream msg;
msg << "Illegal station name in the configuration branch \"" << sNodePath << "\": \"" << stName << "\"";
throw std::runtime_error(msg.str());
}
int iDetSystem = it->second;
auto v = item.second.as<std::vector<double>>();
if (v.size() != 3) {
std::stringstream msg;
msg << "Illegal number of misalignbment tolerances in configuration branch \"" << sNodePath << "\": \"" << stName
<< "\": " << v.size() << " values were passed, while 3 values are expected";
throw std::runtime_error(msg.str());
}
fpInitManager->SetMisalignmentTolerance(static_cast<EDetectorID>(iDetSystem), v[0], v[1], v[2]);
}
}
// ---------------------------------------------------------------------------------------------------------------------
//
Iteration ConfigReader::ReadSingleCAIteration(const YAML::Node& node, const Iteration& defaultIter) const
{
auto iter = Iteration();
try {
iter.SetName(node["name"].as<std::string>());
iter.SetTrackChi2Cut(node["track_chi2_cut"].as<float>(defaultIter.GetTrackChi2Cut()));
iter.SetTripletChi2Cut(node["triplet_chi2_cut"].as<float>(defaultIter.GetTripletChi2Cut()));
iter.SetTripletFinalChi2Cut(node["triplet_final_chi2_cut"].as<float>(defaultIter.GetTripletFinalChi2Cut()));
iter.SetDoubletChi2Cut(node["doublet_chi2_cut"].as<float>(defaultIter.GetDoubletChi2Cut()));
iter.SetPickGather(node["pick_gather"].as<float>(defaultIter.GetPickGather()));
iter.SetTripletLinkChi2(node["triplet_link_chi2"].as<float>(defaultIter.GetTripletLinkChi2()));
iter.SetMaxQp(node["max_qp"].as<float>(defaultIter.GetMaxQp()));
iter.SetMaxSlopePV(node["max_slope_pv"].as<float>(defaultIter.GetMaxSlopePV()));
iter.SetMaxSlope(node["max_slope"].as<float>(defaultIter.GetMaxSlope()));
iter.SetMaxDZ(node["max_dz"].as<float>(defaultIter.GetMaxDZ()));
iter.SetTargetPosSigmaXY(node["target_pos_sigma_x"].as<float>(defaultIter.GetTargetPosSigmaX()),
node["target_pos_sigma_y"].as<float>(defaultIter.GetTargetPosSigmaY()));
iter.SetFirstStationIndex(node["first_station_index"].as<int>(defaultIter.GetFirstStationIndex()));
iter.SetPrimaryFlag(node["is_primary"].as<bool>(defaultIter.GetPrimaryFlag()));
iter.SetElectronFlag(node["is_electron"].as<bool>(defaultIter.GetElectronFlag()));
iter.SetTrackFromTripletsFlag(node["is_track_from_triplets"].as<bool>(defaultIter.GetTrackFromTripletsFlag()));
iter.SetExtendTracksFlag(node["is_extend_tracks"].as<bool>(defaultIter.GetExtendTracksFlag()));
iter.SetMaxStationGap(node["max_station_gap"].as<int>(defaultIter.GetMaxStationGap()));
iter.SetMinNhits(node["min_n_hits"].as<int>(defaultIter.GetMinNhits()));
iter.SetMinNhitsStation0(node["min_n_hits_station_0"].as<int>(defaultIter.GetMinNhitsStation0()));
}
catch (const YAML::InvalidNode& exc) {
const auto nodeKeys = this->GetNodeKeys(node);
const auto nodeKeysStr =
std::accumulate(nodeKeys.cbegin(), nodeKeys.cend(), std::string(""),
[](std::string lhs, std::string rhs) { return std::move(lhs) + "\n\t" + std::move(rhs); });
LOG(fatal) << "L1 config: attempt to access key which does not exist in the configuration file (message from "
<< "YAML exception: " << exc.what() << "). Defined keys: " << nodeKeysStr;
}
return iter;
}
// ---------------------------------------------------------------------------------------------------------------------
//
void ConfigReader::SetMainConfigPath(const std::string& path)
{
if (path.size()) {
try {
fsMainConfigPath = path;
fMainConfigNode = YAML::LoadFile(fsMainConfigPath)["ca"];
if (fVerbose >= 1) {
LOG(info) << "ConfigReader: Registering main configuraiton file: \"\033[1;32m" << path << "\033[0m\"";
}
}
catch (const std::exception& err) {
LOG(error) << "ERROR: " << err.what();
}
}
}
// ---------------------------------------------------------------------------------------------------------------------
//
void ConfigReader::SetUserConfigPath(const std::string& path)
{
if (path.size()) {
try {
fsUserConfigPath = path;
fUserConfigNode = YAML::LoadFile(fsUserConfigPath)["ca"];
if (fVerbose >= 1) {
LOG(info) << "ConfigReader: Registering user configuraiton file: \"\033[1;32m" << path << "\033[0m\"";
}
}
catch (const std::exception& err) {
LOG(error) << "ERROR: " << err.what();
}
}
}
/* Copyright (C) 2022-2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
/// \file CaConfigReader.h
/// \brief Configuration parameter file reader for the CA tracking algorithm (header)
/// \author S.Zharko <s.zharko@gsi.de>
/// \since 18.07.2022
#pragma once // include this header only once per compilation unit
#include "CaIteration.h"
#include <functional>
#include <string>
#include <unordered_map>
#include <vector>
#include <yaml-cpp/yaml.h>
namespace YAML
{
class Node;
}
namespace cbm::algo::ca
{
class InitManager;
enum class DetectorID;
/// \class cbm::algo::ca::ConfigReader
/// \brief A reader for the CA parameters from the YAML configuration files
///
/// TODO: Describe configuration procedure here... (main config, user config etc...)
///
class ConfigReader {
public:
/// \brief Constructor
/// \param pInitManager Pointer to the L1InitManager instance
ConfigReader(InitManager* pInitManager, int verbose = 1);
/// \brief Destructor
~ConfigReader() = default;
/// \brief Reads configuration from files
void Read();
/// \brief Reads CA track finder iterations from YAML node
/// \return A vector of iterations
std::vector<Iteration> ReadCAIterationVector();
/// \brief Sets main config file
/// \param path Path to the file
void SetMainConfigPath(const std::string& path);
/// \brief Sets user config file
/// \param path Path to user config file
void SetUserConfigPath(const std::string& path);
/// \brief Sets verbosity level
void SetVerbosity(int verbose) { fVerbose = verbose; }
/// \brief Gets verbosity level
int GetVerbosity() const { return fVerbose; }
/// \brief Gets geometry lock status
bool GetGeometryLock() const { return fbGeometryLock; }
/// \brief Sets geometry lock status
void SetGeometryLock(bool lock) { fbGeometryLock = lock; }
private:
/// \brief Reads inactive tracking station map
/// \return A vector of sets of disabled station local indexes vs. the the detector index
std::vector<std::set<int>> ReadInactiveStationMap();
/// \brief Reads the misalignment tolerance
void ReadMisalignmentTolerance();
/// \brief Accesses a node either from user config or from main config
/// \param fn A function, which returns a YAML::Node reference object
/// \param optional true: node is not mandatory
/// \note If the node is not found in both configs
/// \throw std::runtime_error, if the path does not exist in the config
///
/// This function is to be used, if the desired node should exist either in main or in user config. Firstly,
/// the user config is checked, if it is provided. If the node is not found in user config, the main config
/// is checked. If the node does not exist in the main config as well, an exception will be thrown.
YAML::Node GetNode(std::function<YAML::Node(YAML::Node)> fn, bool optional = false) const;
/// \brief Reads iteration from config file
/// \param node YAML node containing an iteration
/// \param defaultIter Default iteration
/// \return A CA-iteration object
Iteration ReadSingleCAIteration(const YAML::Node& node, const Iteration& defaultIter) const;
/// \brief Gets parameters content of the node
/// \param node YAML node
/// \return Vector of key names
std::vector<std::string> GetNodeKeys(const YAML::Node& node) const;
InitManager* fpInitManager = nullptr; ///< Pointer to the L1InitManager instance
int fVerbose = 1; ///< Verbosity level
std::string fsMainConfigPath = ""; ///< Path to the main config file (mandatory)
std::string fsUserConfigPath = ""; ///< Path to the user config file (optional)
YAML::Node fMainConfigNode{YAML::NodeType::Undefined}; ///< Main configuration node
YAML::Node fUserConfigNode{YAML::NodeType::Undefined}; ///< User configuration node
bool fbMainConfigInitialized = false; ///< Main configuration file is initialized (e.g. via parameters obj)
bool fbGeometryLock = false; ///< Geometry initialization locked
};
} // namespace cbm::algo::ca