GCC Code Coverage Report


Directory: ./
File: src/detID/wireID.cc
Date: 2025-09-01 06:19:01
Exec Total Coverage
Lines: 71 111 64.0%
Functions: 6 7 85.7%
Branches: 64 93 68.8%

Line Branch Exec Source
1 #include "na64detID/wireID.hh"
2
3 #include <cstdio>
4 #include <stdexcept>
5 #include <cstring>
6 #include <regex>
7
8 #include "na64util/str-fmt.hh"
9
10 namespace na64dp {
11
12 char
13 49173 APVPlaneID::proj_label( Projection p ) {
14
4/6
✓ Branch 0 taken 12294 times.
✓ Branch 1 taken 12293 times.
✓ Branch 2 taken 12293 times.
✓ Branch 3 taken 12293 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
49173 switch(p) {
15 12294 case kX:
16 case kX2:
17 12294 return 'X';
18 12293 case kY:
19 case kY2:
20 12293 return 'Y';
21 12293 case kU:
22 case kU2:
23 12293 return 'U';
24 12293 case kV:
25 case kV2:
26 12293 return 'V';
27 case kP:
28 return 'P';
29 default:
30 return p ? '?' : '*';
31 }
32 }
33
34 APVPlaneID::Projection
35 32826 APVPlaneID::proj_code( char p ) {
36
4/6
✓ Branch 0 taken 8208 times.
✓ Branch 1 taken 8206 times.
✓ Branch 2 taken 8206 times.
✓ Branch 3 taken 8206 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
32826 switch(p) {
37 8208 case 'X':
38 8208 return kX;
39 8206 case 'Y':
40 8206 return kY;
41 8206 case 'U':
42 8206 return kU;
43 8206 case 'V':
44 8206 return kV;
45 case 'P':
46 return kP;
47 default:
48 return kUnknown;
49 }
50 }
51
52 APVPlaneID::Projection
53 1 APVPlaneID::adjoint_proj_code( Projection p ) {
54
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if( !(0x8 & p) ) return kUnknown;
55 // set 3rd bit
56 1 return (Projection) (p | 0x4);
57 }
58
59 /**By "conjugated projection planes" we imply correspoance between two (usually
60 * ortogonal) detector planes like X&Y and U&V.
61 *
62 * Currently, this function assumes that conjugated planes are pairwise, i.e.
63 * there is no detector composed with, say, X, U and V planes triplet (NA58
64 * actually uses it like so).
65 *
66 * @param pjCode projection code
67 * @throws std::runtime_error if given numerical ID is not one of
68 * the WireID::Projection values.
69 * */
70 APVPlaneID::Projection
71 16380 APVPlaneID::conjugated_projection_code( WireID::Projection pjCode ) {
72
2/2
✓ Branch 0 taken 4095 times.
✓ Branch 1 taken 12285 times.
16380 if( kX == pjCode ) return kY;
73
2/2
✓ Branch 0 taken 4095 times.
✓ Branch 1 taken 8190 times.
12285 if( kY == pjCode ) return kX;
74
75
2/2
✓ Branch 0 taken 4095 times.
✓ Branch 1 taken 4095 times.
8190 if( kU == pjCode ) return kV;
76
1/2
✓ Branch 0 taken 4095 times.
✗ Branch 1 not taken.
4095 if( kV == pjCode ) return kU;
77
78 NA64DP_RUNTIME_ERROR(
79 , "Not a projection code / failed to get conjugated for: %d"
80 , pjCode );
81 }
82
83 void
84 WireID::append_completion_context( DetID did
85 , std::map<std::string, std::string> & m ) {
86 char bf[64];
87 if( ! did.is_payload_set() ) {
88 m["proj"] = "";
89 return;
90 }
91 WireID wID(did.payload());
92
93 if( wID.wire_no_is_set() ) {
94 snprintf(bf, sizeof(bf), "%d", wID.wire_no() );
95 m["wireNo"] = bf;
96 }
97
98 if( wID.proj_is_set() ) {
99 if( !WireID::proj_is_adjoint(wID.proj()) ) {
100 snprintf(bf, sizeof(bf), "%c", WireID::proj_label(wID.proj()) );
101 } else {
102 snprintf(bf, sizeof(bf), "%c2", WireID::proj_label(wID.proj()) );
103 }
104 m["proj"] = bf;
105 snprintf( bf, sizeof(bf)
106 , "%c%c"
107 , WireID::proj_label(wID.proj())
108 , WireID::proj_is_adjoint(wID.proj()) ? '2' : '1'
109 );
110 m["projN"] = bf;
111 } else {
112 m["proj"] = ""; // since projection is usually a part of station pattern
113 }
114 WireID::to_string( did.payload(), bf, sizeof(bf) );
115 m["idPayload"] = bf;
116 }
117
118 void
119 18 WireID::to_string( DetIDPayload_t pl
120 , char * buf
121 , size_t available ) {
122 18 WireID wid(pl);
123
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
18 if( !pl ) return;
124 17 size_t used = 0;
125
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 if( wid.proj_is_set() ) {
126
2/2
✓ Branch 1 taken 17 times.
✓ Branch 4 taken 17 times.
17 *buf = WireID::proj_label(wid.proj());
127
3/3
✓ Branch 1 taken 17 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 1 times.
17 if( !WireID::proj_is_adjoint(wid.proj()) ) {
128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if( available < 2 ) {
129 NA64DP_RUNTIME_ERROR("Buffer too short.");
130 }
131
2/2
✓ Branch 1 taken 16 times.
✓ Branch 4 taken 16 times.
16 *buf = WireID::proj_label(wid.proj());
132 16 ++buf;
133 16 --available;
134 16 *buf = '\0';
135 } else {
136
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if( available < 3 ) {
137 NA64DP_RUNTIME_ERROR("Buffer too short.");
138 }
139 1 buf[1] = '2';
140 1 buf[2] = '\0';
141 1 buf += 2;
142 1 available -= 2;
143 }
144 }
145
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 if( wid.wire_no_is_set() ) {
146 17 size_t n = snprintf(buf, available, "-%d", (int) wid.wire_no());
147
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if( n >= available ) {
148 NA64DP_RUNTIME_ERROR("Buffer too short.");
149 }
150 }
151 #if 0
152 if( wid.proj_is_set() && wid.wire_no_is_set() ) {
153 if( proj_is_adjoint(wid.proj()) ) {
154 used = snprintf( buf, available
155 , "%c-%d"
156 , proj_label(wid.proj())
157 , wid.wire_no() );
158 }
159 } else if( wid.proj_is_set() && !wid.wire_no_is_set() ) {
160 used = snprintf( buf, available
161 , "%c"
162 , proj_label(wid.proj())
163 );
164 } else {
165 used = snprintf( buf, available
166 , "-%d"
167 , wid.wire_no()
168 );
169 }
170 #endif
171 #if 0
172 if(!(wid.proj_is_set() || wid.wire_no_is_set())) { *buf = '\0'; }
173 else {
174 NA64DP_RUNTIME_ERROR( "Bad form of wire identifier for to-string"
175 " conversion: projection is %sset, wire number is %sset."
176 , wid.proj_is_set() ? "" : "not "
177 , wid.wire_no_is_set() ? "" : "not "
178 );
179 }
180 #endif
181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if( (size_t) used >= available ) {
182 NA64DP_RUNTIME_ERROR( "Buffer of length %zu is"
183 " insufficient for WireID string, result truncated."
184 , available );
185 }
186 }
187
188 // Groups:
189 // 0 -- whole match
190 // 1 -- "XY" or "UV", special case for dedicated straw TDC
191 // 2 -- projection symbol, X,Y,U or V
192 // 3 -- plane sub-number (like for 2nd layer of straws), a single digit
193 // 4 -- wire number, if present
194 static std::regex gRxTail
195 = std::regex(R"~(^(?:((?:XY)|(?:UV))|(?:([XYUVP])([12])?))(?:_+)?(?:-(\d+))?$)~");
196 ;
197 static const int gSpecialBiprojKeyGNum = 1 // {XY|UV} group number
198 , gProjKeyGNum = 2
199 , gProjKeySubGNum = 3
200 , gWireGNum = 4
201 ;
202
203 DetIDPayload_t
204 20 WireID::from_string( const char * widStr ) {
205 /* Expected format:
206 * "Y-123" -- standard, projection char and wire no
207 * "Y1__" -- kludgy, only first letter must be interpreted
208 * "Y1__-123" -- kludgy, with wire number
209 */
210 #if 1
211 20 WireID wid;
212 20 std::cmatch m;
213
3/3
✓ Branch 1 taken 20 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 18 times.
20 if( !std::regex_match(widStr, m, gRxTail) ) {
214 2 NA64DP_RUNTIME_ERROR("Tail portion of detector ID \"%s\" does not"
215 " match expected pattern for wired detectors."
216 , widStr );
217 }
218
2/3
✓ Branch 1 taken 18 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
18 if( m[gSpecialBiprojKeyGNum].length() ) {
219 assert(!m[gProjKeyGNum].length()); // {XY|UV} is mutually exclusive with indiv proj-s
220 const std::string tok(m[gSpecialBiprojKeyGNum].str());
221 if( tok == "XY" ) wid.proj(kXY);
222 else if( tok == "UV" ) wid.proj(kUV);
223 wid.unset_wire_no();
224
2/3
✓ Branch 2 taken 18 times.
✓ Branch 5 taken 18 times.
✗ Branch 6 not taken.
18 } else if( m[gProjKeyGNum].length() ) {
225
2/3
✓ Branch 1 taken 18 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
18 assert(!m[gSpecialBiprojKeyGNum].length()); // {XY|UV} is mutually exclusive with indiv proj-s
226
3/4
✓ Branch 1 taken 18 times.
✓ Branch 4 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
18 assert(m[gProjKeyGNum].str().length() == 1);
227
4/4
✓ Branch 1 taken 18 times.
✓ Branch 4 taken 18 times.
✓ Branch 7 taken 18 times.
✓ Branch 10 taken 18 times.
18 WireID::Projection projCode = WireID::proj_code(m[gProjKeyGNum].str()[0]);
228
3/3
✓ Branch 1 taken 18 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 17 times.
18 if(m[gProjKeySubGNum].length()) {
229 // plane sub-number is given
230
3/3
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 7 taken 1 times.
1 char subNum = m[gProjKeySubGNum].str()[0];
231
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if('2' == subNum) {
232
1/1
✓ Branch 1 taken 1 times.
1 projCode = WireID::adjoint_proj_code(projCode);
233 } else if('1' != subNum) {
234 NA64DP_RUNTIME_ERROR( "Sub-plane number %c is not supported."
235 , subNum );
236 }
237 }
238
1/1
✓ Branch 1 taken 18 times.
18 wid.proj(projCode);
239 }
240
2/3
✓ Branch 1 taken 18 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
18 if(m[gWireGNum].length()) {
241
3/3
✓ Branch 1 taken 18 times.
✓ Branch 4 taken 18 times.
✓ Branch 7 taken 18 times.
18 int wireNo = stoi(m[gWireGNum].str());
242
3/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 17 times.
18 if( 0 > wireNo || wireNo > WireID::wireMax ) {
243 1 NA64DP_RUNTIME_ERROR( "Wire number %ld exceed definition limits [0:%d)."
244 , wireNo, wireMax );
245 }
246 17 wid.wire_no(wireNo);
247 }
248 #else // this *may* be a bit more efficient, yet becoming really hard to maintain...
249 assert(widStr);
250 if('\0' == *widStr) return 0x0;
251 WireID wid;
252 if( std::isalpha(*widStr) ) { // projection
253 if( isalpha(widStr[1]) ) { // XY, UV, UX, DX, etc
254 Projection pc1 = proj_code( widStr[0] )
255 , pc2 = proj_code( widStr[1] )
256 ;
257 if( pc1 != kUnknown && pc2 != kUnknown ) {
258 // both letters correspond to projections
259 if( pc1 == kX && pc2 == kY ) {
260 wid.proj(kXY);
261 } else if( pc1 == kU && pc2 == kV ) {
262 wid.proj(kUV);
263 } else {
264 NA64DP_RUNTIME_ERROR( "Unable to interpret projection"
265 " code(s): \"%s\"", widStr );
266 }
267 ++widStr;
268 } else { // both are chars but one or both are not projections
269 // this meant to be up/down or left/right parts for multipart
270 // construction
271 NA64DP_RUNTIME_ERROR( "Multipart detID (%s) not implemented.", widStr );
272 }
273 // end of "two first chars are letters"-clause
274 } else { // second letter is not a projection letter
275 wid.proj(proj_code( widStr[0] ));
276 }
277 if( (!wid.proj_is_set()) || kUnknown == wid.proj() ) {
278 NA64DP_RUNTIME_ERROR( "Projection code label '%x' can not be"
279 " interpreted in string %s.", widStr[0], widStr );
280 }
281 // NOTE: for GEMs we have a special naming scheme in ~2017, when
282 // TBNames had a suffix "{proj}1__". To circumvent this feature, whe
283 // do here a direct string comparison. "__" have to be ignored as well.
284 if( '-' != widStr[1] && '\0' != widStr[1] ) {
285 // There is something at the tail
286 if( '2' == widStr[1] ) {
287
288 }
289 if( strncmp( "1__", widStr+1, 3 ) || strncmp( "__", widStr+1, 2 ) ) {
290 // comparison failure
291 NA64DP_RUNTIME_ERROR( "Unable to interpret tail portion of string"
292 " \"%s\" as wire number (GM-2017 scheme assumed).", widStr+1 );
293 }
294 widStr += isdigit(widStr[1]) ? 3 : 2;
295 }
296 if('\0' == widStr[1]) return wid.id; // only projection char was given
297 if('-' != widStr[1]) {
298 NA64DP_RUNTIME_ERROR( "Unable to interpret tail portion of string"
299 " \"%s\" as wire number. Expected \"-<wireno>\"", widStr );
300 }
301 widStr += 2;
302 } // first matches projection (X, Y, U or V)
303 // wire no, if given
304 char * tail;
305 long int wireNo = strtol( widStr, &tail, 10 );
306 if( '\0' != *tail || tail == widStr ) {
307 NA64DP_RUNTIME_ERROR( "Unable to interpret tail portion \"%s\" of string"
308 " \"%s\" as wire number.", tail, widStr );
309 }
310 if( 0 > wireNo || wireNo > WireID::wireMax ) {
311 NA64DP_RUNTIME_ERROR( "Wire number %ld exceed definition limits [0:%d)."
312 , wireNo, wireMax );
313 }
314 wid.wire_no( (uint16_t) wireNo );
315 #endif
316 17 return wid.id;
317 20 }
318
319 }
320
321