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();
33 const auto invalid = [](std::string message) {
36 const auto checkTruthSize = [&](
const std::size_t
size,
40 : invalid(std::string{
"Truth block size mismatch for "} +
43 const auto checkSegmentSize = [&](
const std::size_t
size,
45 return size == nSegments
47 : invalid(std::string{
"Segment block size mismatch for "} +
50 const auto checkCandidateSize = [&](
const std::size_t
size,
52 return size == nCandidates
54 : invalid(std::string{
"Candidate block size mismatch for "} +
57 const auto checkFinalCandidateSize = [&](
const std::size_t
size,
59 return size == nFinalCandidates
62 std::string{
"Final-candidate block size mismatch for "} +
66 const auto checkSectorLogicSize = [&](
const std::size_t
size,
68 return size == nSectorLogic
70 : invalid(std::string{
"Sector Logic block size mismatch for "} +
74#define TGC_CHECK_TRUTH_SIZE(FIELD) \
76 const auto result = checkTruthSize( \
77 event.truth.FIELD.size(), #FIELD); \
78 if (!result.valid) return result; \
107#undef TGC_CHECK_TRUTH_SIZE
109#define TGC_CHECK_SEGMENT_SIZE(FIELD) \
111 const auto result = checkSegmentSize( \
112 event.segments.FIELD.size(), #FIELD); \
113 if (!result.valid) return result; \
130#undef TGC_CHECK_SEGMENT_SIZE
132#define TGC_CHECK_CANDIDATE_SIZE(FIELD) \
134 const auto result = checkCandidateSize( \
135 event.candidates.FIELD.size(), #FIELD); \
136 if (!result.valid) return result; \
154#undef TGC_CHECK_CANDIDATE_SIZE
156#define TGC_CHECK_FINAL_CANDIDATE_SIZE(FIELD) \
158 const auto result = checkFinalCandidateSize( \
159 event.finalCandidates.FIELD.size(), #FIELD); \
160 if (!result.valid) return result; \
180#undef TGC_CHECK_FINAL_CANDIDATE_SIZE
182#define TGC_CHECK_SECTOR_LOGIC_SIZE(FIELD) \
184 const auto result = checkSectorLogicSize( \
185 event.sectorLogic.FIELD.size(), #FIELD); \
186 if (!result.valid) return result; \
195#undef TGC_CHECK_SECTOR_LOGIC_SIZE
197 const auto wireProjection =
199 const auto stripProjection =
201 const auto invalidStation =
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");
209 if (event.segments.nStations[segment] == 0U ||
210 event.segments.nStations[segment] > 3U) {
211 return invalid(
"Segment station count is out of range");
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");
217 const float residual =
event.segments.truthMatchResidual[segment];
219 (!std::isfinite(residual) ||
221 return invalid(
"Matched segment has an invalid truth residual");
224 return invalid(
"Unmatched segment has a truth residual");
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");
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");
238 std::vector<bool> sourceCandidateLinked(nCandidates,
false);
239 for (std::size_t candidate = 0U; candidate < nFinalCandidates;
241 if (event.finalCandidates.tcId[candidate] > 6U) {
242 return invalid(
"Final-candidate TCID is out of range");
244 if (event.finalCandidates.innerCoincidence[candidate] > 1U ||
245 event.finalCandidates.goodMagneticField[candidate] > 1U) {
246 return invalid(
"Final-candidate flag is not binary");
248 if (std::abs(event.finalCandidates.charge[candidate]) != 1) {
249 return invalid(
"Final-candidate charge is invalid");
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");
263 if (
static_cast<std::size_t
>(source) >= nCandidates) {
264 return invalid(
"Final-candidate source index is out of range");
266 const std::size_t sourceIndex =
static_cast<std::size_t
>(source);
268 return invalid(
"Final-candidate reference station is invalid");
270 if (sourceCandidateLinked[sourceIndex]) {
272 "Source candidate is linked to more than one final candidate");
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");
279 (!std::isfinite(residual) ||
281 return invalid(
"Matched final candidate has an invalid truth residual");
284 return invalid(
"Unmatched final candidate has a truth residual");
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");
294 if (event.finalCandidates.tcId[inputIndex] == 0U) {
295 return invalid(
"Sector Logic input index points to an empty candidate");
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");
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");
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");
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");
321 if (matched && candidate < 0) {
322 return invalid(
"Matched truth has no candidate index");
324 if (!matched && candidate >= 0) {
325 return invalid(
"Unmatched truth has a candidate index");
328 event.truth.unmatchedReason[truth] !=
330 return invalid(
"Matched truth has an unmatched-reason code");
333 event.truth.unmatchedReason[truth] ==
335 return invalid(
"Unmatched truth has no unmatched-reason code");
338 event.truth.unmatchedReason[truth] >
339 static_cast<std::uint8_t
>(
341 return invalid(
"Truth unmatched-reason code is out of range");
344 (!std::isfinite(event.truth.matchMeanDeltaR[truth]) ||
346 return invalid(
"Matched truth has an invalid candidate residual");
350 return invalid(
"Unmatched truth has a candidate residual");
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");
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");
364 if (event.truth.finalCandidateMatched[truth] > 1U) {
365 return invalid(
"Truth final-candidate-matched flag is not binary");
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");
375 if (finalMatched && finalCandidate < 0) {
376 return invalid(
"Final-candidate-matched truth has no candidate index");
378 if (!finalMatched && finalCandidate >= 0) {
379 return invalid(
"Final-candidate-unmatched truth has a candidate index");
382 event.truth.finalCandidateUnmatchedReason[truth] !=
384 return invalid(
"Final-candidate-matched truth has an unmatched-reason code");
387 event.truth.finalCandidateUnmatchedReason[truth] ==
389 return invalid(
"Final-candidate-unmatched truth has no unmatched-reason code");
392 event.truth.finalCandidateUnmatchedReason[truth] >
393 static_cast<std::uint8_t
>(
395 return invalid(
"Truth final-candidate unmatched-reason code is out of range");
398 (!std::isfinite(event.truth.finalCandidateMatchDeltaR[truth]) ||
399 event.truth.finalCandidateMatchDeltaR[truth] ==
401 return invalid(
"Final-candidate-matched truth has an invalid residual");
404 event.truth.finalCandidateMatchDeltaR[truth] !=
406 return invalid(
"Final-candidate-unmatched truth has a residual");
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");
414 finalCandidateOwner[finalCandidateIndex] =
static_cast<int>(truth);
415 if (event.finalCandidates.truthIndex[finalCandidateIndex] !=
416 static_cast<int>(truth)) {
418 "Truth-final-candidate matching indices are not reciprocal");
422 if (event.truth.wireSegmentMatched[truth] > 1U ||
423 event.truth.stripSegmentMatched[truth] > 1U) {
424 return invalid(
"Truth segment-matched flag is not binary");
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");
434 if (stripSegment >= 0 &&
435 static_cast<std::size_t
>(stripSegment) >= nSegments) {
436 return invalid(
"Truth matched-strip-segment index is out of range");
438 if (wireMatched && wireSegment < 0) {
439 return invalid(
"Wire-segment-matched truth has no segment index");
441 if (stripMatched && stripSegment < 0) {
442 return invalid(
"Strip-segment-matched truth has no segment index");
444 if (!wireMatched && wireSegment >= 0) {
445 return invalid(
"Wire-segment-unmatched truth has a segment index");
447 if (!stripMatched && stripSegment >= 0) {
448 return invalid(
"Strip-segment-unmatched truth has a segment index");
451 (!std::isfinite(event.truth.wireSegmentMatchResidual[truth]) ||
452 event.truth.wireSegmentMatchResidual[truth] ==
454 return invalid(
"Wire-segment-matched truth has an invalid residual");
457 event.truth.wireSegmentMatchResidual[truth] !=
459 return invalid(
"Wire-segment-unmatched truth has a residual");
462 (!std::isfinite(event.truth.stripSegmentMatchResidual[truth]) ||
463 event.truth.stripSegmentMatchResidual[truth] ==
465 return invalid(
"Strip-segment-matched truth has an invalid residual");
468 event.truth.stripSegmentMatchResidual[truth] !=
470 return invalid(
"Strip-segment-unmatched truth has a residual");
472 if (wireSegment >= 0 &&
473 event.segments.projection[wireSegment] != wireProjection) {
474 return invalid(
"Truth wire-segment index points to a strip segment");
476 if (stripSegment >= 0 &&
477 event.segments.projection[stripSegment] != stripProjection) {
478 return invalid(
"Truth strip-segment index points to a wire segment");
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");
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");
498 for (std::size_t candidate = 0U; candidate < nFinalCandidates;
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)) {
506 "Truth-final-candidate matching indices are not reciprocal");
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");