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
/* Copyright (C) 2022-2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergey Gorbunov, Sergei Zharko [committer] */
/// \file CaDefs.h
/// \brief Compile-time constants definition for the CA tracking algorithm
/// \since 02.06.2022
/// \author S.Zharko <s.zharko@gsi.de>
#pragma once // include this header only once per compilation unit
#include "CaSimd.h"
#include "KfFramework.h"
#include "KfTrackParam.h"
#include <limits>
namespace cbm::algo::ca
{
using cbm::algo::kf::TrackParam;
using cbm::algo::kf::TrackParamV;
} // namespace cbm::algo::ca
/// Namespace contains compile-time constants definition for the CA tracking algorithm
///
namespace cbm::algo::ca::constants
{
/// Array sizes
namespace size
{
/// Order of polynomial to approximate field in the vicinity of station plane
constexpr int MaxFieldApproxPolynomialOrder{5};
/// Amount of coefficients in field approximations
constexpr int MaxNFieldApproxCoefficients{(MaxFieldApproxPolynomialOrder + 1) * (MaxFieldApproxPolynomialOrder + 2)
/ 2};
/// Amount of bits to code a station or triplet. This values determine the maximum number of stations and triplets
constexpr unsigned int StationBits = 6u; ///< Amount of bits to code one station
constexpr unsigned int TripletBits = 32u - StationBits; ///< Amount of bits to code one triplet
constexpr int MaxNdetectors = 5; ///< Max number of tracking detectors
constexpr int MaxNstations = 1u << StationBits; ///< Max number of stations, 2^6 = 64
constexpr int MaxNtriplets = 1u << TripletBits; ///< Max number of triplets, 2^26 = 67,108,864
constexpr uint8_t DetBits = 4u; ///< Maximum 16 detector systems
/// Max number of track groups
/// NOTE: For a "track group" definition see CaParameters.h, GetSearchWindow function
constexpr int MaxNtrackGroups = 4;
} // namespace size
/// Control flags
namespace control
{
/// \brief Flag: input data QA level
/// - 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
/// \warning other options than 0 do not work properly, more tests are needed!
constexpr int InputDataQaLevel = 0;
} // namespace control
/// Physics constants
namespace phys
{
/// Particle masses etc used for the track fit, double precision
constexpr double MuonMassD = 0.105658375523; ///< Muon mass [GeV/c2]
constexpr double PionMassD = 0.1395703918; ///< Pion mass [GeV/c2]
constexpr double KaonMassD = 0.493677f; ///< Kaon mass [GeV/c2] (PDG 22.08.2023)
constexpr double ElectronMassD = 0.0005109989500015; ///< Electron mass [GeV/c2]
constexpr double ProtonMassD = 0.93827208816; ///< Proton mass [GeV/c2] (PDG 11.08.2022)
constexpr double SpeedOfLightD = 29.9792458; ///< Speed of light [cm/ns]
constexpr double SpeedOfLightInvD = 1. / SpeedOfLightD; ///< Inverse speed of light [ns/cm]
/// Particle masses etc used for the track fit, fscal precision
constexpr fscal MuonMass = MuonMassD; ///< Muon mass [GeV/c2]
constexpr fscal PionMass = PionMassD; ///< Pion mass [GeV/c2]
constexpr fscal KaonMass = KaonMassD; ///< Kaon mass [GeV/c2] (PDG 22.08.2023)
constexpr fscal ElectronMass = ElectronMassD; ///< Electron mass [GeV/c2]
constexpr fscal ProtonMass = ProtonMassD; ///< Proton mass [GeV/c2] (PDG 11.08.2022)
constexpr fscal SpeedOfLight = SpeedOfLightD; ///< Speed of light [cm/ns]
constexpr fscal SpeedOfLightInv = SpeedOfLightInvD; ///< Inverse speed of light [ns/cm]
} // namespace phys
/// Math constants
namespace math
{
constexpr double Pi = 3.14159265358979323846; ///< Value of PI, used in ROOT TMath
} // namespace math
/// Miscellaneous constants
namespace misc
{
constexpr int AssertionLevel = 0; ///< Assertion level
constexpr int Alignment = 16; ///< Default alignment of data (bytes)
constexpr fscal NegligibleFieldkG = 1.e-4; ///< Negligible field [kG]
} // namespace misc
/// \brief Undefined values
template<typename T1, typename T2 = T1>
constexpr T2 Undef;
template<>
inline constexpr int Undef<int> = std::numeric_limits<int>::min();
template<>
inline constexpr unsigned Undef<unsigned> = std::numeric_limits<unsigned>::max();
template<>
inline constexpr float Undef<float> = std::numeric_limits<float>::signaling_NaN();
template<>
inline constexpr double Undef<double> = std::numeric_limits<double>::signaling_NaN();
template<>
inline constexpr fscal Undef<fvec> = std::numeric_limits<fscal>::signaling_NaN();
/// Colors of terminal log messages
namespace clrs
{
// NOTE: To be used first, because different users may have different console bg and fg colors
constexpr char CL[] = "\e[0m"; ///< clear
constexpr char CLb[] = "\e[1m"; ///< clear bold
constexpr char CLi[] = "\e[3m"; ///< clear italic
constexpr char CLu[] = "\e[4m"; ///< clear underline
constexpr char CLr[] = "\e[7m"; ///< clear reverse
constexpr char CLbi[] = "\e[1;3m"; ///< clear bold-italic
constexpr char CLbu[] = "\e[1;4m"; ///< clear bold-underline
constexpr char CLbr[] = "\e[1;7m"; ///< clear bold-reverse
// regular
constexpr char BK[] = "\e[30m"; ///< normal black
constexpr char RD[] = "\e[31m"; ///< normal red
constexpr char GN[] = "\e[32m"; ///< normal green
constexpr char YL[] = "\e[33m"; ///< normal yellow
constexpr char BL[] = "\e[34m"; ///< normal blue
constexpr char MG[] = "\e[35m"; ///< normal magenta
constexpr char CY[] = "\e[36m"; ///< normal cyan
constexpr char GY[] = "\e[37m"; ///< normal grey
constexpr char WT[] = "\e[38m"; ///< normal white
// bold
constexpr char BKb[] = "\e[1;30m"; ///< bold black
constexpr char RDb[] = "\e[1;31m"; ///< bold red
constexpr char GNb[] = "\e[1;32m"; ///< bold green
constexpr char YLb[] = "\e[1;33m"; ///< bold yellow
constexpr char BLb[] = "\e[1;34m"; ///< bold blue
constexpr char MGb[] = "\e[1;35m"; ///< bold magenta
constexpr char CYb[] = "\e[1;36m"; ///< bold cyan
constexpr char GYb[] = "\e[1;37m"; ///< bold grey
constexpr char WTb[] = "\e[1;38m"; ///< bold white
// italic
constexpr char BKi[] = "\e[3;30m"; ///< italic black
constexpr char RDi[] = "\e[3;31m"; ///< italic red
constexpr char GNi[] = "\e[3;32m"; ///< italic green
constexpr char YLi[] = "\e[3;33m"; ///< italic yellow
constexpr char BLi[] = "\e[3;34m"; ///< italic blue
constexpr char MGi[] = "\e[3;35m"; ///< italic magenta
constexpr char CYi[] = "\e[3;36m"; ///< italic cyan
constexpr char GYi[] = "\e[3;37m"; ///< italic grey
constexpr char WTi[] = "\e[3;38m"; ///< italic white
// underline
constexpr char BKu[] = "\e[4;30m"; ///< underline black
constexpr char RDu[] = "\e[4;31m"; ///< underline red
constexpr char GNu[] = "\e[4;32m"; ///< underline green
constexpr char YLu[] = "\e[4;33m"; ///< underline yellow
constexpr char BLu[] = "\e[4;34m"; ///< underline blue
constexpr char MGu[] = "\e[4;35m"; ///< underline magenta
constexpr char CYu[] = "\e[4;36m"; ///< underline cyan
constexpr char GYu[] = "\e[4;37m"; ///< underline grey
constexpr char WTu[] = "\e[4;38m"; ///< underline white
// reverse
constexpr char BKr[] = "\e[7;30m"; ///< reverse black
constexpr char RDr[] = "\e[7;31m"; ///< reverse red
constexpr char GNr[] = "\e[7;32m"; ///< reverse green
constexpr char YLr[] = "\e[7;33m"; ///< reverse yellow
constexpr char BLr[] = "\e[7;34m"; ///< reverse blue
constexpr char MGr[] = "\e[7;35m"; ///< reverse magenta
constexpr char CYr[] = "\e[7;36m"; ///< reverse cyan
constexpr char GYr[] = "\e[7;37m"; ///< reverse grey
constexpr char WTr[] = "\e[7;38m"; ///< reverse white
// bold-underline
constexpr char BKbu[] = "\e[1;4;30m"; ///< bold-underline black
constexpr char RDbu[] = "\e[1;4;31m"; ///< bold-underline red
constexpr char GNbu[] = "\e[1;4;32m"; ///< bold-underline green
constexpr char YLbu[] = "\e[1;4;33m"; ///< bold-underline yellow
constexpr char BLbu[] = "\e[1;4;34m"; ///< bold-underline blue
constexpr char MGbu[] = "\e[1;4;35m"; ///< bold-underline magenta
constexpr char CYbu[] = "\e[1;4;36m"; ///< bold-underline cyan
constexpr char GYbu[] = "\e[1;4;37m"; ///< bold-underline grey
constexpr char WTbu[] = "\e[1;4;38m"; ///< bold-underline white
// bold-italic
constexpr char BKbi[] = "\e[1;3;30m"; ///< bold-italic black
constexpr char RDbi[] = "\e[1;3;31m"; ///< bold-italic red
constexpr char GNbi[] = "\e[1;3;32m"; ///< bold-italic green
constexpr char YLbi[] = "\e[1;3;33m"; ///< bold-italic yellow
constexpr char BLbi[] = "\e[1;3;34m"; ///< bold-italic blue
constexpr char MGbi[] = "\e[1;3;35m"; ///< bold-italic magenta
constexpr char CYbi[] = "\e[1;3;36m"; ///< bold-italic cyan
constexpr char GYbi[] = "\e[1;3;37m"; ///< bold-italic grey
constexpr char WTbi[] = "\e[1;3;38m"; ///< bold-italic white
// bold-reverse
constexpr char BKbr[] = "\e[1;7;30m"; ///< bold-reverse black
constexpr char RDbr[] = "\e[1;7;31m"; ///< bold-reverse red
constexpr char GNbr[] = "\e[1;7;32m"; ///< bold-reverse green
constexpr char YLbr[] = "\e[1;7;33m"; ///< bold-reverse yellow
constexpr char BLbr[] = "\e[1;7;34m"; ///< bold-reverse blue
constexpr char MGbr[] = "\e[1;7;35m"; ///< bold-reverse magenta
constexpr char CYbr[] = "\e[1;7;36m"; ///< bold-reverse cyan
constexpr char GYbr[] = "\e[1;7;37m"; ///< bold-reverse grey
constexpr char WTbr[] = "\e[1;7;38m"; ///< bold-reverse white
} // namespace clrs
} // namespace cbm::algo::ca::constants
/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergey Gorbunov, Sergei Zharko [committer] */
/// \file CaInitManager.cxx
/// \brief Input data management class for the CA tracking algorithm (implementation)
/// \since 19.01.2022
/// \author Sergei Zharko <s.zharko@gsi.de>
#include "CaInitManager.h"
#include "CaConfigReader.h"
#include "KfSetupBuilder.h"
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <algorithm>
#include <fstream>
#include <sstream>
namespace cbm::algo::ca
{
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::AddStation(const StationInitializer& inStation) { fvStationInfo.push_back(inStation); }
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::AddStations(const Parameters<fvec>& par)
{
const auto& stations = par.GetStations();
for (int iSt = 0; iSt < par.GetNstationsActive(); ++iSt) {
auto stationIn = Station<double>(stations[iSt]);
// Get detector ID of the station
auto [detId, locId] = par.GetStationIndexLocal(par.GetActiveToGeoMap()[iSt]);
auto stationInfo = ca::StationInitializer(detId, locId);
stationInfo.SetStationType(stationIn.type);
stationInfo.SetZmin(0.); // NOTE: Deprecated (not used)
stationInfo.SetZmax(0.); // NOTE: Deprecated (not used)
stationInfo.SetZref(stationIn.fZ);
stationInfo.SetXmax(stationIn.Xmax);
stationInfo.SetYmax(stationIn.Ymax);
stationInfo.SetFieldStatus(stationIn.fieldStatus);
stationInfo.SetTimeInfo(stationIn.timeInfo);
stationInfo.SetTrackingStatus(true);
this->AddStation(stationInfo);
}
}
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::CheckInit()
{
this->CheckCAIterationsInit();
this->CheckStationsInfoInit();
fbConfigIsRead = false;
fbGeometryConfigLock = false;
}
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::ClearSetupInfo()
{
// Clear stations set and a thickness map
fvStationInfo.clear();
fInitController.SetFlag(EInitKey::kStationsInfo, false);
// Set number of stations do default values
this->ClearStationLayout();
// Clear field info
fParameters.fVertexFieldRegion = kf::FieldRegion<fvec>();
fParameters.fVertexFieldValue = kf::FieldValue<fvec>();
fInitController.SetFlag(EInitKey::kPrimaryVertexField, false);
// Clear target position
fParameters.fTargetPos.fill(Undef<float>);
fTargetZ = 0.;
fInitController.SetFlag(EInitKey::kTargetPos, false);
// Clear field function
fFieldFunction = FieldFunction_t([](const double(&)[3], double(&)[3]) {});
fInitController.SetFlag(EInitKey::kFieldFunction, false);
// Clear other flags
fParameters.fRandomSeed = 1;
fParameters.fGhostSuppression = 0;
fInitController.SetFlag(EInitKey::kRandomSeed, false);
fInitController.SetFlag(EInitKey::kGhostSuppression, false);
fParameters.fMisalignmentX.fill(0.);
fParameters.fMisalignmentY.fill(0.);
fParameters.fMisalignmentT.fill(0.);
fParameters.fDevIsIgnoreHitSearchAreas = false;
fParameters.fDevIsUseOfOriginalField = false;
fParameters.fDevIsMatchDoubletsViaMc = false;
fParameters.fDevIsMatchTripletsViaMc = false;
fParameters.fDevIsExtendTracksViaMc = false;
fParameters.fDevIsSuppressOverlapHitsViaMc = false;
fParameters.fDevIsParSearchWUsed = false;
fbGeometryConfigLock = false;
}
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::ClearCAIterations()
{
fParameters.fCAIterations.clear();
fCAIterationsNumberCrosscheck = -1;
fInitController.SetFlag(EInitKey::kCAIterations, false);
fInitController.SetFlag(EInitKey::kCAIterationsNumberCrosscheck, false);
}
// --------------------------------------------------------------------------------------------------------------------
// NOTE: this function should be called once in the SendParameters
bool InitManager::FormParametersContainer()
{
// Read configuration files
this->ReadInputConfigs();
if (!fbConfigIsRead) { // Check config reading status
return false;
}
if (!fParameters.fDevIsParSearchWUsed) {
fInitController.SetFlag(EInitKey::kSearchWindows, true);
}
// Apply magnetic field to the station info objects
std::for_each(fvStationInfo.begin(), fvStationInfo.end(), [&](auto& st) { st.SetFieldFunction(fFieldFunction); });
// Check initialization
this->CheckInit();
if (!fInitController.IsFinalized()) {
LOG(error) << "ca::InitManager: Attempt to form parameters container before all necessary fields were initialized"
<< fInitController.ToString();
return false;
}
{ // Form array of stations
auto destIt = fParameters.fStations.begin();
for (const auto& station : fvStationInfo) {
if (!station.GetTrackingStatus()) {
continue;
}
*destIt = station.GetStation();
++destIt;
}
}
// Check the consistency of the parameters object. If object inconsistent, it throws std::logic_error
try {
fParameters.CheckConsistency();
}
catch (const std::logic_error& err) {
LOG(error) << "ca::InitManager: parameters container consistency check failed. Reason: " << err.what();
return false;
}
return true;
}
// --------------------------------------------------------------------------------------------------------------------
//
int InitManager::GetNstationsActive() const
{
if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) {
std::stringstream msg;
msg << "ca::InitManager: number of active stations cannot be accessed until the station layout is initialized";
throw std::runtime_error(msg.str());
}
return fParameters.GetNstationsActive();
}
// --------------------------------------------------------------------------------------------------------------------
//
int InitManager::GetNstationsActive(EDetectorID detectorID) const
{
if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) {
std::stringstream msg;
msg << "ca::InitManager: number of active stations cannot be accessed until the station layout is initialized";
throw std::runtime_error(msg.str());
}
return fParameters.GetNstationsActive(detectorID);
}
// --------------------------------------------------------------------------------------------------------------------
//
int InitManager::GetNstationsGeometry() const
{
if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) {
std::stringstream msg;
msg << "ca::InitManager: number of geometry stations cannot be accessed until the station layout is initialized";
throw std::runtime_error(msg.str());
}
return fParameters.GetNstationsGeometry();
}
// --------------------------------------------------------------------------------------------------------------------
//
int InitManager::GetNstationsGeometry(EDetectorID detectorID) const
{
if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) {
std::stringstream msg;
msg << "ca::InitManager: number of geometry stations cannot be accessed until the station layout is initialized";
throw std::runtime_error(msg.str());
}
return fParameters.GetNstationsGeometry(detectorID);
}
// --------------------------------------------------------------------------------------------------------------------
//
std::vector<StationInitializer>& InitManager::GetStationInfo()
{
if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) {
std::stringstream msg;
msg << "ca::InitManager: station info container cannot be accessed until the station layout is initialized";
throw std::runtime_error(msg.str());
}
return fvStationInfo;
}
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::InitStationLayout()
{
LOG(info) << "ca::InitManager::InitStationLayout(): ....";
this->ClearStationLayout();
std::sort(fvStationInfo.begin(), fvStationInfo.end());
for (const auto& aStation : fvStationInfo) {
++fParameters.fvFirstGeoId[static_cast<int>(aStation.GetDetectorID()) + 1];
}
for (int iDet = 1; iDet < static_cast<int>(fParameters.fvFirstGeoId.size()) - 1; ++iDet) {
fParameters.fvFirstGeoId[iDet + 1] += fParameters.fvFirstGeoId[iDet];
}
fParameters.fNstationsActiveTotal = 0;
for (int iStGeo = 0; iStGeo < static_cast<int>(fvStationInfo.size()); ++iStGeo) {
const auto& aStation = fvStationInfo[iStGeo];
int iDet = static_cast<int>(aStation.GetDetectorID());
int iStLocal = aStation.GetStationID();
// Fill local -> geo map
fParameters.fvGeoToLocalIdMap[iStGeo] = std::make_pair(aStation.GetDetectorID(), iStLocal);
// Fill geo -> local map
fParameters.fvLocalToGeoIdMap[fParameters.fvFirstGeoId[iDet] + iStLocal] = iStGeo;
// Fill geo <-> active map
int iStActive = aStation.GetTrackingStatus() ? fParameters.fNstationsActiveTotal++ : -1;
fParameters.fvGeoToActiveMap[iStGeo] = iStActive;
if (iStActive > -1) {
fParameters.fvActiveToGeoMap[iStActive] = iStGeo;
}
}
fInitController.SetFlag(EInitKey::kStationLayoutInitialized, true);
for (auto& aStation : fvStationInfo) {
aStation.SetGeoLayerID(fParameters.GetStationIndexGeometry(aStation.GetStationID(), aStation.GetDetectorID()));
}
}
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::InitTargetField(double zStep)
{
if (fInitController.GetFlag(EInitKey::kPrimaryVertexField)) {
LOG(warn) << "ca::InitManager::InitTargetField: attempt to reinitialize the field value and field region "
<< "near target. Ignore";
return;
}
// Check for field function
if (!fInitController.GetFlag(EInitKey::kFieldFunction)) {
std::stringstream msg;
msg << "Attempt to initialize the field value and field region near target before initializing field function";
throw std::runtime_error(msg.str());
}
// Check for target defined
if (!fInitController.GetFlag(EInitKey::kTargetPos)) {
std::stringstream msg;
msg << "Attempt to initialize the field value and field region near target before the target position"
<< "initialization";
throw std::runtime_error(msg.str());
}
constexpr int nDimensions{3};
constexpr int nPointsNodal{3};
std::array<double, nPointsNodal> inputNodalZ{fTargetZ, fTargetZ + zStep, fTargetZ + 2. * zStep};
std::array<kf::FieldValue<fvec>, nPointsNodal> B{};
std::array<fvec, nPointsNodal> z{};
// loop over nodal points
for (int idx = 0; idx < nPointsNodal; ++idx) {
double point[nDimensions]{0., 0., inputNodalZ[idx]};
double field[nDimensions]{};
fFieldFunction(point, field);
z[idx] = inputNodalZ[idx];
B[idx].Set(field[0], field[1], field[2]);
} // loop over nodal points: end
fParameters.fVertexFieldRegion.Set(B[0], z[0], B[1], z[1], B[2], z[2]);
fParameters.fVertexFieldValue = B[0];
fInitController.SetFlag(EInitKey::kPrimaryVertexField);
}
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::PushBackCAIteration(const Iteration& iteration)
{
// TODO: probably some checks must be inserted here (S.Zharko)
if (!fInitController.GetFlag(EInitKey::kCAIterationsNumberCrosscheck)) {
std::stringstream msg;
msg << "Attempt to push back a CA track finder iteration before the number of iterations was defined";
throw std::runtime_error(msg.str());
}
fParameters.fCAIterations.push_back(iteration);
}
// -------------------------------------------------------------------------------------------------------------------
//
void InitManager::ReadInputConfigs()
{
if (!fbConfigIsRead) {
LOG(info) << "ca::InitManager: reading parameter configuration ...";
try {
auto configReader = ConfigReader(this, 4);
configReader.SetMainConfigPath(fsConfigInputMain);
configReader.SetUserConfigPath(fsConfigInputUser);
configReader.SetGeometryLock(fbGeometryConfigLock);
configReader.Read();
fbConfigIsRead = true;
LOG(info) << "ca::InitManager: reading parameter configuration ... \033[1;32mdone\033[0m";
}
catch (const std::runtime_error& err) {
LOG(error) << "ca::InitManager: reading parameter configuration ... \033[1;31mfail\033[0m. Reason: "
<< err.what();
}
}
}
// -------------------------------------------------------------------------------------------------------------------
//
void InitManager::ReadGeometrySetup(const std::string& fileName)
{
// Open input binary file
this->SetGeometrySetup(cbm::algo::kf::SetupBuilder::Load<fvec>(fileName));
}
// -------------------------------------------------------------------------------------------------------------------
//
void InitManager::ReadParametersObject(const std::string& fileName)
{
using namespace constants;
// clrs::CL - end colored log
// clrs::GNb - bold green log
// clrs::RDb - bold red log
// Open input binary file
std::ifstream ifs(fileName, std::ios::binary);
if (!ifs) {
std::stringstream msg;
msg << "ca::InitManager: parameters data file \"" << clrs::GNb << fileName << clrs::CL << "\" was not found";
throw std::runtime_error(msg.str());
}
// Get L1InputData object
try {
boost::archive::binary_iarchive ia(ifs);
ia >> fParameters;
fbGeometryConfigLock = true;
}
catch (const std::exception&) {
std::stringstream msg;
msg << "ca::InitManager: parameters file \"" << clrs::GNb << fileName << clrs::CL
<< "\" has incorrect data format or was corrupted";
throw std::runtime_error(msg.str());
}
fInitController.SetFlag(EInitKey::kStationLayoutInitialized, true);
fInitController.SetFlag(EInitKey::kPrimaryVertexField, true);
fInitController.SetFlag(EInitKey::kSearchWindows, true);
}
// -------------------------------------------------------------------------------------------------------------------
//
void InitManager::ReadSearchWindows(const std::string& fileName)
{
// Open input binary file
std::ifstream ifs(fileName);
if (!ifs) {
std::stringstream msg;
msg << "ca::InitManager: search window file \"" << fileName << "\" was not found";
throw std::runtime_error(msg.str());
}
try {
boost::archive::text_iarchive ia(ifs);
int nPars = -1;
int nWindows = -1;
ia >> nPars;
assert(nPars == 1); // Currently only the constant windows are available
ia >> nWindows;
std::stringstream errMsg;
for (int iW = 0; iW < nWindows; ++iW) {
SearchWindow swBuffer;
ia >> swBuffer;
int iStationID = swBuffer.GetStationID();
int iTrackGrID = swBuffer.GetTrackGroupID();
if (iStationID < 0 || iStationID > constants::size::MaxNstations) {
errMsg << "\t- wrong station id for entry " << iW << ": " << iStationID << " (should be between 0 and "
<< constants::size::MaxNstations << ")\n";
}
if (iTrackGrID < 0 || iTrackGrID > constants::size::MaxNtrackGroups) {
errMsg << "\t- wrong track group id for entry " << iW << ": " << iTrackGrID << " (should be between 0 and "
<< constants::size::MaxNtrackGroups << ")\n";
}
fParameters.fSearchWindows[iTrackGrID * constants::size::MaxNstations + iStationID] = swBuffer;
}
if (errMsg.str().size()) {
std::stringstream msg;
msg << "ca::InitManager: some errors occurred while reading search windows: " << errMsg.str();
throw std::runtime_error(msg.str());
}
}
catch (const std::exception& err) {
std::stringstream msg;
msg << "search windows file \"" << fileName << "\" has incorrect data format or was corrupted. ";
msg << "Exception catched: " << err.what();
throw std::runtime_error(msg.str());
}
fInitController.SetFlag(EInitKey::kSearchWindows, true);
}
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::SetCAIterationsNumberCrosscheck(int nIterations)
{
fCAIterationsNumberCrosscheck = nIterations;
auto& iterationsContainer = fParameters.fCAIterations;
// NOTE: should be called to prevent multiple copies of objects between the memory reallocations
iterationsContainer.reserve(nIterations);
fInitController.SetFlag(EInitKey::kCAIterationsNumberCrosscheck);
}
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::SetFieldFunction(const FieldFunction_t& fieldFunction)
{
if (!fInitController.GetFlag(EInitKey::kFieldFunction)) {
fFieldFunction = fieldFunction;
fInitController.SetFlag(EInitKey::kFieldFunction);
}
else {
LOG(warn) << "ca::InitManager::SetFieldFunction: attempt to reinitialize the field function. Ignored";
}
}
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::SetGhostSuppression(int ghostSuppression)
{
if (fInitController.GetFlag(EInitKey::kGhostSuppression)) {
LOG(warn)
<< "ca::InitManager::SetGhostSuppression: attempt of reinitializating the ghost suppresion flag. Ignore";
return;
}
fParameters.fGhostSuppression = ghostSuppression;
fInitController.SetFlag(EInitKey::kGhostSuppression);
}
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::SetRandomSeed(unsigned int seed)
{
if (fInitController.GetFlag(EInitKey::kRandomSeed)) {
LOG(warn) << "ca::InitManager::SetRandomSeed: attempt of reinitializating the random seed. Ignore";
return;
}
fParameters.fRandomSeed = seed;
fInitController.SetFlag(EInitKey::kRandomSeed);
}
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::SetTargetPosition(double x, double y, double z)
{
if (fInitController.GetFlag(EInitKey::kTargetPos)) {
LOG(warn) << "ca::InitManager::SetTargetPosition: attempt to reinitialize the target position. Ignore";
return;
}
/// Fill fvec target fields
fParameters.fTargetPos[0] = x;
fParameters.fTargetPos[1] = y;
fParameters.fTargetPos[2] = z;
/// Set additional field for z component in double precision
fTargetZ = z;
fInitController.SetFlag(EInitKey::kTargetPos);
}
// --------------------------------------------------------------------------------------------------------------------
//
Parameters<fvec>&& InitManager::TakeParameters() { return std::move(fParameters); }
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::WriteParametersObject(const std::string& fileName) const
{
using constants::clrs::CL;
using constants::clrs::GNb;
// Open output binary file
std::ofstream ofs(fileName, std::ios::binary);
if (!ofs) {
std::stringstream msg;
msg << "ca::InitManager: failed opening file \"" << GNb << fileName << CL << "\" to write parameters object";
throw std::runtime_error(msg.str());
}
LOG(info) << "ca::InitManager: writing CA parameters object to file \"" << GNb << fileName << '\"' << CL;
// Serialize L1Parameters object and write
boost::archive::binary_oarchive oa(ofs);
oa << fParameters;
}
// --------------------------------------------------------------------------------------------------------------------
//
void InitManager::CheckCAIterationsInit()
{
bool ifInitPassed = true;
if (!fInitController.GetFlag(EInitKey::kCAIterations)) {
int nIterationsActual = fParameters.fCAIterations.size();
int nIterationsExpected = fCAIterationsNumberCrosscheck;
if (nIterationsActual != nIterationsExpected) {
LOG(warn) << "ca::InitManager::CheckCAIterations: incorrect number of iterations registered: "
<< nIterationsActual << " of " << nIterationsExpected << " expected";
ifInitPassed = false;
}
}
fInitController.SetFlag(EInitKey::kCAIterations, ifInitPassed);
}
// --------------------------------------------------------------------------------------------------------------------
// TODO: REWRITE! and add const qualifier (S.Zharko)
void InitManager::CheckStationsInfoInit()
{
bool ifInitPassed = true;
if (!fInitController.GetFlag(EInitKey::kStationsInfo)) {
// (1) Check the stations themselves
bool bStationsFinalized = std::all_of(fvStationInfo.begin(), fvStationInfo.end(),
[](const auto& st) { return st.GetInitController().IsFinalized(); });
if (!bStationsFinalized) {
std::stringstream msg;
msg << "ca::InitManager: At least one of the StationInitializer objects is not finalized";
}
// (2) Check for maximum allowed number of stations
if (fParameters.GetNstationsGeometry() > constants::size::MaxNstations) {
std::stringstream msg;
msg << "Actual total number of registered stations in geometry (" << fParameters.GetNstationsGeometry()
<< ") is larger then possible (" << constants::size::MaxNstations
<< "). Please, select another set of active tracking detectors or recompile the code with enlarged"
<< " constants::size::MaxNstations value";
throw std::runtime_error(msg.str());
}
}
fInitController.SetFlag(EInitKey::kStationsInfo, ifInitPassed);
}
// -------------------------------------------------------------------------------------------------------------------
//
void InitManager::ClearStationLayout()
{
fParameters.fvFirstGeoId.fill(0);
fParameters.fvLocalToGeoIdMap.fill(0);
fParameters.fvGeoToLocalIdMap.fill(std::make_pair(static_cast<EDetectorID>(0), -1));
fParameters.fvGeoToActiveMap.fill(-1); // Note: by default all the stations are inactive
fParameters.fvActiveToGeoMap.fill(0);
fParameters.fNstationsActiveTotal = -1;
fInitController.SetFlag(EInitKey::kStationLayoutInitialized, false);
}
} // namespace cbm::algo::ca
/* Copyright (C) 2021-2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergey Gorbunov, Sergei Zharko [committer] */
/// \file CaInitManager.h
/// \brief Input data management class for the CA tracking algorithm (header)
/// \since 24.12.2021
/// \author Sergei Zharko <s.zharko@gsi.de>
#pragma once // include this header only once per compilation unit
#include "CaDefs.h"
#include "CaIteration.h"
#include "CaObjectInitController.h"
#include "CaParameters.h"
#include "CaSimd.h"
#include "CaStationInitializer.h"
#include "KfFieldRegion.h"
#include <array>
#include <bitset>
#include <memory> //unique_ptr
#include <numeric>
#include <set>
#include <string>
#include <type_traits>
#include <unordered_map>
namespace cbm::algo::ca
{
/// \enum cbm::algo::ca::EDetectorID
/// \brief Forward declaration of the tracking detectors scoped enumeration
///
/// Concrete realization of this enumeration must be determined in the concrete setup class (i.e. CbmL1)
enum class EDetectorID;
} // namespace cbm::algo::ca
/// \brief Hash function definition for EDetectorID
template<>
struct std::hash<cbm::algo::ca::EDetectorID> {
int operator()(cbm::algo::ca::EDetectorID t) const { return static_cast<int>(t); }
};
namespace cbm::algo::ca
{
/// \brief Underlying integer type for the DetectorID
using DetectorID_t = std::underlying_type_t<EDetectorID>;
/// \class cbm::algo::ca::InitManager
/// \brief A CA Parameters object initialization class
///
/// This class provides an interface to form a solid Parameters object, which is used by the CA algorithm and
/// the related routines. The initialization can be performed either from the detector-specific interfaces or by
/// reading the already prepared binary wile with extention ca.par TODO:.... continue
///
class InitManager {
private:
/// \brief Init-controller key set
enum class EInitKey
{
// NOTE: Please, keep the numbers of the enumeration items in the existing order: it helps to debug the
// initialization with this->GetObjectInitController().ToString() method call (S.Zharko)
kFieldFunction, ///< 0) If magnetic field getter function is set
kTargetPos, ///< 1) If target position was defined
kPrimaryVertexField, ///< 2) If magnetic field value and region defined at primary vertex
kStationsInfo, ///< 3) If all the planned stations were added to the manager
kCAIterationsNumberCrosscheck, ///< 4) If the number of CA track finder is initialized
kCAIterations, ///< 5) If the CA track finder iterations were initialized
kSearchWindows, ///< 6) If the hit search windows were initialized
kGhostSuppression, ///< 7)
kRandomSeed, ///< 8) If the random seed is provided
kStationLayoutInitialized, ///< 9) If stations layout is initialized
kSetupInitialized, ///< 10) If KF-setup initialized
kEnd ///< 11) [technical] number of entries in the enumeration
};
using DetectorIDIntMap_t = std::unordered_map<EDetectorID, int>;
using DetectorIDSet_t = std::set<EDetectorID>;
using FieldFunction_t = std::function<void(const double (&xyz)[3], double (&B)[3])>;
using InitController_t = ObjectInitController<static_cast<int>(EInitKey::kEnd), EInitKey>;
template<typename T>
using DetectorIDArr_t = std::array<T, constants::size::MaxNdetectors>;
public:
/// \brief Default constructor
InitManager() = default;
/// \brief Destructor
~InitManager() = default;
/// \brief Copy constructor is forbidden
InitManager(const InitManager& /*other*/) = delete;
/// \brief Move constructor is forbidden
InitManager(InitManager&& /*other*/) = delete;
/// \brief Copy assignment operator is forbidden
InitManager& operator=(const InitManager& /*other*/) = delete;
/// \brief Move assignment operator is forbidden
InitManager& operator=(InitManager&& /*other*/) = delete;
/// \brief Adds a tracking station to the geometry
///
/// \note The added station stays uninitialized until the Parameters object is formed
void AddStation(const StationInitializer& station);
/// \brief Adds tracking stations from the parameters file
/// \param par A valid instance of parameters, created for ACTIVE + INACTIVE tracking stations
///
// TODO: Probably, we have to remove stations from the parameters and place them into a class ca::Geometery
// together with instances of active and geometry kf::Setup. ca::Parameters should contain only tracking
// parameters, which should be fully defined from the config. Search windows should be stored as an
// independent object, which depends on the ca::Parameters(iterations) and ca::Geometry(active station
// layout).
void AddStations(const Parameters<fvec>& par);
/// \brief Provides final checks of the parameters object
void CheckInit();
/// \brief Clears vector of CA track finder iterations
void ClearCAIterations();
/// \brief Clears vector of base setup
void ClearSetupInfo();
/// \brief Forms parameters container
/// \return Success flag: true - the container is formed, false - error while forming the container occured
bool FormParametersContainer();
/// \brief Gets name of the detector
/// \param detId Index of the detector
/// \return Name of the detector
const std::string& GetDetectorName(EDetectorID detId) const { return fvDetectorNames[static_cast<int>(detId)]; }
/// \brief Gets ghost suppression flag
int GetGhostSuppression() const { return fParameters.fGhostSuppression; }
/// \brief Gets a name of the main input configuration file
const std::string& GetInputConfigMain() const { return fsConfigInputMain; }
/// \brief Gets a name of the user input configuration file
const std::string& GetInputConfigUser() const { return fsConfigInputMain; }
/// \brief Gets a const reference to ca::ObjectInitController
const InitController_t& GetInitController() const { return fInitController; }
/// \brief Gets total number of active stations
int GetNstationsActive() const;
/// \brief Gets number of active stations for given detector ID
int GetNstationsActive(EDetectorID detectorID) const;
/// \brief Gets total number of stations, provided by setup geometry
int GetNstationsGeometry() const;
/// \brief Gets number of stations, provided by setup geometry for given detector ID
int GetNstationsGeometry(EDetectorID detectorID) const;
/// \brief Gets a name of the output configuration file
const std::string& GetOutputConfigName() const { return fConfigOutputName; }
/// \brief Gets a reference to the stations array
std::vector<StationInitializer>& GetStationInfo();
/// \brief Initializes station layout
///
/// This function is to be called after all the tracking stations (StationInitializer objects) are added to the
/// InitManager instance. After the initialization the vector of the tracking stations is sorted by z-positions
/// and is available for modifications.
void InitStationLayout();
/// \brief Calculates kf::FieldValue and L1FieldReference values for a selected step in z-axis from the target position
/// \param zStep step between nodal points
void InitTargetField(double zStep);
/// \brief Checks, if the detector is active
bool IsActive(EDetectorID detectorID) const { return GetNstationsActive(detectorID) != 0; }
/// \brief Checks, if the detector is present in the geometry
bool IsPresent(EDetectorID detectorID) const { return GetNstationsGeometry(detectorID) != 0; }
/// \brief Pushes an CA track finder iteration into a sequence of iteration using reference
void PushBackCAIteration(const Iteration& iteration);
/// \brief Pushes an CA track finder iteration into a sequence of iteration using raw pointer
void PushBackCAIteration(const Iteration* pIteration) { PushBackCAIteration(*pIteration); }
/// \brief Pushes an CA track finder iteration into a sequence of iteration using std::unique_ptr
void PushBackCAIteration(const std::unique_ptr<Iteration>& puIteration) { PushBackCAIteration(*puIteration); }
/// \brief Reads main and user parameters configs
void ReadInputConfigs();
/// \brief Reads geometry setup from file
/// \param fileName Name of input file
void ReadGeometrySetup(const std::string& fileName);
/// \brief Reads parameters object from boost-serialized binary file
/// \param fileName Name of input file
void ReadParametersObject(const std::string& fileName);
/// \brief Reads search windows from file
/// \param fileName Name of input file
void ReadSearchWindows(const std::string& fileName);
/// \brief Sets a number of CA track finder iterations to provide initialization cross-check
// TODO: remove this method
void SetCAIterationsNumberCrosscheck(int nIterations);
/// \brief Sets base configuration file
/// \param mainConfig Path to main configuration file
/// \note The base configuraiton file is mandatory until the tracking configuration is initialized from
/// beforehand created Parameters file.
void SetConfigMain(const std::string& mainConfig) { fsConfigInputMain = mainConfig; }
/// \brief Sets user configuration file
/// \param userConfig Path to user configuration file
/// \note The user configuraiton file is optional
void SetConfigUser(const std::string& userConfig) { fsConfigInputUser = userConfig; }
/// \brief Sets detector names
/// \param container Container of the detector names
template<size_t Size>
void SetDetectorNames(const std::array<const char*, Size>& container)
{
static_assert(Size <= constants::size::MaxNdetectors,
"Please, be ensured that the constants::size::MaxNdetectors is not lower then the "
"EDetectorID::kEND value, provided by your setup");
std::copy(container.begin(), container.end(), fvDetectorNames.begin());
}
/// Sets a magnetic field function, which will be applied for all the stations
void SetFieldFunction(const FieldFunction_t& fieldFcn);
/// \brief Sets the flag to enable/disable the ghost suppression routine
void SetGhostSuppression(int ghostSuppression);
/// \brief Sets a name of the output configuration file
/// \param filename Name of the output CA parameters configuration
///
/// The output file is created from the fields, saved in the resulted Parameters object.
void SetOutputConfigName(const std::string& filename) { fConfigOutputName = filename; }
/// \brief Sets pseudo-random numbers generator seed
/// \param seed Seed value
/// \note The default seed is 1
void SetRandomSeed(unsigned int seed);
// TODO: Use kf::Setup instead
/// \brief Sets target position
/// \param x Position X component [cm]
/// \param y Position Y component [cm]
/// \param z Position Z component [cm]
void SetTargetPosition(double x, double y, double z);
/// \brief Sets upper-bound cut on max number of doublets per one singlet
void SetMaxDoubletsPerSinglet(unsigned int value) { fParameters.fMaxDoubletsPerSinglet = value; }
/// \brief Sets upper-bound cut on max number of triplets per one doublet
void SetMaxTripletPerDoublets(unsigned int value) { fParameters.fMaxTripletPerDoublets = value; }
/// \brief Sets setup
/// \tparam Underlying type of the setup
template<typename DataT>
void SetGeometrySetup(const cbm::algo::kf::Setup<DataT>& setup)
{
if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) {
std::stringstream msg;
msg << "ca::InitManager: setup cannot be set until the station layout is initialized";
throw std::runtime_error(msg.str());
}
fParameters.fGeometrySetup = kf::Setup<fvec>(setup);
fParameters.fActiveSetup = fParameters.fGeometrySetup;
// A sequence of the last inactive materials will be anyway thrown away, so it is more effective to
// loop over stations downstream
for (int iStGeo = setup.GetNofLayers() - 1; iStGeo >= 0; --iStGeo) {
auto [detID, locID] = fParameters.GetStationIndexLocal(iStGeo);
int iStActive = fParameters.GetStationIndexActive(locID, detID);
if (iStActive < 0) {
fParameters.fActiveSetup.DisableLayer(detID, locID);
}
}
LOG(info) << "Geometry setup:" << fParameters.fGeometrySetup.ToString(1);
LOG(info) << "Active setup:" << fParameters.fActiveSetup.ToString(1);
fInitController.SetFlag(EInitKey::kSetupInitialized, true);
}
/// \brief Sets misalignment parameters in X direction
/// \param detectorId Index of the detector system
/// \param x Misalignment tolerance in x [cm]
/// \param y Misalignment tolerance in y [cm]
/// \param t Misalignment tolerance in t [ns]
void SetMisalignmentTolerance(EDetectorID detectorId, double x, double y, double t)
{
fParameters.fMisalignmentX[static_cast<int>(detectorId)] = x;
fParameters.fMisalignmentY[static_cast<int>(detectorId)] = y;
fParameters.fMisalignmentT[static_cast<int>(detectorId)] = t;
}
/// \brief Sets default fitter mass
/// \param mass Particle mass [GeV/c2]
void SetDefaultMass(double mass) { fParameters.fDefaultMass = mass; }
/// \brief Takes parameters object from the init-manager instance
/// \return A parameter object
Parameters<fvec>&& TakeParameters();
/// \brief Writes parameters object from boost-serialized binary file
/// \param fileName Name of input file
void WriteParametersObject(const std::string& fileName) const;
// ***************************
// ** Flags for development **
// ***************************
/// \brief Ignore hit search areas
void DevSetIgnoreHitSearchAreas(bool value = true) { fParameters.fDevIsIgnoreHitSearchAreas = value; }
/// \brief Force use of the original field (not approximated)
void DevSetUseOfOriginalField(bool value = true) { fParameters.fDevIsUseOfOriginalField = value; }
/// \brief Flag to match doublets using MC information
void DevSetIsMatchDoubletsViaMc(bool value = true) { fParameters.fDevIsMatchDoubletsViaMc = value; }
/// \brief Flag to match triplets using Mc information
void DevSetIsMatchTripletsViaMc(bool value = true) { fParameters.fDevIsMatchTripletsViaMc = value; }
/// \brief Flag to match triplets using Mc information
void DevSetIsExtendTracksViaMc(bool value = true) { fParameters.fDevIsExtendTracksViaMc = value; }
/// \brief Flag to match triplets using Mc information
void DevSetIsSuppressOverlapHitsViaMc(bool value = true) { fParameters.fDevIsSuppressOverlapHitsViaMc = value; }
/// \brief Flag to use estimated hit search windows
/// \param true estimated search windows will be used in track finder
/// \param false the Kalman filter is be used in track finder
void DevSetIsParSearchWUsed(bool value = true) { fParameters.fDevIsParSearchWUsed = value; }
private:
/// \brief Checker for Iteration container initialization (sets EInitKey::kCAIterations)
/// \return true If all Iteration objects were initialized properly
void CheckCAIterationsInit();
/// \brief Checker for StationInitializer set initialization (sets EInitKey::kStationsInfo)
/// \return true If all StationInitializer objects were initialized properly. Similar effect can be achieved by
void CheckStationsInfoInit();
/// \brief Returns station layout into undefined condition
void ClearStationLayout();
InitController_t fInitController{}; ///< Initialization flags
DetectorIDArr_t<std::string> fvDetectorNames{}; ///< Names of the detectors
double fTargetZ{0.}; ///< Target position z component in double precision
std::vector<StationInitializer> fvStationInfo{}; ///< Vector of StationInitializer objects (active + inactive)
/// A function which returns magnetic field vector B in a radius-vector xyz
FieldFunction_t fFieldFunction{[](const double (&)[3], double (&)[3]) {}};
// NOTE: Stations of the detectors which are not assigned as active, are not included in the tracking!
// TODO: remove
int fCAIterationsNumberCrosscheck{-1}; ///< Number of iterations to be passed (must be used for cross-checks)
Parameters<fvec> fParameters{}; ///< CA parameters object
// TODO: With a separate KF-framework instance we need to figure it out, how to store and read the corresponding
// parameters (essential for the online reconstruction!!!)
std::string fsConfigInputMain = ""; ///< name for the input configuration file
std::string fsConfigInputUser = ""; ///< name for the input configuration file
std::string fConfigOutputName = ""; ///< name for the output configuration file
bool fbConfigIsRead = false; ///< Flag, if configuration file was read
bool fbGeometryConfigLock = false; ///< Lock geometry initialization
};
} // 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 L1CAIteration.cxx
/// \brief Definition of the L1CAIteration class methods
/// \since 05.02.2022
/// \author S.Zharko <s.zharko@gsi.de>
#include "CaIteration.h"
#include "CaDefs.h"
#include <limits>
#include <sstream>
#include <string_view>
using cbm::algo::ca::Iteration;
using cbm::algo::ca::Vector;
// ---------------------------------------------------------------------------------------------------------------------
//
Iteration::Iteration(const std::string& name) : fName(name) {}
// ---------------------------------------------------------------------------------------------------------------------
//
bool Iteration::Check() const
{
using constants::size::MaxNstations;
constexpr float kMaxFloat = std::numeric_limits<float>::max();
bool res = true;
auto CheckValueLimits = [&](std::string_view name, auto value, auto min, auto max) -> bool {
if (value > max || value < min) {
LOG(info) << "cbm::algo::ca::Iteration: parameter " << name << " = " << value << " runs out of range " << min
<< ", " << max;
return false;
}
return true;
};
// TODO: SZh 06.10.2022: These values should be tuned. At the moment the std::numeric_limits<T>::max value is used for
// debug purposes. In future, these values will be strengthened.
res = CheckValueLimits("track_chi2_cut", fTrackChi2Cut, 0.f, kMaxFloat) && res;
res = CheckValueLimits("triplet_chi2_cut", fTripletChi2Cut, 0.f, kMaxFloat) && res;
res = CheckValueLimits("triplet_final_chi2_cut", fTripletFinalChi2Cut, 0.f, kMaxFloat) && res;
res = CheckValueLimits("doublet_chi2_cut", fDoubletChi2Cut, 0.f, kMaxFloat) && res;
res = CheckValueLimits("pick_gather", fPickGather, 0.f, kMaxFloat) && res;
res = CheckValueLimits("triplet_link_chi2", fTripletLinkChi2, 0.f, kMaxFloat) && res;
res = CheckValueLimits("max_qp", fMaxQp, 0.001f, kMaxFloat) && res;
res = CheckValueLimits("max_slope_pv", fMaxSlopePV, 0.f, kMaxFloat) && res;
res = CheckValueLimits("max_slope", fMaxSlope, 0.f, kMaxFloat) && res;
res = CheckValueLimits("max_dz", fMaxDZ, 0.f, kMaxFloat) && res;
res = CheckValueLimits("min_n_hits", fMinNhits, 3, MaxNstations) && res;
res = CheckValueLimits("min_n_hits_sta_0", fMinNhitsStation0, 3, MaxNstations) && res;
res = CheckValueLimits("first_station_index", fFirstStationIndex, 0, MaxNstations) && res;
res = CheckValueLimits("target_pos_sigma_x", fTargetPosSigmaX, 0.f, kMaxFloat) && res;
res = CheckValueLimits("target_pos_sigma_y", fTargetPosSigmaY, 0.f, kMaxFloat) && res;
return res;
}
// ---------------------------------------------------------------------------------------------------------------------
//
void Iteration::SetTargetPosSigmaXY(float sigmaX, float sigmaY)
{
fTargetPosSigmaX = sigmaX;
fTargetPosSigmaY = sigmaY;
}
// ---------------------------------------------------------------------------------------------------------------------
//
std::string Iteration::ToString(int) const
{
std::vector<Iteration> vIter{*this};
return Iteration::ToTableFromVector(vIter);
}
// ---------------------------------------------------------------------------------------------------------------------
//
std::string Iteration::ToTableFromVector(const Vector<Iteration>& vIterations)
{
std::stringstream msg;
msg << std::boolalpha;
auto PutRow = [&](const std::string& name, std::function<void(const Iteration&)> fn) {
msg << std::setw(40) << std::setfill(' ') << name << ' ';
for (const auto& iter : vIterations) {
msg << std::setw(12) << std::setfill(' ');
fn(iter);
msg << ' ';
}
msg << '\n';
};
PutRow(" ", [&](const Iteration& i) { msg << i.GetName(); });
PutRow("Is primary ", [&](const Iteration& i) { msg << i.GetPrimaryFlag(); });
PutRow("Is electron ", [&](const Iteration& i) { msg << i.GetElectronFlag(); });
PutRow("If tracks created from triplets ", [&](const Iteration& i) { msg << i.GetTrackFromTripletsFlag(); });
PutRow("If tracks extended with unused hits", [&](const Iteration& i) { msg << i.GetExtendTracksFlag(); });
PutRow("Triplets can jump over <=n stations", [&](const Iteration& i) { msg << i.GetMaxStationGap(); });
PutRow("Min number of hits ", [&](const Iteration& i) { msg << i.GetMinNhits(); });
PutRow("Min number of hits on station 0 ", [&](const Iteration& i) { msg << i.GetMinNhitsStation0(); });
PutRow("Track chi2 cut ", [&](const Iteration& i) { msg << i.GetTrackChi2Cut(); });
PutRow("Triplet chi2 cut ", [&](const Iteration& i) { msg << i.GetTripletChi2Cut(); });
PutRow("Triplet final chi2 cut ", [&](const Iteration& i) { msg << i.GetTripletFinalChi2Cut(); });
PutRow("Doublet chi2 cut ", [&](const Iteration& i) { msg << i.GetDoubletChi2Cut(); });
PutRow("Pick gather ", [&](const Iteration& i) { msg << i.GetPickGather(); });
PutRow("Triplet link chi2 ", [&](const Iteration& i) { msg << i.GetTripletLinkChi2(); });
PutRow("Max q/p ", [&](const Iteration& i) { msg << i.GetMaxQp(); });
PutRow("Max slope ", [&](const Iteration& i) { msg << i.GetMaxSlope(); });
PutRow("Max slope at primary vertex ", [&](const Iteration& i) { msg << i.GetMaxSlopePV(); });
PutRow("Max DZ ", [&](const Iteration& i) { msg << i.GetMaxDZ(); });
PutRow("Target position sigma X [cm] ", [&](const Iteration& i) { msg << i.GetTargetPosSigmaX(); });
PutRow("Target position sigma Y [cm] ", [&](const Iteration& i) { msg << i.GetTargetPosSigmaY(); });
PutRow("First tracking station index ", [&](const Iteration& i) { msg << i.GetFirstStationIndex(); });
return msg.str();
}
/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergey Gorbunov, Sergei Zharko [committer] */
/***************************************************************************************************
* @file L1CAIteration.h
* @brief Declaration of the L1CAIteration class
* @since 05.02.2022
* @author S.Zharko <s.zharko@gsi.de>
***************************************************************************************************/
#pragma once // include this header only once per compilation unit
#include "CaVector.h"
#include <boost/serialization/access.hpp>
#include <boost/serialization/string.hpp>
#include <bitset>
#include <iomanip>
#include <string>
namespace cbm::algo::ca
{
/// \class cbm::algo::ca::Iteration
/// \brief A set of parameters for the CA Track finder iteration
///
/// Each iteration utilizes special physics cuts and run condition to find tracks of a particular
/// class (e.g., fast primary tracks or secondary electron tracks). Hits associated with tracks
/// reconstructed during current iteration are removed from the further iterations.
class Iteration {
public:
/// \brief Default constructor
Iteration() = default;
/// \brief Copy constructor
Iteration(const Iteration& other) = default;
/// \brief Copy constructor
Iteration(const Iteration& other, const std::string& name) : Iteration(other) { SetName(name); }
/// \brief Move constructor
Iteration(Iteration&& other) noexcept = default;
/// \brief Constructor from L1CAIteration type
Iteration(const std::string& name);
/// \brief Destructor
~Iteration() noexcept = default;
/// \brief Copy assignment operator
Iteration& operator=(const Iteration& other) = default;
/// \brief Move assignment operator
Iteration& operator=(Iteration&& other) = default;
/// \brief Checks parameters consistency
bool Check() const;
/// \brief Gets doublet chi2 upper cut
float GetDoubletChi2Cut() const { return fDoubletChi2Cut; }
/// \brief flag check: electrons/positrons - true, heavy charged - false
bool GetElectronFlag() const { return fIsElectron; }
/// \brief Sets flag: true - extends track candidates with unused hits
bool GetExtendTracksFlag() const { return fIsExtendTracks; }
/// \brief Gets station index of the first station used in tracking
int GetFirstStationIndex() const { return fFirstStationIndex; }
/// \brief Gets flag: true - triplets are also built with skipping <= GetMaxStationGap stations
int GetMaxStationGap() const { return fMaxStationGap; }
/// \brief Gets correction for accounting overlaping and iff z
float GetMaxDZ() const { return fMaxDZ; }
/// \brief Gets max considered q/p for tracks
float GetMaxQp() const { return fMaxQp; }
/// \brief Gets max slope (tx\ty) in 3D hit position of a triplet
float GetMaxSlope() const { return fMaxSlope; }
/// \brief Gets max slope (tx\ty) in primary vertex
float GetMaxSlopePV() const { return fMaxSlopePV; }
/// \brief Gets min n hits
int GetMinNhits() const { return fMinNhits; }
/// \brief Gets min n hits for tracks that start on station 0
int GetMinNhitsStation0() const { return fMinNhitsStation0; }
/// \brief Gets the name of the iteration
const std::string& GetName() const { return fName; }
/// \brief Gets size of region [TODO: units??] to attach new hits to the created track
float GetPickGather() const { return fPickGather; }
/// \brief Checks flag: true - only primary tracks are searched, false - [all or only secondary?]
bool GetPrimaryFlag() const { return fIsPrimary; }
/// \brief Gets sigma target position in X direction [cm]
float GetTargetPosSigmaX() const { return fTargetPosSigmaX; }
/// \brief Gets sigma target position in Y direction [cm]
float GetTargetPosSigmaY() const { return fTargetPosSigmaY; }
/// \brief Gets track chi2 upper cut
float GetTrackChi2Cut() const { return fTrackChi2Cut; }
/// (DEBUG!) Sets flag:
/// true:
/// all the triplets found on this iteration will be converted to tracks,
/// all the iterations following after this one will be rejected from the
/// iterations sequence;
/// false (default):
/// tracks are built from triplets, and the minimal amount of hits used in
/// each track equals four. In case of primary tracks the first measurement
/// is taken from the target, and the other three measurements are taken from
/// the triplet.
bool GetTrackFromTripletsFlag() const { return fIsTrackFromTriplets; }
/// \brief Gets triplet chi2 upper cut
float GetTripletChi2Cut() const { return fTripletChi2Cut; }
/// \brief Gets triplet chi2 upper cut
float GetTripletFinalChi2Cut() const { return fTripletFinalChi2Cut; }
/// \brief Gets min value of dp/dp_error, for which two tiplets are neighbours
float GetTripletLinkChi2() const { return fTripletLinkChi2; }
/// \brief Sets doublet chi2 upper cut
void SetDoubletChi2Cut(float input) { fDoubletChi2Cut = input; }
/// \brief Sets flag: electron tracks - true, heavy ion tracks - false
void SetElectronFlag(bool flag) { fIsElectron = flag; }
/// \brief Sets flag: true - extends track candidates with unused hits
void SetExtendTracksFlag(bool flag) { fIsExtendTracks = flag; }
/// \brief Sets index of first station used in tracking
void SetFirstStationIndex(int index) { fFirstStationIndex = index; }
/// \brief Sets flag: true - triplets are built also skipping <= GetMaxStationGap stations
void SetMaxStationGap(int nSkipped) { fMaxStationGap = nSkipped; }
/// \brief TODO: select a more proper name
void SetMaxDZ(float input) { fMaxDZ = input; }
/// \brief Sets max considered q/p for tracks
void SetMaxQp(float input) { fMaxQp = input; }
/// \brief Sets max slope (tx\ty) in 3D hit position of a triplet
void SetMaxSlope(float input) { fMaxSlope = input; }
/// \brief Sets max slope (tx\ty) in primary vertex
void SetMaxSlopePV(float input) { fMaxSlopePV = input; }
/// \brief Sets flag: true - skip track candidates with level = 0
void SetMinNhits(int val) { fMinNhits = val; }
/// \brief Sets min n hits for tracks that start on station 0
void SetMinNhitsStation0(int val) { fMinNhitsStation0 = val; }
/// \brief Sets name of the iteration
void SetName(const std::string& name) { fName = name; }
/// \brief Sets size of region [TODO: units??] to attach new hits to the created track
void SetPickGather(float input) { fPickGather = input; }
/// \brief Sets flag: primary tracks - true, secondary tracks - false
void SetPrimaryFlag(bool flag) { fIsPrimary = flag; }
/// \brief Sets sigma of target positions in XY plane
/// \param sigmaX Sigma value in X direction [cm]
/// \param sigmaX Sigma value in Y direction [cm]
void SetTargetPosSigmaXY(float sigmaX, float sigmaY);
/// \brief Sets track chi2 upper cut
void SetTrackChi2Cut(float input) { fTrackChi2Cut = input; }
/// \brief Sets flag:
/// true:
/// all the triplets found on this iteration will be converted to tracks,
/// all the iterations following after this one will be rejected from the
/// iterations sequence;
/// false (default):
/// tracks are built from triplets, and the minimal amount of hits used in
/// each track equals four. In case of primary tracks the first measurement
/// is taken from the target, and the other three measurements are taken from
/// the triplet.
void SetTrackFromTripletsFlag(bool flag) { fIsTrackFromTriplets = flag; }
/// \brief Sets triplet chi2 upper cut
void SetTripletChi2Cut(float input) { fTripletChi2Cut = input; }
/// \brief Sets triplet chi2 upper cut
void SetTripletFinalChi2Cut(float input) { fTripletFinalChi2Cut = input; }
/// \brief Sets min value of dp/dp_error, for which two tiplets are neighbours
void SetTripletLinkChi2(float input) { fTripletLinkChi2 = input; }
/// \brief String representation of the class contents
/// \param indentLevel Level of indentation for the text (in terms of \t symbols)
std::string ToString(int indentLevel = 0) const;
/// \brief Forms a string, representing a table of iterations from the vector of iterations
/// \param vIterations Vector of iterations
/// \return Iterations table represented with a string
static std::string ToTableFromVector(const Vector<Iteration>& vIterations);
private:
/** Basic fields **/
std::string fName{""}; ///< Iteration name
/** Track finder dependent cuts **/
// TODO: Iteratively change the literals to floats (S.Zharko)
// NOTE: For each new cut one should not forget to create a setter and a getter, insert the value
// initialization in the copy constructor and the Swap operator as well as a string repre-
// sentation to the ToString method (S.Zharko)
float fTrackChi2Cut = 10.f; ///< Track chi2 upper cut
float fTripletChi2Cut = 21.1075f; ///< Triplet chi2 upper cut
float fTripletFinalChi2Cut = 21.1075f; ///< Triplet chi2 upper cut
float fDoubletChi2Cut = 11.3449 * 2.f / 3.f; ///< Doublet chi2 upper cut
float fPickGather = 3.0; ///< Size of region to attach new hits to the created track
float fTripletLinkChi2 = 25.0; ///< Min value of dp^2/dp_error^2, for which two tiplets are neighbours
float fMaxQp = 1.0 / 0.5; ///< Max considered q/p for tracks
float fMaxSlopePV = 1.1; ///< Max slope (tx\ty) in primary vertex
float fMaxSlope = 2.748; ///< Max slope (tx\ty) in 3D hit position of a triplet
float fMaxDZ = 0.f; ///< Correction for accounting overlaping and iff z [cm]
float fTargetPosSigmaX = 0; ///< Constraint on target position in X direction [cm]
float fTargetPosSigmaY = 0; ///< Constraint on target position in Y direction [cm]
int fFirstStationIndex = 0; ///< First station, used for tracking
int fMinNhits = 3; ///< min n hits on the tracks
int fMinNhitsStation0 = 3; ///< min n hits for tracks that start on station 0
bool fIsPrimary = false; ///< Flag: true - only primary tracks are searched for
bool fIsElectron = false; ///< Flag: true - only electrons are searched for
bool fIsExtendTracks = false; ///< Flag: true - extends track candidates with unused hits
int fMaxStationGap = 0; ///< Flag: true - find triplets with fMaxStationGap missing stations
/// @brief Flag to select triplets on the iteration as tracks
/// In ordinary cases, the shortest track consists from four hits. For primary track the target is accounted as
/// the first hit, and the other three hits are taken from the stations. For secondary track all the hits are selected
/// from the stations only.
/// If the fIsTrackFromTriplets flag is turned on, all of the triplets found on this iterations will be considered
/// as tracks.
///
/// @note The only one iteration with the fIsTrackFromTriplets flag turned on can exist in the tracking iterations
/// sequence and this iteration should be the last in the tracking sequence.
bool fIsTrackFromTriplets = false;
/// Serialization method, used to save ca::Hit objects into binary or text file in a defined order
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned int /*version*/)
{
ar& fName;
ar& fTrackChi2Cut;
ar& fTripletChi2Cut;
ar& fTripletFinalChi2Cut;
ar& fDoubletChi2Cut;
ar& fPickGather;
ar& fTripletLinkChi2;
ar& fMaxQp;
ar& fMaxSlopePV;
ar& fMaxSlope;
ar& fMaxDZ;
ar& fTargetPosSigmaX;
ar& fTargetPosSigmaY;
ar& fFirstStationIndex;
ar& fMinNhits;
ar& fMinNhitsStation0;
ar& fIsPrimary;
ar& fIsElectron;
ar& fIsExtendTracks;
ar& fMaxStationGap;
ar& fIsTrackFromTriplets;
}
};
} // namespace cbm::algo::ca