CbmRoot
Loading...
Searching...
No Matches
CaConfigReader.cxx
Go to the documentation of this file.
1/* Copyright (C) 2022-2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Sergei Zharko [committer] */
4
9
10#include "CaConfigReader.h"
11
12#include "CaDefs.h"
13
14#include <boost/algorithm/string.hpp>
15
16#include <iostream>
17#include <numeric>
18#include <sstream>
19#include <unordered_map>
20
21#include <yaml-cpp/yaml.h>
22
27
28// ---------------------------------------------------------------------------------------------------------------------
29//
30ConfigReader::ConfigReader(int verbose) : fVerbose(verbose) {}
31
32// ---------------------------------------------------------------------------------------------------------------------
33//
34// TODO: switch to the Yaml library by Felix
35YAML::Node ConfigReader::GetNode(std::function<YAML::Node(YAML::Node)> fn, bool optional) const
36{
37 auto node = YAML::Node(YAML::NodeType::Undefined);
38 if (fUserConfigNode) {
39 node = fn(fUserConfigNode);
40 }
41 if (!node) {
42 node = fn(fMainConfigNode);
43 }
44 if (!node && !optional) {
45 std::stringstream msg;
46 msg << "requested node was not found ";
47 if (fUserConfigNode) {
48 msg << "either in user config (path: " << fsUserConfigPath << ") or ";
49 }
50 msg << "in main config (path: " << fsMainConfigPath << ")";
51 throw std::runtime_error(msg.str());
52 }
53 return node;
54}
55
56// ---------------------------------------------------------------------------------------------------------------------
57//
58std::vector<std::string> ConfigReader::GetNodeKeys(const YAML::Node& node) const
59{
60 std::vector<std::string> res;
61 res.reserve(node.size());
62 try {
63 for (const auto& item : node) {
64 res.push_back(item.first.as<std::string>());
65 }
66 }
67 catch (const YAML::InvalidNode& exc) {
68 LOG(warn)
69 << "L1 config: attempt to call ConfigReader::GetNodeKeys for node, keys of which could not be represented "
70 << "with strings. An empty vector will be returned";
71 std::vector<std::string>().swap(res);
72 }
73 return res;
74}
75
76// ---------------------------------------------------------------------------------------------------------------------
77//
78std::vector<Iteration> ConfigReader::ReadCAIterationVector() const
79{
80 std::vector<Iteration> res;
81
82 // Read iterations store
83 std::unordered_map<std::string, Iteration> mPossibleIterations;
84 {
85 auto currentNode = fMainConfigNode["possible_iterations"];
86 assert(currentNode);
87 for (const auto& iterNode : currentNode) {
88 std::string thisIterName = iterNode["name"].as<std::string>("");
89 std::string baseIterName = iterNode["base_iteration"].as<std::string>("");
90
91 if (baseIterName.size()) { // Create iteration from previously defined one
92 if (mPossibleIterations.find(baseIterName) == mPossibleIterations.end()) {
93 std::stringstream msg;
94 msg << "A CA iteration \"" << thisIterName << "\" requires a base iteration with name \"" << baseIterName
95 << "\", which was not registered yet. Please, place an entry with the requested base iteration above "
96 << "in the possible_iterations node";
97 throw std::runtime_error(std::move(msg.str()));
98 }
99 mPossibleIterations[thisIterName] = ReadSingleCAIteration(iterNode, mPossibleIterations.at(baseIterName));
100 }
101 else {
102 mPossibleIterations[thisIterName] = ReadSingleCAIteration(iterNode, Iteration());
103 }
104 }
105 }
106
107 // Read actual iteration sequence
108 //
109 if (fUserConfigNode) {
110 if (fVerbose >= 1) {
111 LOG(info) << "- Reading user iterations ";
112 }
113
114 auto currentNode = fUserConfigNode["core"]["track_finder"]["iterations"];
115 if (currentNode) {
116 for (const auto& iterNode : currentNode) {
117 std::string thisIterName = iterNode["name"].as<std::string>("");
118 std::string baseIterName = iterNode["base_iteration"].as<std::string>("");
119 if (fVerbose >= 2) {
120 LOG(info) << "- Reading user iteration " << thisIterName << "(" << baseIterName << ")";
121 }
122 if (mPossibleIterations.find(thisIterName) != mPossibleIterations.end()) {
123 // This is an update of existing possible iteration
124 res.push_back(ReadSingleCAIteration(iterNode, mPossibleIterations.at(thisIterName)));
125 }
126 else if (mPossibleIterations.find(baseIterName) != mPossibleIterations.end()) {
127 // This is a user iteration based on the existing possible iteration
128 res.push_back(ReadSingleCAIteration(iterNode, mPossibleIterations.at(baseIterName)));
129 }
130 else {
131 // Try to find a base iteration from user-defined
132 auto itFound = std::find_if(res.begin(), res.end(), [&](auto& i) { return i.GetName() == baseIterName; });
133 if (itFound != res.end()) {
134 res.push_back(ReadSingleCAIteration(iterNode, *itFound));
135 }
136 else {
137 res.push_back(ReadSingleCAIteration(iterNode, Iteration()));
138 }
139 }
140 }
141 }
142 }
143
144 if (res.size() == 0) {
145 auto currentNode = fMainConfigNode["core"]["track_finder"]["iteration_sequence"];
146 assert(currentNode);
147 assert(currentNode.size());
148 for (const auto& iterNode : currentNode) {
149 std::string thisIterName = iterNode.as<std::string>();
150 if (mPossibleIterations.find(thisIterName) == mPossibleIterations.end()) {
151 std::stringstream msg;
152 msg << "Unknow iteration in the iteration sequence, defined in main config file: " << thisIterName;
153 throw std::runtime_error(std::move(msg.str()));
154 }
155 res.push_back(mPossibleIterations.at(thisIterName));
156 }
157 }
158
159 return res;
160}
161
162// ---------------------------------------------------------------------------------------------------------------------
163//
164std::vector<std::pair<EDetectorID, int>> ConfigReader::ReadInactiveStationMap() const
165{
166 std::vector<std::pair<EDetectorID, int>> res;
167
168 // Check, if the "skip_stations" branch exists either in the user config or in the main config
169 std::string sNodePath = "ca/core/common/inactive_stations";
170 auto node = GetNode([](YAML::Node n) { return n["core"]["common"]["inactive_stations"]; }, true);
171 if (!node || node.size() == 0) {
172 return res;
173 }
174
175 // Fill map of inactive stations
176 res.reserve(node.size());
177 for (const auto& item : node) {
178 std::string nodeVal = item.as<std::string>();
179
180 // Check contents
181 if (nodeVal.empty()) {
182 continue;
183 }
184
185 // Check for spaces, tabs and new line characters
186 if (std::any_of(nodeVal.begin(), nodeVal.end(), [](auto c) { return c == ' ' || c == '\t' || c == '\n'; })) {
187 throw std::runtime_error(
188 fmt::format("Station name passed in YAML branch {} contains illegal characters: {}", sNodePath, nodeVal));
189 }
190
191 // Parse the {detId, locId} from the node value
192 std::vector<std::string> nodeValParts;
193 boost::algorithm::split(nodeValParts, nodeVal, boost::is_any_of(":"));
194 if (nodeValParts.size() > 2) {
195 throw std::runtime_error(
196 fmt::format("Station name passed in YAML branch {} contains to many colon characters (max 2 allowed): {}",
197 sNodePath, nodeVal));
198 }
199
200 //auto detIdOpt = cbm::util::FromString<EDetectorID>(nodeValParts[0]);
201
202 auto itDetName = fDetNameMap.find(boost::algorithm::to_lower_copy(nodeValParts[0]));
203 if (itDetName == fDetNameMap.end()) {
204 throw std::runtime_error(
205 fmt::format("Detector name {} passed in YAML branch {} is not supported by CA. Please ensure, that "
206 "the detector is registered in enum class EDetectorID",
207 nodeValParts[0], sNodePath));
208 }
209
210 EDetectorID detId = itDetName->second;
211 if (nodeValParts.size() == 1) {
212 res.emplace_back(detId, -1); // Disable all stations for this det. ID
213 continue;
214 }
215
216 int locId{-1}; // All stations for this detId will be disabled, if nodeValParts.size() != 2
217 // Try to parse the locId
218 try {
219 locId = std::stoi(nodeValParts[1]);
220 }
221 catch (const std::exception& err) {
222 throw std::runtime_error(fmt::format("Could not convert the {} to integral locId value (node {}, branch {})",
223 nodeValParts[1], nodeVal, sNodePath));
224 }
225
226 if (locId < -1) {
227 throw std::runtime_error(
228 fmt::format("Illegal station locId passed in the node {} in YAML branch {}. The possible values are: "
229 "-1 to disable all stations, non-negative integer to disable a single station",
230 locId, sNodePath));
231 }
232 res.emplace_back(detId, locId);
233 }
234 return res;
235}
236
237// ---------------------------------------------------------------------------------------------------------------------
238//
240{
242 std::string sNodePath = "ca/core/common/misalignment_tolerance";
243 auto node = GetNode([](YAML::Node n) { return n["core"]["common"]["misalignment_tolerance"]; }, true);
244 if (!node || node.size() == 0) {
245 return res;
246 }
247
248 for (const auto& item : node) {
249 std::string detName = boost::algorithm::to_lower_copy(item.first.as<std::string>());
250 auto it = fDetNameMap.find(detName);
251 if (it == fDetNameMap.end()) {
252 throw std::runtime_error(
253 fmt::format("Detector name {} passed in YAML branch {} is not supported by CA. Please ensure, that "
254 "the detector is registered in enum class EDetectorID",
255 item.first.as<std::string>(), sNodePath));
256 }
257
258 auto detId = it->second;
259 auto v = item.second.as<std::vector<float>>();
260 if (v.size() != 3) {
261 throw std::runtime_error(fmt::format("Illegal number of elements, provided to initialize misalignment "
262 "tolerances ({} != 3)",
263 v.size()));
264 }
265 res[static_cast<int>(detId)] = MisalignmentTolerance{v[0], v[1], v[2]};
266 }
267
268 return res;
269}
270
271// ---------------------------------------------------------------------------------------------------------------------
272//
273Iteration ConfigReader::ReadSingleCAIteration(const YAML::Node& node, const Iteration& defaultIter) const
274{
275 auto iter = Iteration();
276 try {
277 iter.SetName(node["name"].as<std::string>());
278 iter.SetTrackChi2Cut(node["track_chi2_cut"].as<float>(defaultIter.GetTrackChi2Cut()));
279 iter.SetTripletChi2Cut(node["triplet_chi2_cut"].as<float>(defaultIter.GetTripletChi2Cut()));
280 iter.SetTripletFinalChi2Cut(node["triplet_final_chi2_cut"].as<float>(defaultIter.GetTripletFinalChi2Cut()));
281 iter.SetDoubletChi2Cut(node["doublet_chi2_cut"].as<float>(defaultIter.GetDoubletChi2Cut()));
282 iter.SetPickGather(node["pick_gather"].as<float>(defaultIter.GetPickGather()));
283 iter.SetTripletLinkChi2(node["triplet_link_chi2"].as<float>(defaultIter.GetTripletLinkChi2()));
284 iter.SetMaxQp(node["max_qp"].as<float>(defaultIter.GetMaxQp()));
285 iter.SetMaxSlopePV(node["max_slope_pv"].as<float>(defaultIter.GetMaxSlopePV()));
286 iter.SetMaxSlope(node["max_slope"].as<float>(defaultIter.GetMaxSlope()));
287 iter.SetMaxDZ(node["max_dz"].as<float>(defaultIter.GetMaxDZ()));
288 iter.SetTargetPosSigmaXY(node["target_pos_sigma_x"].as<float>(defaultIter.GetTargetPosSigmaX()),
289 node["target_pos_sigma_y"].as<float>(defaultIter.GetTargetPosSigmaY()));
290 iter.SetFirstStationIndex(node["first_station_index"].as<int>(defaultIter.GetFirstStationIndex()));
291 iter.SetPrimaryFlag(node["is_primary"].as<bool>(defaultIter.GetPrimaryFlag()));
292 iter.SetElectronFlag(node["is_electron"].as<bool>(defaultIter.GetElectronFlag()));
293 iter.SetTrackFromTripletsFlag(node["is_track_from_triplets"].as<bool>(defaultIter.GetTrackFromTripletsFlag()));
294 iter.SetExtendTracksFlag(node["is_extend_tracks"].as<bool>(defaultIter.GetExtendTracksFlag()));
295 iter.SetMaxStationGap(node["max_station_gap"].as<int>(defaultIter.GetMaxStationGap()));
296 iter.SetMinNhits(node["min_n_hits"].as<int>(defaultIter.GetMinNhits()));
297 iter.SetMinNhitsStation0(node["min_n_hits_station_0"].as<int>(defaultIter.GetMinNhitsStation0()));
298 }
299 catch (const YAML::InvalidNode& exc) {
300 const auto nodeKeys = this->GetNodeKeys(node);
301 const auto nodeKeysStr =
302 std::accumulate(nodeKeys.cbegin(), nodeKeys.cend(), std::string(""),
303 [](std::string lhs, std::string rhs) { return std::move(lhs) + "\n\t" + std::move(rhs); });
304 LOG(fatal) << "L1 config: attempt to access key which does not exist in the configuration file (message from "
305 << "YAML exception: " << exc.what() << "). Defined keys: " << nodeKeysStr;
306 }
307 return iter;
308}
309
310// ---------------------------------------------------------------------------------------------------------------------
311//
313{
314 return Config{std::move(ReadCAIterationVector()),
315 std::move(yaml::Read<Config::Control>(GetNode([](YAML::Node n) { return n["core"]["track_finder"]; }))),
316 std::move(yaml::Read<Config::Dev>(GetNode([](YAML::Node n) { return n["core"]["dev"]; }))),
317 std::move(ReadMisalignmentTolerances())};
318}
319
320// ---------------------------------------------------------------------------------------------------------------------
321//
322void ConfigReader::SetDetectorNames(const std::array<std::string, constants::size::MaxNdetectors>& input)
323{
324 for (int iDet = 0; iDet < static_cast<int>(input.size()); ++iDet) {
325 std::string detName = boost::algorithm::to_lower_copy(input[iDet]);
326 if (!detName.empty()) {
327 fDetNameMap[detName] = static_cast<EDetectorID>(iDet);
328 }
329 }
330}
331
332// ---------------------------------------------------------------------------------------------------------------------
333//
334void ConfigReader::SetMainConfigPath(const std::string& path)
335{
336 if (path.size()) {
337 try {
338 fsMainConfigPath = path;
339 fMainConfigNode = YAML::LoadFile(fsMainConfigPath)["ca"];
340 if (fVerbose >= 1) {
341 LOG(info) << "ConfigReader: Registering main configuraiton file: \"\033[1;32m" << path << "\033[0m\"";
342 }
343 }
344 catch (const std::exception& err) {
345 LOG(error) << "ERROR: " << err.what();
346 }
347 }
348}
349
350// ---------------------------------------------------------------------------------------------------------------------
351//
352void ConfigReader::SetUserConfigPath(const std::string& path)
353{
354 if (path.size()) {
355 try {
356 fsUserConfigPath = path;
357 fUserConfigNode = YAML::LoadFile(fsUserConfigPath)["ca"];
358 if (fVerbose >= 1) {
359 LOG(info) << "ConfigReader: Registering user configuraiton file: \"\033[1;32m" << path << "\033[0m\"";
360 }
361 }
362 catch (const std::exception& err) {
363 LOG(error) << "ERROR: " << err.what();
364 }
365 }
366}
Configuration parameter file reader for the CA tracking algorithm (header)
Compile-time constants definition for the CA tracking algorithm.
fscal v[fmask::Size]
Definition KfSimdPseudo.h:4
ConfigReader(int verbose=1)
Constructor.
A reader for the CA parameters from the YAML configuration files.
std::vector< Iteration > ReadCAIterationVector() const
Reads CA track finder iterations from YAML node.
YAML::Node fUserConfigNode
User configuration node.
int fVerbose
Verbosity level.
void SetDetectorNames(const std::array< std::string, constants::size::MaxNdetectors > &input)
Sets detector names.
void SetUserConfigPath(const std::string &path)
Sets user config file.
Config::MisalignmentTolArray_t ReadMisalignmentTolerances() const
Reads misalignment tolerances.
Iteration ReadSingleCAIteration(const YAML::Node &node, const Iteration &defaultIter) const
Reads iteration from config file.
YAML::Node fMainConfigNode
Main configuration node.
std::unordered_map< std::string, EDetectorID > fDetNameMap
YAML::Node GetNode(std::function< YAML::Node(YAML::Node)> fn, bool optional=false) const
Accesses a node either from user config or from main config.
std::vector< std::pair< EDetectorID, int > > ReadInactiveStationMap() const
Reads inactive tracking station map.
std::string fsUserConfigPath
Path to the user config file (optional)
std::vector< std::string > GetNodeKeys(const YAML::Node &node) const
Gets parameters content of the node.
std::string fsMainConfigPath
Path to the main config file (mandatory)
void SetMainConfigPath(const std::string &path)
Sets main config file.
Config CreateConfig() const
Creates a config.
Configuration of the CA tracking (excluding geometry)
Definition CaConfig.h:36
std::array< MisalignmentTolerance, constants::size::MaxNdetectors > MisalignmentTolArray_t
Definition CaConfig.h:41
A set of parameters for the CA Track finder iteration.
Definition CaIteration.h:31
int GetMinNhits() const
Gets min n hits.
Definition CaIteration.h:88
float GetTripletChi2Cut() const
Gets triplet chi2 upper cut.
float GetMaxSlope() const
Gets max slope (tx\ty) in 3D hit position of a triplet.
Definition CaIteration.h:82
float GetPickGather() const
Gets size of region [TODO: units??] to attach new hits to the created track.
Definition CaIteration.h:97
float GetTrackChi2Cut() const
Gets track chi2 upper cut.
bool GetElectronFlag() const
flag check: electrons/positrons - true, heavy charged - false
Definition CaIteration.h:64
float GetDoubletChi2Cut() const
Gets doublet chi2 upper cut.
Definition CaIteration.h:61
float GetTripletFinalChi2Cut() const
Gets triplet chi2 upper cut.
int GetMaxStationGap() const
Gets flag: true - triplets are also built with skipping <= GetMaxStationGap stations.
Definition CaIteration.h:73
int GetMinNhitsStation0() const
Gets min n hits for tracks that start on station 0.
Definition CaIteration.h:91
float GetTargetPosSigmaX() const
Gets sigma target position in X direction [cm].
bool GetTrackFromTripletsFlag() const
float GetTripletLinkChi2() const
Gets min value of dp/dp_error, for which two tiplets are neighbours.
float GetMaxQp() const
Gets max considered q/p for tracks.
Definition CaIteration.h:79
float GetMaxDZ() const
Gets correction for accounting overlaping and iff z.
Definition CaIteration.h:76
bool GetPrimaryFlag() const
Checks flag: true - only primary tracks are searched, false - [all or only secondary?...
float GetTargetPosSigmaY() const
Gets sigma target position in Y direction [cm].
int GetFirstStationIndex() const
Gets station index of the first station used in tracking.
Definition CaIteration.h:70
bool GetExtendTracksFlag() const
Sets flag: true - extends track candidates with unused hits.
Definition CaIteration.h:67
float GetMaxSlopePV() const
Gets max slope (tx\ty) in primary vertex.
Definition CaIteration.h:85
Misalignment correction for x, y and time measurements in tracking.
EDetectorID
Enumeration for the tracking detector subsystems in CBM-CA.
Definition CbmDefs.h:216