Check vector sizes and reciprocal cross-block indices.
25 {
26 const std::size_t nTruth = event.truth.pdgId.size();
27 const std::size_t nSegments = event.segments.subdetectorId.size();
28 const std::size_t nCandidates = event.candidates.subdetectorId.size();
29 const std::size_t nFinalCandidates =
30 event.finalCandidates.subdetectorId.size();
31 const std::size_t nSectorLogic = event.sectorLogic.candWord.size();
32
33 const auto invalid = [](std::string message) {
35 };
36 const auto checkTruthSize = [&](
const std::size_t
size,
40 : invalid(std::string{"Truth block size mismatch for "} +
42 };
43 const auto checkSegmentSize = [&](
const std::size_t
size,
45 return size == nSegments
47 : invalid(std::string{"Segment block size mismatch for "} +
49 };
50 const auto checkCandidateSize = [&](
const std::size_t
size,
52 return size == nCandidates
54 : invalid(std::string{"Candidate block size mismatch for "} +
56 };
57 const auto checkFinalCandidateSize = [&](
const std::size_t
size,
59 return size == nFinalCandidates
61 : invalid(
62 std::string{"Final-candidate block size mismatch for "} +
64 };
65
66 const auto checkSectorLogicSize = [&](
const std::size_t
size,
68 return size == nSectorLogic
70 : invalid(std::string{"Sector Logic block size mismatch for "} +
72 };
73
74#define TGC_CHECK_TRUTH_SIZE(FIELD) \
75 do { \
76 const auto result = checkTruthSize( \
77 event.truth.FIELD.size(), #FIELD); \
78 if (!result.valid) return result; \
79 } while (false)
80
107#undef TGC_CHECK_TRUTH_SIZE
108
109#define TGC_CHECK_SEGMENT_SIZE(FIELD) \
110 do { \
111 const auto result = checkSegmentSize( \
112 event.segments.FIELD.size(), #FIELD); \
113 if (!result.valid) return result; \
114 } while (false)
115
130#undef TGC_CHECK_SEGMENT_SIZE
131
132#define TGC_CHECK_CANDIDATE_SIZE(FIELD) \
133 do { \
134 const auto result = checkCandidateSize( \
135 event.candidates.FIELD.size(), #FIELD); \
136 if (!result.valid) return result; \
137 } while (false)
138
154#undef TGC_CHECK_CANDIDATE_SIZE
155
156#define TGC_CHECK_FINAL_CANDIDATE_SIZE(FIELD) \
157 do { \
158 const auto result = checkFinalCandidateSize( \
159 event.finalCandidates.FIELD.size(), #FIELD); \
160 if (!result.valid) return result; \
161 } while (false)
162
180#undef TGC_CHECK_FINAL_CANDIDATE_SIZE
181
182#define TGC_CHECK_SECTOR_LOGIC_SIZE(FIELD) \
183 do { \
184 const auto result = checkSectorLogicSize( \
185 event.sectorLogic.FIELD.size(), #FIELD); \
186 if (!result.valid) return result; \
187 } while (false)
188
195#undef TGC_CHECK_SECTOR_LOGIC_SIZE
196
197 const auto wireProjection =
199 const auto stripProjection =
201 const auto invalidStation =
203
204 for (std::size_t segment = 0U; segment < nSegments; ++segment) {
205 const std::uint8_t projection = event.segments.projection[segment];
206 if (projection != wireProjection && projection != stripProjection) {
207 return invalid("Segment projection is not wire or strip");
208 }
209 if (
event.segments.nStations[segment] == 0U ||
210 event.segments.nStations[segment] > 3U) {
211 return invalid("Segment station count is out of range");
212 }
213 const int truth = event.segments.truthIndex[segment];
214 if (truth >= 0 && static_cast<std::size_t>(truth) >= nTruth) {
215 return invalid("Segment truth index is out of range");
216 }
217 const float residual =
event.segments.truthMatchResidual[segment];
218 if (truth >= 0 &&
219 (!std::isfinite(residual) ||
221 return invalid("Matched segment has an invalid truth residual");
222 }
224 return invalid("Unmatched segment has a truth residual");
225 }
226 }
227
228 for (std::size_t candidate = 0U; candidate < nCandidates; ++candidate) {
229 if (
event.candidates.goodMagneticField[candidate] > 1U) {
230 return invalid("Candidate GoodMag flag is not binary");
231 }
232 const int truth = event.candidates.truthIndex[candidate];
233 if (truth >= 0 && static_cast<std::size_t>(truth) >= nTruth) {
234 return invalid("Candidate truth index is out of range");
235 }
236 }
237
238 std::vector<bool> sourceCandidateLinked(nCandidates, false);
239 for (std::size_t candidate = 0U; candidate < nFinalCandidates;
240 ++candidate) {
241 if (
event.finalCandidates.tcId[candidate] > 6U) {
242 return invalid("Final-candidate TCID is out of range");
243 }
244 if (
event.finalCandidates.innerCoincidence[candidate] > 1U ||
245 event.finalCandidates.goodMagneticField[candidate] > 1U) {
246 return invalid("Final-candidate flag is not binary");
247 }
248 if (std::abs(
event.finalCandidates.charge[candidate]) != 1) {
249 return invalid("Final-candidate charge is invalid");
250 }
251 const int source =
event.finalCandidates.sourceCandidateIndex[candidate];
252 const std::uint8_t station =
253 event.finalCandidates.referenceStation[candidate];
254 const int truth = event.finalCandidates.truthIndex[candidate];
255 const float residual =
event.finalCandidates.truthMatchDeltaR[candidate];
256 if (
event.finalCandidates.tcId[candidate] == 0U) {
257 if (source >= 0 || station != invalidStation || truth >= 0 ||
259 return invalid("Empty final candidate has validation links");
260 }
261 continue;
262 }
263 if (static_cast<std::size_t>(source) >= nCandidates) {
264 return invalid("Final-candidate source index is out of range");
265 }
266 const std::size_t sourceIndex =
static_cast<std::size_t
>(
source);
268 return invalid("Final-candidate reference station is invalid");
269 }
270 if (sourceCandidateLinked[sourceIndex]) {
271 return invalid(
272 "Source candidate is linked to more than one final candidate");
273 }
274 sourceCandidateLinked[sourceIndex] = true;
275 if (truth >= 0 && static_cast<std::size_t>(truth) >= nTruth) {
276 return invalid("Final-candidate truth index is out of range");
277 }
278 if (truth >= 0 &&
279 (!std::isfinite(residual) ||
281 return invalid("Matched final candidate has an invalid truth residual");
282 }
284 return invalid("Unmatched final candidate has a truth residual");
285 }
286 }
287
288 for (std::size_t candidate = 0U; candidate < nSectorLogic; ++candidate) {
289 const std::size_t inputIndex =
290 event.sectorLogic.inputCandidateIndex[candidate];
291 if (inputIndex >= nFinalCandidates) {
292 return invalid("Sector Logic input-candidate index is out of range");
293 }
294 if (
event.finalCandidates.tcId[inputIndex] == 0U) {
295 return invalid("Sector Logic input index points to an empty candidate");
296 }
297 if (candidate != 0U &&
298 event.sectorLogic.inputCandidateIndex[candidate] <=
299 event.sectorLogic.inputCandidateIndex[candidate - 1U]) {
300 return invalid("Sector Logic input-candidate indices are not ordered");
301 }
302 if (
event.sectorLogic.boardId[candidate] != 0U ||
303 event.sectorLogic.fiberId[candidate] != 0U ||
304 event.sectorLogic.bcidOffset[candidate] != 0 ||
305 event.sectorLogic.veto[candidate] != 0U) {
306 return invalid("Sector Logic placeholder metadata is not zero");
307 }
308 }
309
310 std::vector<int> candidateOwner(nCandidates, -1);
311 std::vector<int> finalCandidateOwner(nFinalCandidates, -1);
312 for (std::size_t truth = 0U; truth < nTruth; ++truth) {
313 if (
event.truth.matched[truth] > 1U) {
314 return invalid("Truth matched flag is not binary");
315 }
316 const bool matched = event.truth.matched[truth] != 0U;
317 const int candidate = event.truth.matchedCandidateIndex[truth];
318 if (candidate >= 0 && static_cast<std::size_t>(candidate) >= nCandidates) {
319 return invalid("Truth matched-candidate index is out of range");
320 }
321 if (matched && candidate < 0) {
322 return invalid("Matched truth has no candidate index");
323 }
324 if (!matched && candidate >= 0) {
325 return invalid("Unmatched truth has a candidate index");
326 }
327 if (matched &&
328 event.truth.unmatchedReason[truth] !=
330 return invalid("Matched truth has an unmatched-reason code");
331 }
332 if (!matched &&
333 event.truth.unmatchedReason[truth] ==
335 return invalid("Unmatched truth has no unmatched-reason code");
336 }
337 if (!matched &&
338 event.truth.unmatchedReason[truth] >
339 static_cast<std::uint8_t>(
341 return invalid("Truth unmatched-reason code is out of range");
342 }
343 if (matched &&
344 (!std::isfinite(
event.truth.matchMeanDeltaR[truth]) ||
346 return invalid("Matched truth has an invalid candidate residual");
347 }
348 if (!matched &&
350 return invalid("Unmatched truth has a candidate residual");
351 }
352 if (candidate >= 0) {
353 const auto candidateIndex = static_cast<std::size_t>(candidate);
354 if (candidateOwner[candidateIndex] >= 0) {
355 return invalid("Candidate is matched to more than one truth muon");
356 }
357 candidateOwner[candidateIndex] = static_cast<int>(truth);
358 if (
event.candidates.truthIndex[candidateIndex] !=
359 static_cast<int>(truth)) {
360 return invalid("Truth-candidate matching indices are not reciprocal");
361 }
362 }
363
364 if (
event.truth.finalCandidateMatched[truth] > 1U) {
365 return invalid("Truth final-candidate-matched flag is not binary");
366 }
367 const bool finalMatched =
368 event.truth.finalCandidateMatched[truth] != 0U;
369 const int finalCandidate =
370 event.truth.matchedFinalCandidateIndex[truth];
371 if (finalCandidate >= 0 &&
372 static_cast<std::size_t>(finalCandidate) >= nFinalCandidates) {
373 return invalid("Truth matched-final-candidate index is out of range");
374 }
375 if (finalMatched && finalCandidate < 0) {
376 return invalid("Final-candidate-matched truth has no candidate index");
377 }
378 if (!finalMatched && finalCandidate >= 0) {
379 return invalid("Final-candidate-unmatched truth has a candidate index");
380 }
381 if (finalMatched &&
382 event.truth.finalCandidateUnmatchedReason[truth] !=
384 return invalid("Final-candidate-matched truth has an unmatched-reason code");
385 }
386 if (!finalMatched &&
387 event.truth.finalCandidateUnmatchedReason[truth] ==
389 return invalid("Final-candidate-unmatched truth has no unmatched-reason code");
390 }
391 if (!finalMatched &&
392 event.truth.finalCandidateUnmatchedReason[truth] >
393 static_cast<std::uint8_t>(
395 return invalid("Truth final-candidate unmatched-reason code is out of range");
396 }
397 if (finalMatched &&
398 (!std::isfinite(
event.truth.finalCandidateMatchDeltaR[truth]) ||
399 event.truth.finalCandidateMatchDeltaR[truth] ==
401 return invalid("Final-candidate-matched truth has an invalid residual");
402 }
403 if (!finalMatched &&
404 event.truth.finalCandidateMatchDeltaR[truth] !=
406 return invalid("Final-candidate-unmatched truth has a residual");
407 }
408 if (finalCandidate >= 0) {
409 const auto finalCandidateIndex =
410 static_cast<std::size_t>(finalCandidate);
411 if (finalCandidateOwner[finalCandidateIndex] >= 0) {
412 return invalid("Final candidate is matched to more than one truth muon");
413 }
414 finalCandidateOwner[finalCandidateIndex] = static_cast<int>(truth);
415 if (
event.finalCandidates.truthIndex[finalCandidateIndex] !=
416 static_cast<int>(truth)) {
417 return invalid(
418 "Truth-final-candidate matching indices are not reciprocal");
419 }
420 }
421
422 if (
event.truth.wireSegmentMatched[truth] > 1U ||
423 event.truth.stripSegmentMatched[truth] > 1U) {
424 return invalid("Truth segment-matched flag is not binary");
425 }
426 const bool wireMatched = event.truth.wireSegmentMatched[truth] != 0U;
427 const bool stripMatched = event.truth.stripSegmentMatched[truth] != 0U;
428 const int wireSegment = event.truth.matchedWireSegmentIndex[truth];
429 const int stripSegment = event.truth.matchedStripSegmentIndex[truth];
430 if (wireSegment >= 0 &&
431 static_cast<std::size_t>(wireSegment) >= nSegments) {
432 return invalid("Truth matched-wire-segment index is out of range");
433 }
434 if (stripSegment >= 0 &&
435 static_cast<std::size_t>(stripSegment) >= nSegments) {
436 return invalid("Truth matched-strip-segment index is out of range");
437 }
438 if (wireMatched && wireSegment < 0) {
439 return invalid("Wire-segment-matched truth has no segment index");
440 }
441 if (stripMatched && stripSegment < 0) {
442 return invalid("Strip-segment-matched truth has no segment index");
443 }
444 if (!wireMatched && wireSegment >= 0) {
445 return invalid("Wire-segment-unmatched truth has a segment index");
446 }
447 if (!stripMatched && stripSegment >= 0) {
448 return invalid("Strip-segment-unmatched truth has a segment index");
449 }
450 if (wireMatched &&
451 (!std::isfinite(
event.truth.wireSegmentMatchResidual[truth]) ||
452 event.truth.wireSegmentMatchResidual[truth] ==
454 return invalid("Wire-segment-matched truth has an invalid residual");
455 }
456 if (!wireMatched &&
457 event.truth.wireSegmentMatchResidual[truth] !=
459 return invalid("Wire-segment-unmatched truth has a residual");
460 }
461 if (stripMatched &&
462 (!std::isfinite(
event.truth.stripSegmentMatchResidual[truth]) ||
463 event.truth.stripSegmentMatchResidual[truth] ==
465 return invalid("Strip-segment-matched truth has an invalid residual");
466 }
467 if (!stripMatched &&
468 event.truth.stripSegmentMatchResidual[truth] !=
470 return invalid("Strip-segment-unmatched truth has a residual");
471 }
472 if (wireSegment >= 0 &&
473 event.segments.projection[wireSegment] != wireProjection) {
474 return invalid("Truth wire-segment index points to a strip segment");
475 }
476 if (stripSegment >= 0 &&
477 event.segments.projection[stripSegment] != stripProjection) {
478 return invalid("Truth strip-segment index points to a wire segment");
479 }
480 if ((wireSegment >= 0 &&
481 event.segments.truthIndex[wireSegment] !=
static_cast<int>(truth)) ||
482 (stripSegment >= 0 &&
483 event.segments.truthIndex[stripSegment] !=
static_cast<int>(truth))) {
484 return invalid("Truth-segment matching indices are not reciprocal");
485 }
486 }
487
488 for (std::size_t candidate = 0U; candidate < nCandidates; ++candidate) {
489 const int truth = event.candidates.truthIndex[candidate];
490 if (truth < 0) continue;
491 if (
event.truth.matched[truth] == 0U ||
492 event.truth.matchedCandidateIndex[truth] !=
493 static_cast<int>(candidate)) {
494 return invalid("Truth-candidate matching indices are not reciprocal");
495 }
496 }
497
498 for (std::size_t candidate = 0U; candidate < nFinalCandidates;
499 ++candidate) {
500 const int truth = event.finalCandidates.truthIndex[candidate];
501 if (truth < 0) continue;
502 if (
event.truth.finalCandidateMatched[truth] == 0U ||
503 event.truth.matchedFinalCandidateIndex[truth] !=
504 static_cast<int>(candidate)) {
505 return invalid(
506 "Truth-final-candidate matching indices are not reciprocal");
507 }
508 }
509
510 for (std::size_t segment = 0U; segment < nSegments; ++segment) {
511 const int truth = event.segments.truthIndex[segment];
512 if (truth < 0) continue;
513 const bool isWire = event.segments.projection[segment] == wireProjection;
514 const int reverseIndex =
515 isWire ? event.truth.matchedWireSegmentIndex[truth]
516 : event.truth.matchedStripSegmentIndex[truth];
517 if (reverseIndex != static_cast<int>(segment)) {
518 return invalid("Truth-segment matching indices are not reciprocal");
519 }
520 }
521
522 return {};
523}
Scalar eta() const
pseudorapidity method
Scalar deltaPhi(const MatrixBase< Derived > &vec) const
Scalar phi() const
phi method
double charge(const T &p)
size_t size() const
Number of registered mappings.
unsigned bcTag(unsigned bcBitMap)
#define TGC_CHECK_SEGMENT_SIZE(FIELD)
#define TGC_CHECK_FINAL_CANDIDATE_SIZE(FIELD)
#define TGC_CHECK_TRUTH_SIZE(FIELD)
#define TGC_CHECK_CANDIDATE_SIZE(FIELD)
#define TGC_CHECK_SECTOR_LOGIC_SIZE(FIELD)
std::vector< std::string > veto
these patterns are anded
static constexpr float TgcL0ValidationInvalidValue
Common sentinel for unavailable floating-point validation data.
static constexpr std::uint8_t TgcL0ValidationNoUnmatchedReason
Sentinel indicating that a matched truth object has no failure code.
Result of a structural validation-data consistency check.