GCC Code Coverage Report


Directory: ./
File: src/detID/TBName.cc
Date: 2025-09-01 06:19:01
Exec Total Coverage
Lines: 94 153 61.4%
Functions: 7 15 46.7%
Branches: 125 156 80.1%

Line Branch Exec Source
1 #include "na64detID/TBName.hh"
2 #include "na64detID/TBNameErrors.hh"
3 #include "na64detID/cellID.hh"
4 #include "na64detID/wireID.hh"
5 #include "na64util/str-fmt.hh"
6 #include "na64detID/nameparse.hh"
7
8 #include <limits>
9 #include <cstdio>
10 #include <cstring>
11
12 #include <yaml-cpp/yaml.h>
13 #include <log4cpp/Category.hh>
14
15 // NOTE: sections marked as "TODO: ChipTraits" has to become the subject of
16 // dedicated type system addressing the call to particular extension
17
18 namespace na64dp {
19 namespace errors {
20
21 3 IDIsOutOfRange::IDIsOutOfRange( const char * what_, int proposed, int maximum ) throw()
22 : std::runtime_error(what_)
23 3 , _proposedID(proposed)
24 3 , _maximumValue(maximum) {}
25
26 TBNameParsingFailure::TBNameParsingFailure( const char * msg, const char * culprit_ ) throw() :
27 std::runtime_error( msg ) {
28 strncpy( _TBName, culprit_, sizeof(_TBName) );
29 }
30
31 1 NameIsNotUniq::NameIsNotUniq( const char * what_, const char * nm_ ) throw()
32 1 : std::runtime_error(what_) {
33 1 strncpy( _name, nm_, sizeof(_name) );
34 1 }
35
36 }
37
38 namespace nameutils {
39
40 void
41 DetectorNaming::clear() {
42 ChipFeaturesTable::clear();
43 KinFeaturesTable::clear();
44 }
45
46 DetectorNaming::KinFeatures &
47 59 DetectorNaming::define_kin( const std::string & kinName
48 , DetKin_t kinID
49 , const std::string & chipName
50 , const std::string & fmt
51 , const std::string & kinDescription
52 , const std::string & histsTPath ) {
53 59 DetChip_t chipID = chip_id(chipName);
54 58 return define_kin( kinName, kinID, chipID, fmt, kinDescription, histsTPath );
55 }
56
57 void
58 8 DetectorNaming::_append_subst_dict_for( DetID did
59 , std::map<std::string, std::string> & m
60 , const ChipFeatures * chipFtsPtr
61 , const KinFeatures * kinFtsPtr ) {
62 char bf[128];
63
2/3
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 if( did.is_chip_set() ) {
64 assert(chipFtsPtr); // LCOV_EXCL_LINE
65
3/3
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 7 taken 8 times.
16 m["chip"] = chipFtsPtr->name;
66
3/3
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 7 taken 8 times.
16 m["chipDesc"] = chipFtsPtr->description;
67
1/1
✓ Branch 1 taken 8 times.
8 snprintf(bf, sizeof(bf), "%#x", did.chip());
68
3/3
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 7 taken 8 times.
16 m["chipNo"] = bf;
69 }
70
71
2/3
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 if( did.is_kin_set() ) {
72
1/1
✓ Branch 1 taken 8 times.
8 snprintf(bf, sizeof(bf), "%#x", did.kin());
73
3/3
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 7 taken 8 times.
8 m["kinNo"] = bf;
74
75
2/3
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 if( did.is_chip_set() ) {
76 assert( kinFtsPtr ); // LCOV_EXCL_LINE
77
3/3
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 7 taken 8 times.
16 m["kin"] = kinFtsPtr->name;
78
3/3
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 7 taken 8 times.
24 m["kinDesc"] = kinFtsPtr->description;
79 }
80 }
81
82
3/3
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 2 times.
8 if( did.is_number_set() ) {
83
1/1
✓ Branch 1 taken 6 times.
6 snprintf(bf, sizeof(bf), "%d", did.number() );
84
3/3
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
✓ Branch 7 taken 6 times.
6 m["statNum"] = bf;
85
86
1/1
✓ Branch 1 taken 6 times.
6 snprintf(bf, sizeof(bf), "%02d", did.number() );
87
3/3
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
✓ Branch 7 taken 6 times.
12 m["statNum2"] = bf;
88 }
89
90
2/3
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 if( did.is_chip_set() ) {
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(chipFtsPtr);
92
7/7
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 7 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 6 times.
8 if(chipFtsPtr->to_string && did.is_payload_set()) {
93 char plBf[64];
94
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 chipFtsPtr->to_string(did.payload(), plBf, sizeof(plBf));
95
3/3
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
4 m["subDet"] = plBf;
96 }
97
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
8 if(chipFtsPtr->append_completion_context) {
98
1/1
✓ Branch 1 taken 7 times.
7 chipFtsPtr->append_completion_context( did, m );
99 }
100 }
101 8 }
102
103 /** Naming substitution is needed in some applications that requires
104 * interpretation of numerical detector identifier. This method of naming,
105 * together with `str_subst()` function provides a way to render
106 * meaningful strings based on the detector identifier. For any valid
107 * detector ID the following list of substitutions will be written in map
108 * object provided as an argument in this method:
109 *
110 * If chip is set by the given detector ID:
111 * * chip -- chip name (SADC, APV, etc)
112 * * chipNo -- chip number in hex form (e.g. 0x1, 0xa, etc)
113 * * chipDesc -- a chip description
114 *
115 * If chip and kin are set by the given ID:
116 * * kin -- kin name (ECAL, HCAL, GEM, etc)
117 * * kinNo -- kin number in hex form (e.g. 0x1, 0xff, etc)
118 * * kinDesc -- a kin (detector type) textual description
119 * * TBName -- a name in format of DDD. Note that if DDD format string
120 * contains `statNum` or `statNum2` and station number is not set
121 * by ID it won't be resolved (so TBName is not guaranteed to be
122 * corrected if station number is not set)
123 *
124 * If station number is set by the given ID:
125 * * statNum -- station number (1, 2, 123, etc.)
126 * * statNum2 -- station number of two digits (01, 02, etc)
127 *
128 * If chip and payload are set, the dictionary will be appended with
129 * appropriate payload information (see `ChipTraits`).
130 * */
131 void
132 8 DetectorNaming::append_subst_dict_for( DetID_t did_
133 , std::map<std::string, std::string> & m ) const {
134 8 DetID did(did_);
135
1/1
✓ Branch 1 taken 8 times.
8 const ChipFeatures * chipFtsPtr = did.is_chip_set()
136
3/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 6 taken 8 times.
8 ? &chip_features(did.chip())
137 8 : nullptr;
138
3/4
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
16 const KinFeatures * kinFtsPtr = did.is_chip_set() && did.is_kin_set()
139
5/6
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 6 taken 8 times.
✓ Branch 9 taken 8 times.
✓ Branch 12 taken 8 times.
16 ? &kin_features( std::make_pair(did.chip(), did.kin()) )
140 8 : nullptr;
141
1/1
✓ Branch 1 taken 8 times.
16 return _append_subst_dict_for( did, m, chipFtsPtr, kinFtsPtr );
142 }
143
144 void
145 DetectorNaming::append_subst_dict_for( TrackID trackID
146 , std::map<std::string, std::string> & m ) const {
147 char bf[256];
148 {
149 snprintf(bf, sizeof(bf), "%#x", trackID.code);
150 m["trackID"] = bf;
151 }
152 {
153 snprintf(bf, sizeof(bf), "%#x", trackID.zones());
154 m["trackZonePattern"] = bf;
155 }
156 // ...
157 }
158
159 /** Uses string template provided in `fmt` argument to produce a string form
160 * of detector ID by its numerical representation. Although this method is
161 * convenient in various contexts, note the following features:
162 *
163 * - if chip is not defined by num ID, an exception will be thrown.
164 * - if kin is not defined by num ID, returned string is the chip name.
165 * - if station number is not defined, but it appears at kin format string,
166 * an exception (stating that detector ID is not complete) will be thrown.
167 * - if payload is not set, the returned string is somewhat similar to
168 * orginal "TBName" from `DaqDataDecoding` library. Examples are:
169 * "MM01X__", "ECAL0", "HCAL3", etc. This specific form is quite important.
170 * - for payload being set, the "extension suffix" will appear in the output
171 * string.
172 *
173 * */
174 std::string
175 8 DetectorNaming::name( DetID did ) const {
176
2/3
✓ Branch 1 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
8 if( !did.is_chip_set() ) {
177 NA64DP_RUNTIME_ERROR( "Dectector ID (=%#x) has no chip ID."
178 , (int) did );
179 }
180
2/3
✓ Branch 1 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
8 if( !did.is_kin_set() ) {
181 return chip_features(did.chip()).name;
182 }
183
3/3
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 7 taken 8 times.
8 auto kinID = std::make_pair( did.chip(), did.kin() );
184
1/1
✓ Branch 1 taken 8 times.
8 const ChipFeatures & chipFts = chip_features( kinID.first );
185
1/1
✓ Branch 1 taken 8 times.
8 const KinFeatures & kinFts = kin_features( kinID );
186
187 const std::string * templatePtr;
188
3/3
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 6 times.
8 if( did.is_payload_set() ) {
189 // payload is set -- use full name format
190 2 templatePtr = &detector_string_patern<&KinFeatures::nameFormat>( chipFts, kinFts );
191 } else {
192 // payload is not set -- use TBName format
193 6 templatePtr = &detector_string_patern<&KinFeatures::dddNameFormat>( chipFts, kinFts );
194 }
195
196 // if resulting string template is empty -- nor kin, nor chip template
197 // were not defined that must be considered as error in runtime
198 // configuration (config file)
199
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if( templatePtr->empty() ) {
200 if( did.is_payload_set() ) {
201 NA64DP_RUNTIME_ERROR( "Full name pattern is not defined for"
202 " detector entity of kin \"%s\" of chip \"%s\""
203 , kinFts.name.c_str()
204 , chipFts.name.c_str() );
205 } else {
206 NA64DP_RUNTIME_ERROR( "TBName pattern is not defined for"
207 " detector station of kin \"%s\" of chip \"%s\""
208 , kinFts.name.c_str()
209 , chipFts.name.c_str() );
210 }
211 }
212
213 // acquire context and render string
214 8 util::StrSubstDict ctx;
215
1/1
✓ Branch 2 taken 8 times.
8 append_subst_dict_for( did, ctx );
216 try {
217
1/1
✓ Branch 1 taken 7 times.
8 return util::str_subst( *templatePtr, ctx );
218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 } catch( errors::StringIncomplete & e ) {
219 // this can still be a valid conversion if kin template implies
220 // station number
221
5/8
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 if( e.token() == "{statNum}" || e.token() == "{statNum2}" ) {
222 return util::str_subst( "{kin}", ctx );
223 }
224 throw errors::IncompleteDetectorID( templatePtr->c_str()
225
1/1
✓ Branch 5 taken 1 times.
1 , e.incomplete_string().c_str() );
226 1 }
227 8 }
228
229 std::string
230 DetectorNaming::name( StationKey sk ) const { // TODO: verify
231 if( !sk.is_chip_set() ) {
232 NA64DP_RUNTIME_ERROR( "Dectector ID (=%#x) has no chip ID."
233 , (int) sk.id );
234 }
235 if( !sk.is_kin_set() ) {
236 return chip_features(sk.chip()).name;
237 }
238 //auto kinID = std::make_pair( sk.chip(), sk.kin() );
239 //const ChipFeatures & chipFts = chip_features( kinID.first );
240 //const KinFeatures & kinFts = kin_features( kinID );
241
242 std::string strTemplate = "{kin}{statNum2}";
243
244 // acquire context and render string
245 util::StrSubstDict ctx;
246 append_subst_dict_for( DetID(sk.id), ctx );
247 return util::str_subst( strTemplate, ctx );
248 }
249
250 #if 0
251 std::string
252 DetectorNaming::smart_name(DetID id) const {
253 uint8_t avail
254 = ( id.is_chip_set() ? 0x1 : 0x0)
255 | ( id.is_kin_set() ? 0x2 : 0x0)
256 | ( id.is_number_set() ? 0x4 : 0x0)
257 | ( id.is_payload_set() ? 0x8 : 0x0)
258 ;
259 util::StrSubstDict ctx;
260 append_subst_dict_for(DetID(id), ctx);
261 switch(avail) {
262 case 0x7:
263 case 0xf:
264 { // all set or all set except for payload
265 return name(id);
266 } break;
267 case 0x3:
268 { // only chip+kin set
269 std::string tmpl = "{kin}";
270 return util::str_subst(tmpl, ctx);
271 } break;
272 case 0x1:
273 { // only chip is set
274 std::string tmpl = "{chip}";
275 return util::str_subst(tmpl, ctx);
276 }
277 };
278 // if we reach this line, detector ID does not bring some "standard"
279 // identifiers. In this case we shall still provide user code with usable
280 // information, but particular use cases are still unclear...
281 NA64DP_RUNTIME_ERROR("TODO: convert partial detector ID to string."); // TODO
282 }
283 #endif
284
285 DetID
286 11 DetectorNaming::id(const std::string & nm, bool noThrow) const {
287 11 std::string name
288 11 , number
289 11 , payload
290 ;
291
2/3
✓ Branch 1 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
11 if( !tokenize_name_str( nm, name, number, payload ) ) {
292 if( noThrow )
293 return DetID();
294 NA64DP_RUNTIME_ERROR( "Failed to convert string \"%s\" to detector"
295 " name (lexical mismatch).", nm.c_str() );
296 }
297
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 assert( !name.empty() );
298
1/1
✓ Branch 1 taken 11 times.
11 bool nameRefersToKin = has_kin(name);
299
6/6
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 9 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 10 times.
11 if( number.empty() && payload.empty() ) {
300 // assume it is kin or chip name
301
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if( nameRefersToKin ) {
302 // interpret as kin name
303
1/1
✓ Branch 1 taken 1 times.
1 KinID kid = kin_id(name);
304
1/1
✓ Branch 1 taken 1 times.
1 return DetID( kid.first, kid.second );
305 }
306 // otherwise, interpret name as chip name
307 DetID did = DetID( chip_id(name), 0x0 );
308 did.unset_kin();
309 return did;
310 }
311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if( !nameRefersToKin ) {
312 //NA64DP_RUNTIME_ERROR( "Name \"%s\" does not refer to known kin."
313 // , name.c_str() );
314 throw errors::UnknownKin( name, nm.c_str() );
315 }
316
1/1
✓ Branch 1 taken 10 times.
10 KinID kid = kin_id(name);
317
1/1
✓ Branch 1 taken 10 times.
10 DetID did( kid.first, kid.second );
318
2/3
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
10 assert(!did.is_payload_set());
319
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1 times.
10 if( !number.empty() ) {
320 9 char * endptr = nullptr;
321 9 long int statNum = strtol( number.data(), &endptr, 10 );
322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 assert( statNum > -1 );
323
1/1
✓ Branch 1 taken 9 times.
9 did.number( (DetNumber_t) statNum );
324
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 assert( endptr == number.data() + number.size() );
325 }
326
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2 times.
10 if( !payload.empty() ) {
327
1/1
✓ Branch 1 taken 8 times.
8 const ChipFeatures & chipFts = chip_features( kid.first );
328
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 if( !chipFts.from_string ) {
329
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if( noThrow )
330 return did;
331 2 NA64DP_RUNTIME_ERROR(
332 "No payload-from-str conversion defined"
333 " for chip \"%s\"."
334 , chipFts.name.c_str() );
335 }
336
1/1
✓ Branch 2 taken 6 times.
6 auto pl = chipFts.from_string(payload.data());
337
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if( pl ) {
338
1/1
✓ Branch 1 taken 4 times.
4 did.payload( pl );
339
2/3
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 assert( did.payload() == pl );
340 }
341 }
342 8 return did;
343 15 }
344
345
346 const std::string &
347 DetectorNaming::name_template(DetID detID) const {
348 if( detID.is_payload_set() ) {
349 return detector_string_patern<&KinFeatures::nameFormat>(
350 chip_features( detID.chip() ),
351 kin_features( std::make_pair(detID.chip(), detID.kin()) )
352 );
353 } else {
354 return detector_string_patern<&KinFeatures::dddNameFormat>(
355 chip_features( detID.chip() ),
356 kin_features( std::make_pair(detID.chip(), detID.kin()) )
357 );
358 }
359 }
360
361 const std::string &
362 DetectorNaming::path_template(StationKey sk) const {
363 return detector_string_patern<&KinFeatures::pathFormat>(
364 chip_features( sk.chip() ),
365 kin_features( std::make_pair(sk.chip(), sk.kin()) )
366 );
367 }
368
369
370 void
371 DetectorIDStrSubstTraits< std::pair<DetID, DetID> >::append_context(
372 const nameutils::DetectorNaming & nm
373 , std::pair<DetID, DetID> k
374 , util::StrSubstDict & ctx
375 ) {
376 util::StrSubstDict one, two;
377 DetectorIDStrSubstTraits<DetID>::append_context(nm, k.first, one);
378 DetectorIDStrSubstTraits<DetID>::append_context(nm, k.second, two);
379 for( const auto & p : one ) {
380 ctx.emplace( "first." + p.first, p.second );
381 }
382 for( const auto & p : two ) {
383 ctx.emplace( "second." + p.first, p.second );
384 }
385 }
386
387 // Default path template for plots identified by detector ID pair
388 static const std::string _dftHstTemplate
389 = "multityped/{hist}-{first.kin}-vs-{second.kin}";
390
391 const std::string *
392 DetectorIDStrSubstTraits< std::pair<DetID, DetID> >::path_template_for(
393 const nameutils::DetectorNaming & nm
394 , std::pair<DetID, DetID> k ) {
395 return &_dftHstTemplate;
396 }
397
398 } // namespace na64::nameutils
399 } // namespace na64
400