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();
30 const auto invalid = [](std::string message) {
33 const auto checkTruthSize = [&](
const std::size_t
size,
37 : invalid(std::string{
"Truth block size mismatch for "} +
40 const auto checkSegmentSize = [&](
const std::size_t
size,
42 return size == nSegments
44 : invalid(std::string{
"Segment block size mismatch for "} +
47 const auto checkCandidateSize = [&](
const std::size_t
size,
49 return size == nCandidates
51 : invalid(std::string{
"Candidate block size mismatch for "} +
55#define TGC_CHECK_TRUTH_SIZE(FIELD) \
57 const auto result = checkTruthSize( \
58 event.truth.FIELD.size(), #FIELD); \
59 if (!result.valid) return result; \
84#undef TGC_CHECK_TRUTH_SIZE
86#define TGC_CHECK_SEGMENT_SIZE(FIELD) \
88 const auto result = checkSegmentSize( \
89 event.segments.FIELD.size(), #FIELD); \
90 if (!result.valid) return result; \
107#undef TGC_CHECK_SEGMENT_SIZE
109#define TGC_CHECK_CANDIDATE_SIZE(FIELD) \
111 const auto result = checkCandidateSize( \
112 event.candidates.FIELD.size(), #FIELD); \
113 if (!result.valid) return result; \
127#undef TGC_CHECK_CANDIDATE_SIZE
129 const auto wireProjection =
131 const auto stripProjection =
134 for (std::size_t segment = 0U; segment < nSegments; ++segment) {
135 const std::uint8_t projection =
event.segments.projection[segment];
136 if (projection != wireProjection && projection != stripProjection) {
137 return invalid(
"Segment projection is not wire or strip");
139 if (event.segments.nStations[segment] == 0U ||
140 event.segments.nStations[segment] > 3U) {
141 return invalid(
"Segment station count is out of range");
143 const int truth =
event.segments.truthIndex[segment];
144 if (truth >= 0 &&
static_cast<std::size_t
>(truth) >= nTruth) {
145 return invalid(
"Segment truth index is out of range");
147 const float residual =
event.segments.truthMatchResidual[segment];
149 (!std::isfinite(residual) ||
151 return invalid(
"Matched segment has an invalid truth residual");
154 return invalid(
"Unmatched segment has a truth residual");
158 for (
const int truth : event.candidates.truthIndex) {
159 if (truth >= 0 &&
static_cast<std::size_t
>(truth) >= nTruth) {
160 return invalid(
"Candidate truth index is out of range");
164 std::vector<int> candidateOwner(nCandidates, -1);
165 for (std::size_t truth = 0U; truth < nTruth; ++truth) {
166 if (event.truth.matched[truth] > 1U) {
167 return invalid(
"Truth matched flag is not binary");
169 const bool matched =
event.truth.matched[truth] != 0U;
170 const int candidate =
event.truth.matchedCandidateIndex[truth];
171 if (candidate >= 0 &&
static_cast<std::size_t
>(candidate) >= nCandidates) {
172 return invalid(
"Truth matched-candidate index is out of range");
174 if (matched && candidate < 0) {
175 return invalid(
"Matched truth has no candidate index");
177 if (!matched && candidate >= 0) {
178 return invalid(
"Unmatched truth has a candidate index");
181 event.truth.unmatchedReason[truth] !=
183 return invalid(
"Matched truth has an unmatched-reason code");
186 event.truth.unmatchedReason[truth] ==
188 return invalid(
"Unmatched truth has no unmatched-reason code");
191 event.truth.unmatchedReason[truth] >
192 static_cast<std::uint8_t
>(
194 return invalid(
"Truth unmatched-reason code is out of range");
197 (!std::isfinite(event.truth.matchMeanDeltaR[truth]) ||
199 return invalid(
"Matched truth has an invalid candidate residual");
203 return invalid(
"Unmatched truth has a candidate residual");
205 if (candidate >= 0) {
206 const auto candidateIndex =
static_cast<std::size_t
>(candidate);
207 if (candidateOwner[candidateIndex] >= 0) {
208 return invalid(
"Candidate is matched to more than one truth muon");
210 candidateOwner[candidateIndex] =
static_cast<int>(truth);
211 if (event.candidates.truthIndex[candidateIndex] !=
212 static_cast<int>(truth)) {
213 return invalid(
"Truth-candidate matching indices are not reciprocal");
217 if (event.truth.wireSegmentMatched[truth] > 1U ||
218 event.truth.stripSegmentMatched[truth] > 1U) {
219 return invalid(
"Truth segment-matched flag is not binary");
221 const bool wireMatched =
event.truth.wireSegmentMatched[truth] != 0U;
222 const bool stripMatched =
event.truth.stripSegmentMatched[truth] != 0U;
223 const int wireSegment =
event.truth.matchedWireSegmentIndex[truth];
224 const int stripSegment =
event.truth.matchedStripSegmentIndex[truth];
225 if (wireSegment >= 0 &&
226 static_cast<std::size_t
>(wireSegment) >= nSegments) {
227 return invalid(
"Truth matched-wire-segment index is out of range");
229 if (stripSegment >= 0 &&
230 static_cast<std::size_t
>(stripSegment) >= nSegments) {
231 return invalid(
"Truth matched-strip-segment index is out of range");
233 if (wireMatched && wireSegment < 0) {
234 return invalid(
"Wire-segment-matched truth has no segment index");
236 if (stripMatched && stripSegment < 0) {
237 return invalid(
"Strip-segment-matched truth has no segment index");
239 if (!wireMatched && wireSegment >= 0) {
240 return invalid(
"Wire-segment-unmatched truth has a segment index");
242 if (!stripMatched && stripSegment >= 0) {
243 return invalid(
"Strip-segment-unmatched truth has a segment index");
246 (!std::isfinite(event.truth.wireSegmentMatchResidual[truth]) ||
247 event.truth.wireSegmentMatchResidual[truth] ==
249 return invalid(
"Wire-segment-matched truth has an invalid residual");
252 event.truth.wireSegmentMatchResidual[truth] !=
254 return invalid(
"Wire-segment-unmatched truth has a residual");
257 (!std::isfinite(event.truth.stripSegmentMatchResidual[truth]) ||
258 event.truth.stripSegmentMatchResidual[truth] ==
260 return invalid(
"Strip-segment-matched truth has an invalid residual");
263 event.truth.stripSegmentMatchResidual[truth] !=
265 return invalid(
"Strip-segment-unmatched truth has a residual");
267 if (wireSegment >= 0 &&
268 event.segments.projection[wireSegment] != wireProjection) {
269 return invalid(
"Truth wire-segment index points to a strip segment");
271 if (stripSegment >= 0 &&
272 event.segments.projection[stripSegment] != stripProjection) {
273 return invalid(
"Truth strip-segment index points to a wire segment");
275 if ((wireSegment >= 0 &&
276 event.segments.truthIndex[wireSegment] !=
static_cast<int>(truth)) ||
277 (stripSegment >= 0 &&
278 event.segments.truthIndex[stripSegment] !=
static_cast<int>(truth))) {
279 return invalid(
"Truth-segment matching indices are not reciprocal");
283 for (std::size_t candidate = 0U; candidate < nCandidates; ++candidate) {
284 const int truth =
event.candidates.truthIndex[candidate];
285 if (truth < 0)
continue;
286 if (event.truth.matched[truth] == 0U ||
287 event.truth.matchedCandidateIndex[truth] !=
288 static_cast<int>(candidate)) {
289 return invalid(
"Truth-candidate matching indices are not reciprocal");
293 for (std::size_t segment = 0U; segment < nSegments; ++segment) {
294 const int truth =
event.segments.truthIndex[segment];
295 if (truth < 0)
continue;
296 const bool isWire =
event.segments.projection[segment] == wireProjection;
297 const int reverseIndex =
298 isWire ?
event.truth.matchedWireSegmentIndex[truth]
299 :
event.truth.matchedStripSegmentIndex[truth];
300 if (reverseIndex !=
static_cast<int>(segment)) {
301 return invalid(
"Truth-segment matching indices are not reciprocal");