106 const auto & numberGroup =
getGroup(
"PixelNNNumber");
107 const auto & posSummary =
getGroup(
"PixelNNPosSummary");
108 const auto & splitGroup =
getGroup(
"PixelNNSplitFrac");
111 if (!pixelClusters.
isValid()) {
113 return StatusCode::SUCCESS;
117 std::vector<std::vector<const SiHit*>> siHitsByHash;
119 siHitsByHash.resize(
m_pixelID->wafer_hash_max());
122 for (
const SiHit&
h : *siHits) {
123 if (!
h.isPixel()) {
continue; }
125 h.getPhiModule(),
h.getEtaModule());
127 if (wh < m_pixelID->wafer_hash_max()) siHitsByHash[wh].push_back(&
h);
130 ATH_MSG_DEBUG(
"SiHit collection not available; truth plots disabled this event");
138 std::unordered_map<Identifier::value_type, std::vector<OnTrackInfo>> onTrackClusters;
142 if (!track) {
continue; }
143 for (
const auto* tsos : *track->trackStateOnSurfaces()) {
145 const auto* rio =
dynamic_cast<const Trk::RIO_OnTrack*
>(tsos->measurementOnTrack());
146 if (!rio || !rio->prepRawData()) {
continue; }
148 if (!pixClus || !tsos->trackParameters()) {
continue; }
149 onTrackClusters[pixClus->identify().get_compact()].push_back(
150 {tsos->trackParameters(), &rio->associatedSurface()});
160 if (
h.isValid()) splitProbs =
h.cptr();
167 double evtMinErrX = std::numeric_limits<double>::max();
168 double evtMaxErrX = 0.;
169 double evtMinErrY = std::numeric_limits<double>::max();
170 double evtMaxErrY = 0.;
171 double evtMaxAbsDeltaX = 0.;
172 double evtMaxAbsDeltaY = 0.;
173 double evtMaxProb2 = 0.;
174 bool evtHasPos =
false;
176 for (
const auto* coll : *pixelClusters) {
177 if (!coll) {
continue; }
178 for (
const auto* cluster : *coll) {
179 if (!cluster) {
continue; }
181 if (!element) {
continue; }
184 const double eta = cluster->globalPosition().eta();
185 const int nCell =
static_cast<int>(cluster->rdoList().
size());
188 std::vector<Amg::Vector2D> truths;
189 if (
m_doTruth && !siHitsByHash.empty()) {
192 const int trueN =
static_cast<int>(truths.size());
193 const bool haveTruth = (trueN >= 1 && trueN <= 3);
199 auto it = onTrackClusters.find(cluster->identify().get_compact());
200 if (it == onTrackClusters.end() || it->second.empty()) {
continue; }
208 std::vector<double> probs =
209 m_nnFactory->estimateNumberOfParticles(*cluster, *surf0, *tp0);
210 if (probs.size() < 3) {
continue; }
214 const int predN = splitDecision(std::span<const double, 3>(probs.data(), 3));
220 constexpr double refPathLength = 0.250;
223 const double cosTheta = std::cos(localIntersection.theta());
225 if (std::abs(cosTheta) < 1e-6) {
continue; }
226 localIntersection *= refPathLength / cosTheta;
227 const double trkTheta = std::atan2(localIntersection.y(), refPathLength);
228 double trkPhi = std::atan2(localIntersection.x(), refPathLength);
230 trkPhi = std::atan(std::tan(trkPhi) - tanl);
232 evtMaxProb2 = std::max(evtMaxProb2, probs[1]);
237 fill(numberGroup, monPredN, monProb1, monProb2, monProb3);
243 for (
const OnTrackInfo& t : it->second)
244 if (t.params) leadPt = std::max(leadPt, t.params->momentum().perp());
245 const int nnArgmax = 1 +
static_cast<int>(
246 std::max_element(probs.begin(), probs.begin() + 3) - probs.begin());
248 auto monPt =
Scalar<float>(
"trackPt", leadPt / Gaudi::Units::GeV);
252 auto monNn =
Scalar<int> (
"nnSplit", nnArgmax >= 2 ? 1 : 0);
253 fill(splitGroup, monPt, monPhi, monTheta, monClusEta, monNn);
256 auto monReco =
Scalar<int>(
"recoSplit",
sp.isSplit() ? 1 : 0);
257 fill(splitGroup, monPt, monPhi, monTheta, monClusEta, monReco);
260 auto monTruth =
Scalar<int>(
"truthSplit", trueN >= 2 ? 1 : 0);
261 fill(splitGroup, monPt, monPhi, monTheta, monClusEta, monTruth);
267 auto monIsCorrect =
Scalar<int> (
"isCorrect", trueN == predN ? 1 : 0);
270 auto monProbMulti =
Scalar<float>(
"probMulti", probs[1] + probs[2]);
271 fill(numberGroup, monTrueN, monPredNc, monIsCorrect, monEta, monNCell, monProbMulti);
280 const int numberOfSubclusters = predN;
282 const auto & posDQ =
getGroup(
"PixelNNPosDQ");
283 const auto & posGroup =
getGroup(
"PixelNNPosN" + std::to_string(numberOfSubclusters));
284 for (
const OnTrackInfo& trk : it->second) {
285 if (!trk.params || !trk.surface) {
continue; }
286 std::vector<Amg::MatrixX> errors;
287 std::vector<Amg::Vector2D> positions =
m_nnFactory->estimatePositions(
288 *cluster, *trk.surface, *trk.params, errors, numberOfSubclusters);
289 if (
static_cast<int>(positions.size()) != numberOfSubclusters ||
290 static_cast<int>(errors.size()) != numberOfSubclusters) {
continue; }
294 for (
int i = 0; i < numberOfSubclusters; ++i) {
295 if (errors[i].rows() < 2) {
continue; }
296 const double sigX = std::sqrt(errors[i](0, 0));
297 const double sigY = std::sqrt(errors[i](1, 1));
298 if (sigX <= 0 || sigY <= 0) {
continue; }
305 auto monPrecX =
Scalar<float>(
"posPrecX", 1.0 / (sigX * sigX));
306 auto monPrecY =
Scalar<float>(
"posPrecY", 1.0 / (sigY * sigY));
307 fill(posDQ, monDeltaX, monDeltaY, monErrXWide, monErrYWide, monPrecX, monPrecY);
308 evtMinErrX = std::min(evtMinErrX, sigX);
309 evtMaxErrX = std::max(evtMaxErrX, sigX);
310 evtMinErrY = std::min(evtMinErrY, sigY);
311 evtMaxErrY = std::max(evtMaxErrY, sigY);
312 evtMaxAbsDeltaX = std::max(evtMaxAbsDeltaX, std::abs(dX));
313 evtMaxAbsDeltaY = std::max(evtMaxAbsDeltaY, std::abs(dY));
317 if (!haveTruth || predN != trueN) {
continue; }
323 constexpr double fallbackErrX = 0.01;
324 constexpr double fallbackErrY = 0.05;
326 if (trk.params->covariance()) {
327 trkErr =
Amg::Vector2D(std::sqrt((*trk.params->covariance())(0, 0)),
328 std::sqrt((*trk.params->covariance())(1, 1)));
331 double best = std::numeric_limits<double>::max();
332 for (
int i = 0; i < numberOfSubclusters; ++i) {
333 double d = std::pow(trkPos[0] - positions[i][0], 2) / trkErr[0]
334 + std::pow(trkPos[1] - positions[i][1], 2) / trkErr[1];
335 if (d < best) { best = d; sub = i; }
337 if (errors[sub].rows() < 2) {
continue; }
338 const double errX = std::sqrt(errors[sub](0, 0));
339 const double errY = std::sqrt(errors[sub](1, 1));
340 if (errX <= 0 || errY <= 0) {
continue; }
346 std::vector<int> perm(numberOfSubclusters);
347 std::iota(perm.begin(), perm.end(), 0);
348 std::vector<int> bestPerm = perm;
349 double bestDist = std::numeric_limits<double>::max();
352 for (
int i = 0; i < numberOfSubclusters; ++i)
353 dsum += (positions[i] - truths[perm[i]]).squaredNorm();
354 if (dsum < bestDist) { bestDist = dsum; bestPerm = perm; }
355 }
while (std::next_permutation(perm.begin(), perm.end()));
356 const int tr = bestPerm[sub];
361 auto monResX =
Scalar<float>(
"resX", resX / Gaudi::Units::micrometer);
362 auto monResY =
Scalar<float>(
"resY", resY / Gaudi::Units::micrometer);
365 auto monErrX =
Scalar<float>(
"errX", errX / Gaudi::Units::micrometer);
366 auto monErrY =
Scalar<float>(
"errY", errY / Gaudi::Units::micrometer);
369 fill(posGroup, monResX, monResY, monPullX, monPullY, monErrX, monErrY, monEta, monNCell);
371 auto monPosN =
Scalar<int>(
"posN", numberOfSubclusters);
372 fill(posSummary, monPosN, monPullX, monPullY, monErrX, monErrY);
377 auto monNClusters =
Scalar<int>(
"nClusters", nClusters);
378 fill(numberGroup, monNClusters);
381 const auto & extremes =
getGroup(
"PixelNNExtremes");
386 auto monMaxDX =
Scalar<float>(
"evtMaxAbsDeltaX", evtMaxAbsDeltaX);
387 auto monMaxDY =
Scalar<float>(
"evtMaxAbsDeltaY", evtMaxAbsDeltaY);
389 fill(extremes, monMinErrX, monMaxErrX, monMinErrY, monMaxErrY, monMaxDX, monMaxDY, monMaxP2);
391 return StatusCode::SUCCESS;