ATLAS Offline Software
Loading...
Searching...
No Matches
TritonTracccTrackMaker.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include <memory>
6#include <fstream>
7#include <sstream>
8
10
12
13#include <chrono>
14
15struct cell_order {
16 bool operator()(const TracccCell& lhs,
17 const TracccCell& rhs) const
18 {
19 if (lhs.channel1 != rhs.channel1) {
20 return (lhs.channel1 < rhs.channel1);
21 } else {
22 return (lhs.channel0 < rhs.channel0);
23 }
24 }
25};
26
28{
29 // input handles / tools
30 ATH_CHECK(detStore()->retrieve(m_pixelID, "PixelID"));
31 ATH_CHECK(m_pixelRDOKey.initialize());
32
33 ATH_CHECK(detStore()->retrieve(m_stripID, "SCT_ID"));
34 ATH_CHECK(m_stripRDOKey.initialize());
35
36 ATH_CHECK(detStore()->retrieve(m_pixelManager));
37 ATH_CHECK(detStore()->retrieve(m_stripManager));
38
39 // output container
41
45
46 // geometry helper for output
47 if (!m_trackingGeometrySvc.empty()) {
49 m_trackingGeometry = m_trackingGeometrySvc->trackingGeometry();
50 if (!m_trackingGeometry) {
51 ATH_MSG_DEBUG("Null Acts::TrackingGeometry from tracking geometry service");
52 return StatusCode::FAILURE;
53 }
54
56 if (!m_detEleToGeoIdMap) {
57 ATH_MSG_DEBUG("Null detector element to Acts geometry ID map from "
58 "tracking geometry service");
59 return StatusCode::FAILURE;
60 }
61 }
62
63 // tools
65
67
68 // Initialize condition handle keys
69 ATH_CHECK(m_pixelDetEleCollKey.initialize());
70 ATH_CHECK(m_stripDetEleCollKey.initialize());
71
72 // Initialize cluster container keys
78
79 // Initialize truth association keys if needed
82
83 ATH_CHECK(m_ctxProvider.initialize());
84
85 return StatusCode::SUCCESS;
86}
87
88StatusCode TritonTracccTrackMaker::execute(const EventContext& ctx) const
89{
90
91 // fill cells struct for sending to traccc
92 std::vector<TracccCell> cells;
93 auto cell_start = std::chrono::high_resolution_clock::now();
94 ATH_CHECK(read_cells(cells, ctx));
95 auto cell_end = std::chrono::high_resolution_clock::now();
96 std::chrono::duration<double, std::milli> cell_time = cell_end - cell_start;
97 ATH_MSG_INFO("Cell reading time: " << cell_time.count() << " ms");
98
99 std::unordered_map<int64_t, int> cluster_map;
100 if (m_doTruth)
101 {
102 cluster_map = readAndConvertClusters(ctx);
103 }
104
105 // create output containers
106 std::vector<TracccTrackParameters> TracccTrackParams;
107 std::vector<LocalMeasurementInfoInTracks> TracccMeasurementsInfoInTracks;
108
109 // Run the inference
110 auto traccc_start = std::chrono::high_resolution_clock::now();
111 ATH_CHECK(m_tracccTrackingTool->getTracks(cells, TracccTrackParams, TracccMeasurementsInfoInTracks));
112 auto traccc_end = std::chrono::high_resolution_clock::now();
113 std::chrono::duration<double, std::milli> traccc_time = traccc_end - traccc_start;
114 ATH_MSG_INFO("Traccc total inference time: " << traccc_time.count() << " ms");
115
116 // convert to ACTs tracks
117 unsigned int nb_output_tracks = 0;
118 auto convert_start = std::chrono::high_resolution_clock::now();
119 ATH_CHECK(convertTracks(ctx, TracccTrackParams, TracccMeasurementsInfoInTracks,
120 cluster_map, nb_output_tracks));
121 auto convert_end = std::chrono::high_resolution_clock::now();
122 std::chrono::duration<double, std::milli> convert_time = convert_end - convert_start;
123 ATH_MSG_INFO("Traccc total conversion time: " << convert_time.count() << " ms");
124
125 return StatusCode::SUCCESS;
126}
127
129 int low_bound,
130 int high_bound,
131 int threshold,
132 int shift) const
133{
134
135 std::vector<int> result;
136
137 if (index == low_bound) { // 398 -> 398,399 ; 382 -> 382,383
138 result.push_back(index);
139 result.push_back(index + 1);
140 } else if (index == low_bound + 1) { // 399 -> 400,401 ; 383 -> 384,385
141 result.push_back(index + 1);
142 result.push_back(index + 2);
143 } else if (index == low_bound + 2) { // 400 -> 402,403 ; 384 -> 386,387
144 result.push_back(index + 2);
145 result.push_back(index + 3);
146 } else if (index == high_bound) { // 401 -> 404,405 ; 385 -> 388,390
147 result.push_back(index + 3);
148 result.push_back(index + 4);
149 } else if (index > threshold) {
150 result.push_back(index + shift);
151 } else {
152 result.push_back(index);
153 }
154
155 return result;
156}
157
158std::vector<std::pair<int, int>> TritonTracccTrackMaker::correct_indices(
159 int phiIndex, int etaIndex, int rows,
160 int columns) const
161{
162 // Traccc currently assumes a uniform pitch distributions on the modules
163 // however, in some EC and barel layers (> 0 and >1, respectively), there
164 // are 'quad' modules meaning the middle two rows and middle two columns are
165 // double pitch: 0.05 mm -> 0.1 mm We solve this in G-200 by splitting these
166 // cells into two contributions to ensure a uniform pitch across the module
167 // and therefore the correct cluster position calculation When translating
168 // the Athena cells to Traccc cells, the middle indices then need to get two
169 // contributions, the indices below are unchanged, the indices above get
170 // shifted by 4
171
172 int middle_row = rows / 2;
173 int middle_column = columns / 2;
174
175 std::vector<std::pair<int, int>> index_vec;
176
177 std::vector<int> mapped_x =
178 map_index(phiIndex, middle_row - 2, middle_row + 1, middle_row + 1, 4);
179 std::vector<int> mapped_y = map_index(
180 etaIndex, middle_column - 2, middle_column + 1, middle_column + 1, 4);
181
182 if ((middle_row - 2 <= phiIndex && phiIndex <= middle_row + 1) and
183 (middle_column - 2 <= etaIndex && etaIndex <= middle_column + 1)) {
184 ATH_MSG_DEBUG("mapping: " << phiIndex << "," << etaIndex);
185 }
186
187 for (auto [phi, eta] : std::views::cartesian_product(mapped_x, mapped_y)) {
188 index_vec.emplace_back(phi, eta);
189 if ((middle_row - 2 <= phiIndex && phiIndex <= middle_row + 1) and
190 (middle_column - 2 <= etaIndex &&
191 etaIndex <= middle_column + 1)) {
192 ATH_MSG_DEBUG(phi << "," << eta);
193 }
194 }
195
196 return index_vec;
197}
198
200 std::vector<TracccCell>& cells,
201 const EventContext& evtcontext) const
202{
203 cells.clear();
204
205 ATH_MSG_DEBUG("Reading pixel hits");
206
207 const PixelRDO_Container* pixelRDOHandle{};
208 ATH_CHECK(SG::get(pixelRDOHandle, m_pixelRDOKey, evtcontext));
209
210 int nPix = 0;
211 for (const InDetRawDataCollection<PixelRDORawData>* pixel_rdoCollection :
212 *pixelRDOHandle) {
213
214 for (const PixelRDORawData* pixelRawData : *pixel_rdoCollection) {
215
216 Identifier rdoId = pixelRawData->identify();
217
218 // get the det element from the det element collection
219 const InDetDD::SiDetectorElement* sielement =
220 m_pixelManager->getDetectorElement(rdoId);
221 assert(sielement);
222 const Identifier Pixel_ModuleID = sielement->identify();
223 InDetDD::SiCellId id = sielement->cellIdFromIdentifier(rdoId);
224
225 int layer_disk = m_pixelID->layer_disk(Pixel_ModuleID);
226 int barrel_ec = m_pixelID->barrel_ec(Pixel_ModuleID);
227
228 int64_t const geometry_id = Pixel_ModuleID.get_compact();
229
230 ATH_MSG_DEBUG("Doing this module: " << geometry_id);
231
232 if ((barrel_ec != 0 && layer_disk > 1) ||
233 (barrel_ec == 0 && layer_disk > 0)) {
234 const InDetDD::PixelModuleDesign* p_design =
235 static_cast<const InDetDD::PixelModuleDesign*>(
236 &sielement->design());
237 std::vector<std::pair<int, int>> cell_vec =
238 correct_indices(id.phiIndex(), id.etaIndex(),
239 p_design->rows(), p_design->columns());
240 for (std::size_t c = 0; c < cell_vec.size(); c++) {
241
242 std::tuple<int, int> indices = cell_vec.at(c);
243 const int phiIndex = std::get<0>(indices);
244 const int etaIndex = std::get<1>(indices);
245
246 cells.push_back({
247 geometry_id, 0, static_cast<int64_t>(phiIndex),
248 static_cast<int64_t>(etaIndex),
249 static_cast<float>(pixelRawData->getToT()),
250 8 // timestamp is not used
251 });
252 }
253 } else {
254 cells.push_back({
255 geometry_id, 0, static_cast<int64_t>(id.phiIndex()),
256 static_cast<int64_t>(id.etaIndex()),
257 static_cast<float>(pixelRawData->getToT()),
258 8 // timestamp is not used
259 });
260 }
261
262 nPix++;
263 }
264 }
265 ATH_MSG_DEBUG("Read " << nPix << " pixel hits");
266
267 ATH_MSG_DEBUG("Reading strip hits");
268
269 const SCT_RDO_Container* stripRDOHandle{};
270 ATH_CHECK(SG::get(stripRDOHandle, m_stripRDOKey, evtcontext));
271
272 int nStrip = 0;
273 for (const InDetRawDataCollection<SCT_RDORawData>* strip_Collection :
274 *stripRDOHandle) {
275 if (strip_Collection == nullptr) {
276 continue;
277 }
278 for (const SCT_RDORawData* stripRawData : *strip_Collection) {
279
280 const Identifier rdoId = stripRawData->identify();
281 const InDetDD::SiDetectorElement* sielement =
282 m_stripManager->getDetectorElement(rdoId);
283
284 const Identifier strip_moduleID = m_stripID->module_id(
285 sielement->identify()); // from wafer id to module id
286 const IdentifierHash Strip_ModuleHash =
287 m_stripID->wafer_hash(strip_moduleID);
288
289 // Extract the correct Strip_ModuleID
290 int side = m_stripID->side(sielement->identify());
291 const Identifier Strip_ModuleID =
292 m_stripID->wafer_id(Strip_ModuleHash + side);
293
294 InDetDD::SiCellId id = sielement->cellIdFromIdentifier(rdoId);
295
296 int64_t const geometry_id = Strip_ModuleID.get_compact();
297
298 if (m_stripID->barrel_ec(Strip_ModuleID) == 0) {
299
300 // if we have barrel modules, then this is in cartesian
301 // coordinates so phi, eta indices hold
302
303 for (int i = 0; i < stripRawData->getGroupSize(); i++) {
304
305 cells.push_back({
306 geometry_id, 0,
307 static_cast<int64_t>(id.phiIndex() + i), 0, 1,
308 8 // timestamp is not used
309 });
310 nStrip++;
311 }
312
313 } else {
314
315 // if we have annulus modules in the endcaps
316 // then we want to make r,phi measurements in the strip local
317 // frame but we cluster in the phi direction, so this has to be
318 // coordinate y
319
320 for (int i = 0; i < stripRawData->getGroupSize(); i++) {
321
322 cells.push_back({
323 geometry_id, 0, 0,
324 static_cast<int64_t>(id.phiIndex() + i), 1,
325 8 // timestamp is not used
326 });
327 nStrip++;
328 }
329 }
330 }
331 }
332 ATH_MSG_DEBUG("Read " << nStrip << " strip hits");
333
334 // Sort the cells. Deduplication or not, they do need to be sorted.
335 std::sort(cells.begin(), cells.end(), ::cell_order());
336
337 ATH_MSG_DEBUG("Sorted the cells container");
338
339 return StatusCode::SUCCESS;
340}
341
342std::unordered_map<int64_t, int> TritonTracccTrackMaker::readAndConvertClusters(
343 const EventContext& eventContext) const
344{
345 int nPix = 0;
346 int nStrip = 0;
347 std::unordered_map<int64_t, int> traccc_to_xaod_cluster_map;
348
349 ATH_MSG_INFO("Converting InDet clusters to xAOD");
351 xAODPixelContainerFromInDetClusters(
353 if ((xAODPixelContainerFromInDetClusters.record(
354 std::make_unique<xAOD::PixelClusterContainer>(),
355 std::make_unique<xAOD::PixelClusterAuxContainer>()))
356 .isFailure()) {
358 "Could not record xAOD Pixel container from InDet Clusters");
359 throw std::runtime_error(
360 "creation of xAOD Pixel container from InDet Clusters failed");
361 }
362
364 xAODStripContainerFromInDetClusters(
366 if ((xAODStripContainerFromInDetClusters.record(
367 std::make_unique<xAOD::StripClusterContainer>(),
368 std::make_unique<xAOD::StripClusterAuxContainer>()))
369 .isFailure()) {
371 "Could not record xAOD Strip container from InDet Clusters");
372 throw std::runtime_error(
373 "creation of xAOD Strip container from InDet Clusters failed");
374 }
375
377 m_pixelDetEleCollKey, eventContext);
378
379 const InDetDD::SiDetectorElementCollection* pixElements{};
380 if (SG::get(pixElements, m_pixelDetEleCollKey, eventContext).isFailure() ||
381 pixElements == nullptr) {
382 ATH_MSG_FATAL(m_pixelDetEleCollKey.fullKey() << " is not available.");
383 std::ostringstream errMsg;
384 errMsg << m_pixelDetEleCollKey.fullKey() << " is not available.";
385 throw std::runtime_error(errMsg.str());
386 }
387
389 m_stripDetEleCollKey, eventContext);
390 const InDetDD::SiDetectorElementCollection* stripElements(
391 *stripDetEleHandle);
392 if (not stripDetEleHandle.isValid() or stripElements == nullptr) {
393 ATH_MSG_FATAL(m_stripDetEleCollKey.fullKey() << " is not available.");
394 std::ostringstream errMsg;
395 errMsg << m_stripDetEleCollKey.fullKey() << " is not available.";
396 throw std::runtime_error(errMsg.str());
397 }
398
400 xAODSpacepointContainerFromInDetClusters(
402 if (xAODSpacepointContainerFromInDetClusters
403 .record(std::make_unique<xAOD::SpacePointContainer>(),
404 std::make_unique<xAOD::SpacePointAuxContainer>())
405 .isFailure()) {
406 throw std::runtime_error(
407 "creation of InDet spacepoint containers failed");
408 }
409
410 ATH_MSG_DEBUG("Reading clusters");
411
412 const InDet::PixelClusterContainer* inputPixelClusterContainer{};
413 if (SG::get(inputPixelClusterContainer, m_inputPixelClusterContainerKey,
414 eventContext)
415 .isFailure() ||
416 inputPixelClusterContainer == nullptr) {
418 << " is not available.");
419 std::ostringstream errMsg;
420 errMsg << m_inputPixelClusterContainerKey.fullKey()
421 << " is not available.";
422 throw std::runtime_error(errMsg.str());
423 }
424
425 for (const auto* const clusterCollection : *inputPixelClusterContainer) {
426 if (!clusterCollection)
427 continue;
428 for (const auto* const theCluster : *clusterCollection) {
429
430 const InDetDD::SiDetectorElement* element =
431 theCluster->detectorElement();
432 const Identifier Pixel_ModuleID = element->identify();
433
434 auto pixelCl = xAODPixelContainerFromInDetClusters->push_back(
435 std::make_unique<xAOD::PixelCluster>());
436 if ((convertInDetToXaodCluster(*theCluster, *element, *pixelCl))
437 .isFailure()) {
438 ATH_MSG_FATAL("Could not convert InDet pixel cluster to xAOD");
439 throw std::runtime_error(
440 "conversion of InDet pixel cluster to xAOD failed");
441 }
442
443 auto xaod_sp = xAODSpacepointContainerFromInDetClusters->push_back(
444 std::make_unique<xAOD::SpacePoint>());
445 const IdentifierHash Pixel_ModuleHash =
446 m_pixelID->wafer_hash(Pixel_ModuleID);
447
449 xAOD::MeasVector<3> globalPosition{xAOD::toStorage(theCluster->globalPosition())};
450
451 xaod_sp->setSpacePoint(Pixel_ModuleHash, globalPosition,
452 globalVariance(0, 0), globalVariance(1, 0),
453 {pixelCl});
454
455 size_t index = xAODPixelContainerFromInDetClusters->size() - 1;
456 traccc_to_xaod_cluster_map[Pixel_ModuleID.get_compact()] = index;
457
458 nPix++;
459 }
460 }
461 ATH_MSG_DEBUG("Read " << nPix << " pixel clusters");
462
463 const InDet::SCT_ClusterContainer* inputStripClusterContainer{};
464 if (SG::get(inputStripClusterContainer, m_inputStripClusterContainerKey,
465 eventContext)
466 .isFailure() ||
467 inputStripClusterContainer == nullptr) {
469 << " is not available.");
470 std::ostringstream errMsg;
471 errMsg << m_inputStripClusterContainerKey.fullKey()
472 << " is not available.";
473 throw std::runtime_error(errMsg.str());
474 }
475
476 for (const auto* const clusterCollection : *inputStripClusterContainer) {
477 if (!clusterCollection)
478 continue;
479 for (const auto* const theCluster : *clusterCollection) {
480
481 const InDetDD::SiDetectorElement* element =
482 theCluster->detectorElement();
483 const Identifier Strip_ModuleID = element->identify();
484
485 xAOD::StripCluster* stripCl = new xAOD::StripCluster();
486 xAODStripContainerFromInDetClusters->push_back(stripCl);
487 if ((convertInDetToXaodCluster(*theCluster, *element, *stripCl))
488 .isFailure()) {
489 ATH_MSG_FATAL("Could not convert InDet strip cluster to xAOD");
490 throw std::runtime_error(
491 "conversion of InDet strip cluster to xAOD failed");
492 }
493 size_t index = xAODStripContainerFromInDetClusters->size() - 1;
494 traccc_to_xaod_cluster_map[Strip_ModuleID.get_compact()] = index;
495
496 nStrip++;
497 }
498 }
499
500 ATH_MSG_DEBUG("Read " << nStrip << " strip clusters");
501
502 return traccc_to_xaod_cluster_map;
503}
504
506 const InDet::PixelCluster& indetCluster,
507 const InDetDD::SiDetectorElement& element, xAOD::PixelCluster& xaodCluster) const
508{
509 IdentifierHash idHash = element.identifyHash();
510
511 auto localPos = indetCluster.localPosition();
512 auto localCov = indetCluster.localCovariance();
513
514 xAOD::MeasVector<2> localPosition = xAOD::toStorage(localPos);
515
516 xAOD::MeasMatrix<2> localCovariance;
517 localCovariance.setZero();
518 localCovariance(0, 0) = localCov(0, 0);
519 localCovariance(1, 1) = localCov(1, 1);
520
521 auto globalPos = indetCluster.globalPosition();
522 Eigen::Matrix<float, 3, 1> globalPosition(globalPos.x(), globalPos.y(),
523 globalPos.z());
524
525 const auto& RDOs = indetCluster.rdoList();
526 const auto& ToTs = indetCluster.totList();
527 const auto& charges = indetCluster.chargeList();
528 const auto& width = indetCluster.width();
529
530 xaodCluster.setMeasurement<2>(idHash, localPosition, localCovariance);
531 xaodCluster.setIdentifier(indetCluster.identify().get_compact());
532 xaodCluster.setRDOlist(RDOs);
533 xaodCluster.globalPosition() = globalPosition;
534 xaodCluster.setToTlist(ToTs);
535 xaodCluster.setChargelist(charges);
536 xaodCluster.setLVL1A(indetCluster.LVL1A());
537 xaodCluster.setChannelsInPhiEta(width.colRow()[0], width.colRow()[1]);
538 xaodCluster.setWidthInEta(static_cast<float>(width.widthPhiRZ()[1]));
539
540 return StatusCode::SUCCESS;
541}
542
544 const InDet::SCT_Cluster& indetCluster,
545 const InDetDD::SiDetectorElement& element, xAOD::StripCluster& xaodCluster) const
546{
547 constexpr double one_over_twelve = 1. / 12.;
548 IdentifierHash idHash = element.identifyHash();
549
550 auto localPos = indetCluster.localPosition();
551
552 xAOD::MeasVector<1> localPosition;
553 xAOD::MeasMatrix<1> localCovariance;
554 localCovariance.setZero();
555
556 if (element.isBarrel()) {
557 localPosition(0, 0) = localPos.x();
558 localCovariance(0, 0) =
559 element.phiPitch() * element.phiPitch() * one_over_twelve;
560 } else {
561 InDetDD::SiCellId cellId = element.cellIdOfPosition(localPos);
563 dynamic_cast<const InDetDD::StripStereoAnnulusDesign*>(
564 &element.design());
565 if (design == nullptr) {
566 return StatusCode::FAILURE;
567 }
568 InDetDD::SiLocalPosition localInPolar =
569 design->localPositionOfCellPC(cellId);
570 localPosition(0, 0) = localInPolar.xPhi();
571 localCovariance(0, 0) =
572 design->phiPitchPhi() * design->phiPitchPhi() * one_over_twelve;
573 }
574
575 auto globalPos = indetCluster.globalPosition();
576 Eigen::Matrix<float, 3, 1> globalPosition(globalPos.x(), globalPos.y(),
577 globalPos.z());
578
579 const auto& RDOs = indetCluster.rdoList();
580 const auto& width = indetCluster.width();
581
582 xaodCluster.setMeasurement<1>(idHash, localPosition, localCovariance);
583 xaodCluster.setIdentifier(indetCluster.identify().get_compact());
584 xaodCluster.setRDOlist(RDOs);
585 xaodCluster.globalPosition() = globalPosition;
586 xaodCluster.setChannelsInPhi(width.colRow()[0]);
587
588 return StatusCode::SUCCESS;
589}
590
592 const Identifier& atlasID) const
593{
594 const bool isPixel = m_pixelID->is_pixel(atlasID);
595 const IdentifierHash hash = isPixel ? m_pixelID->wafer_hash(atlasID)
596 : m_stripID->wafer_hash(atlasID);
597 const auto measType = isPixel ? xAOD::UncalibMeasType::PixelClusterType
599
600 const auto geoKey = ActsTrk::makeDetectorElementKey(
601 measType, static_cast<unsigned int>(hash));
602 const auto it = m_detEleToGeoIdMap->find(geoKey);
603 if (it != m_detEleToGeoIdMap->end()) {
604 const Acts::Surface* surface = m_trackingGeometry->findSurface(
606 if (surface) {
607 return surface;
608 }
609 }
610 ATH_MSG_DEBUG("No Acts surface corresponding to this ATLAS id: " << atlasID);
611 return nullptr;
612}
613
615 const LocalMeasurementInfoInTracks& state) const
616{
617 // traccc's model output is in Acts-native units
618 Acts::BoundMatrix cov = Acts::BoundMatrix::Zero();
619 for (unsigned int i = 0; i < 5; i++) {
620 for (unsigned int j = 0; j < 5; j++) {
621 size_t index = i * 5 + j;
622 cov(i, j) = state.covariances[index];
623 }
624 }
625
626 // traccc does not fit the time parameter (yet). Give it a
627 // large placeholder uncertainty instead of leaving it at zero.
628 constexpr double kUnconstrainedTimeVariance = 1e6;
629 cov(Acts::eBoundTime, Acts::eBoundTime) = kUnconstrainedTimeVariance;
630
631 return cov;
632}
633
634std::optional<Acts::BoundTrackParameters>
636 const LocalMeasurementInfoInTracks& state) const
637{
638 using namespace Acts::UnitLiterals;
639 std::shared_ptr<const Acts::Surface> actsSurface;
640 Acts::BoundVector params;
641
642 Identifier const atlas_ID(static_cast<Identifier::value_type>(state.athena_id[0]));
643
644 // get the associated surface
645 const Acts::Surface* surface = actsSurfaceFromAtlasId(atlas_ID);
646 if (!surface) {
647 return std::nullopt;
648 }
649 actsSurface = surface->getSharedPtr();
650
651 // Construct track parameters
652 ATH_MSG_VERBOSE("Constructing track parameters for this state");
653 params << state.local_x[0], state.local_y[0],
654 state.phi[0], state.theta[0], state.qop[0], state.time[0];
655
656 Acts::BoundMatrix const cov = buildBoundCovariance(state);
657
658 Acts::ParticleHypothesis hypothesis{Acts::ParticleHypothesis::pion()};
659
660 return Acts::BoundTrackParameters(actsSurface, params, cov, hypothesis);
661}
662
664 EventContext const& eventContext,
665 std::vector<TracccTrackParameters>& trackParams,
666 std::vector<LocalMeasurementInfoInTracks>& measInfo,
667 const std::unordered_map<int64_t, int>& cluster_map,
668 unsigned& nb_output_tracks) const
669{
670 nb_output_tracks = 0;
671
672 Acts::VectorTrackContainer track_backend;
673 Acts::VectorMultiTrajectory track_state_backend;
674 ActsTrk::MutableTrackContainer track_container(
675 std::move(track_backend), std::move(track_state_backend));
676
677 SG::WriteHandle<ActsTrk::TrackContainer> trackContainerHandle(
678 m_ActsTracccTrackContainerKey, eventContext);
679
680 Acts::GeometryContext tgContext = m_ctxProvider.getGeometryContext(eventContext);
681
682 if (m_doTruth) {
683 ATH_MSG_DEBUG("Will map truth");
684 ATH_MSG_DEBUG("retrieving cluster container keys: "
687 }
688
689 // Debug stats
690 float chi2_min = std::numeric_limits<float>::max();
691 float chi2_max = std::numeric_limits<float>::min();
692
693 float ndf_min = std::numeric_limits<float>::max();
694 float ndf_max = std::numeric_limits<float>::min();
695
696 unsigned meas_min = std::numeric_limits<unsigned>::max();
697 unsigned meas_max = std::numeric_limits<unsigned>::min();
698
699 int excluded_ndf = 0;
700 int excluded_no_sp = 0;
701 int excluded_weird_state = 0;
702
703 for (std::size_t i = 0; i < trackParams.size(); i++) {
704 auto fit_res = trackParams.at(i);
705 auto& states = measInfo.at(i);
706 if (states.local_x.size() < 1) {
707 excluded_no_sp += 1;
708 continue;
709 }
710
711 // In Acts ndf, aka nDoF, is unsigned int. This makes sure the number is
712 // safe to cast; exclude the track otherwise.
713 if (fit_res.ndf >
714 static_cast<float>(std::numeric_limits<unsigned int>::max()) ||
715 fit_res.ndf <
716 static_cast<float>(std::numeric_limits<unsigned int>::min())) {
717 excluded_ndf += 1;
718 continue;
719 }
720
721 // Create the MutableTrack and add the parameters
722 auto actsTrack = track_container.makeTrack();
723 enum TrackValidity { VALID, INVALID_STATE, INVALID_GLOBAL };
724 TrackValidity track_validity = VALID;
725
726
727 actsTrack.chi2() = fit_res.chi2;
728 actsTrack.nDoF() = fit_res.ndf;
729
730 Acts::TrackStatePropMask const mask =
731 Acts::TrackStatePropMask::Smoothed;
732
733 bool first_state = true;
734 for (size_t j = 0; j < states.local_x.size(); ++j) {
735 auto actsTSOS = actsTrack.appendTrackState(mask);
736
737 // Build a measurement struct for this state
739 singleState.local_x = {states.local_x[j]};
740 singleState.local_y = {states.local_y[j]};
741 singleState.phi = {states.phi[j]};
742 singleState.theta = {states.theta[j]};
743 singleState.qop = {states.qop[j]};
744 singleState.time = {states.time[j]};
745 singleState.covariances = {};
746 for (size_t k = 0; k < 25; ++k) {
747 singleState.covariances.push_back(states.covariances[j * 25 + k]);
748 }
749 singleState.athena_id = {states.athena_id[j]};
750
751 std::optional<Acts::BoundTrackParameters> params_opt =
752 convertToActsParameters(singleState);
753 if (!params_opt.has_value()) {
754 // if the measurement was "buggy", the whole track is dismissed.
756 "convertToActsParameters failed: track state is weird");
757 track_validity = INVALID_STATE;
758 break;
759
760 }
761
762 Acts::BoundTrackParameters const& parameters = params_opt.value();
763 ATH_MSG_DEBUG("Track parameters: " << parameters.parameters());
764
765 if (m_doTruth) {
767 m_xAODPixelClusterFromInDetClusterKey.key(), eventContext);
768 ATH_CHECK(pixelClustersHandle.isValid());
769 const xAOD::PixelClusterContainer* inputPixelClusters =
770 pixelClustersHandle.cptr();
771
773 m_xAODStripClusterFromInDetClusterKey.key(), eventContext);
774 ATH_CHECK(stripClustersHandle.isValid());
775 const xAOD::StripClusterContainer* inputStripClusters =
776 stripClustersHandle.cptr();
777
778 // match measurement to the cluster container
779 int cl_index = -1;
780 if (auto it = cluster_map.find(states.athena_id[j]);
781 it != cluster_map.end()) {
782 cl_index = it->second;
783 } else {
784 return StatusCode::FAILURE;
785 }
786
787 // Determine detector type from athena_id
788 Identifier id(static_cast<Identifier::value_type>(states.athena_id[j]));
789 bool isPixel = m_pixelID->is_pixel(id);
790
791 const xAOD::UncalibratedMeasurement* umeas = nullptr;
792 if (isPixel) {
793 umeas = inputPixelClusters->at(cl_index);
794 } else {
795 umeas = inputStripClusters->at(cl_index);
796 }
797
798 actsTSOS.setUncalibratedSourceLink(
800 }
801
802 // This is the conversion of global track parameters
803 // Because Traccc does not do backpropagation yet,
804 // we do not have the reference surface ie the perigee.
805 // So for now we will set the global track params with
806 // the reference surface being the surface of first measurement
807 // and enable back propagation during ACTS->xAOD conversion
808 // this will find the pergee and re-set the global trk params.
809 if (first_state) {
810 // This is the first track state, so we need to set the track
811 // global parameters
812
813 std::optional<Acts::BoundTrackParameters> params_gl =
814 convertToActsParameters(singleState);
815
816 if (!params_gl.has_value()) {
817 // if the params are "buggy", the whole track is dismissed.
819 "convertToActsParameters failed: track state is weird");
820 track_validity = INVALID_GLOBAL;
821 break;
822 }
823
824 Acts::BoundTrackParameters const& parameters_gl =
825 params_gl.value();
826
827 ATH_MSG_VERBOSE("First state of track.");
828 actsTrack.parameters() = parameters_gl.parameters();
829 actsTrack.covariance() = *parameters_gl.covariance();
830 actsTrack.setReferenceSurface(
831 parameters_gl.referenceSurface().getSharedPtr());
832 first_state = false;
833
834 }
835
836 actsTSOS.setReferenceSurface(
837 parameters.referenceSurface().getSharedPtr());
838 actsTSOS.smoothed() = parameters.parameters();
839 actsTSOS.smoothedCovariance() = *parameters.covariance();
840 // Mark this state as a measurement for temporary efficiency matching
841 actsTSOS.typeFlags().setIsMeasurement();
842 if (!(actsTSOS.hasSmoothed() &&
843 actsTSOS.hasReferenceSurface())) {
845 "TrackState does not have smoothed state ["
846 << actsTSOS.hasSmoothed()
847 << "] or reference surface ["
848 << actsTSOS.hasReferenceSurface() << "].");
849 } else {
851 "TrackState has smoothed state and reference "
852 "surface.");
853 }
854 }
855
856 // ATH_MSG_INFO("Done with states of this track.");
857 if (track_validity == INVALID_STATE) {
858 ATH_MSG_INFO("excluding track " << i << " for weird state");
859 excluded_weird_state += 1;
860 track_container.removeTrack(actsTrack.index());
861 } else if (track_validity == INVALID_GLOBAL) {
862 ATH_MSG_INFO("excluding track " << i
863 << " for weird global params");
864 track_container.removeTrack(actsTrack.index());
865 }
866
867
868 // Debug stats
869 chi2_min = std::min(fit_res.chi2, chi2_min);
870 chi2_max = std::max(fit_res.chi2, chi2_max);
871 ndf_min = std::min(fit_res.ndf, ndf_min);
872 ndf_max = std::max(fit_res.ndf, ndf_max);
873 meas_min = std::min<unsigned>(states.local_x.size(), meas_min);
874 meas_max = std::max<unsigned>(states.local_x.size(), meas_max);
875 }
876
877 nb_output_tracks = track_container.size();
878 ATH_MSG_DEBUG("Wrote out "<< nb_output_tracks << " tracks from " << trackParams.size() << " candidates"
879 << ", excluded:"
880 << " no sp: " << excluded_no_sp
881 << ", weird sp: " << excluded_weird_state
882 << ", ndf: " << excluded_ndf
883 );
884
885 Acts::ConstVectorTrackContainer ctrack_backend(
886 std::move(track_container.container()));
887 Acts::ConstVectorMultiTrajectory ctrack_state_backend(
888 std::move(track_container.trackStateContainer()));
889 std::unique_ptr<ActsTrk::TrackContainer> ctrack_container =
890 std::make_unique<ActsTrk::TrackContainer>(
891 std::move(ctrack_backend), std::move(ctrack_state_backend));
892
893 ATH_CHECK(trackContainerHandle.record(std::move(ctrack_container)));
894
895 return StatusCode::SUCCESS;
896}
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
static constexpr double one_over_twelve
InDetRawDataContainer< InDetRawDataCollection< PixelRDORawData > > PixelRDO_Container
InDetRawDataContainer< InDetRawDataCollection< SCT_RDORawData > > SCT_RDO_Container
const double width
static Acts::SourceLink pack(const Ptr_t &measurement)
Pack the measurement type pointer to an Acts::SourceLink including the intermediate conversion into a...
const ServiceHandle< StoreGateSvc > & detStore() const
const T * at(size_type n) const
Access an element, as an rvalue.
This is a "hash" representation of an Identifier.
value_type get_compact() const
Get the compact id.
Class used to describe the design of a module (diode segmentation and readout scheme).
int columns() const
Number of cell columns per module:
int rows() const
Number of cell rows per module:
Identifier for the strip or pixel cell.
Definition SiCellId.h:29
Class to hold the SiDetectorElement objects to be put in the detector store.
Class to hold geometrical description of a silicon detector element.
virtual SiCellId cellIdFromIdentifier(const Identifier &identifier) const override final
SiCellId from Identifier.
virtual const SiDetectorDesign & design() const override final
access to the local description (inline):
double phiPitch() const
Pitch (inline methods).
Class to represent a position in the natural frame of a silicon sensor, for Pixel and SCT For Pixel: ...
double xPhi() const
position along phi direction:
SiCellId cellIdOfPosition(const Amg::Vector2D &localPos) const
As in previous method but returns SiCellId.
virtual IdentifierHash identifyHash() const override final
identifier hash (inline)
virtual Identifier identify() const override final
identifier of this detector element (inline)
double phiPitchPhi(const SiLocalPosition &localPosition) const
SiLocalPosition localPositionOfCellPC(const SiCellId &cellId) const
This is for debugging only.
const Amg::Vector3D & globalPosition() const
return global position reference
const InDet::SiWidth & width() const
return width class reference
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
SG::ReadHandleKey< InDet::SCT_ClusterContainer > m_inputStripClusterContainerKey
const Acts::Surface * actsSurfaceFromAtlasId(const Identifier &atlasID) const
Acts::BoundMatrix buildBoundCovariance(const LocalMeasurementInfoInTracks &state) const
ServiceHandle< ActsTrk::ITrackingGeometrySvc > m_trackingGeometrySvc
const InDetDD::PixelDetectorManager * m_pixelManager
std::shared_ptr< const Acts::TrackingGeometry > m_trackingGeometry
StatusCode convertInDetToXaodCluster(const InDet::PixelCluster &indetCluster, const InDetDD::SiDetectorElement &element, xAOD::PixelCluster &xaodCluster) const
ActsTrk::MutableTrackContainerHandlesHelper m_tracksBackendHandlesHelper
std::unordered_map< int64_t, int > readAndConvertClusters(const EventContext &eventContext) const
StatusCode read_cells(std::vector< TracccCell > &cells, const EventContext &evtcontext) const
StatusCode convertTracks(EventContext const &eventContext, std::vector< TracccTrackParameters > &trackParams, std::vector< LocalMeasurementInfoInTracks > &measInfo, const std::unordered_map< int64_t, int > &cluster_map, unsigned &nb_output_tracks) const
const InDetDD::SCT_DetectorManager * m_stripManager
SG::WriteHandleKey< xAOD::SpacePointContainer > m_xAODSpacepointFromInDetClusterKey
SG::ReadHandleKey< PixelRDO_Container > m_pixelRDOKey
SG::WriteHandleKey< ActsTrk::TrackContainer > m_ActsTracccTrackContainerKey
SG::ReadHandleKey< SCT_RDO_Container > m_stripRDOKey
SG::ReadHandleKey< InDet::PixelClusterContainer > m_inputPixelClusterContainerKey
ActsTrk::ContextUtility m_ctxProvider
Utility to fetch the geometry, magnetic field and calibration context in the event.
SG::ReadHandleKey< ActsTrk::MeasurementToTruthParticleAssociation > m_stripClustersToTruth
const ActsTrk::DetectorElementToActsGeometryIdMap * m_detEleToGeoIdMap
virtual StatusCode execute(const EventContext &ctx) const override
SG::WriteHandleKey< xAOD::PixelClusterContainer > m_xAODPixelClusterFromInDetClusterKey
SG::ReadCondHandleKey< InDetDD::SiDetectorElementCollection > m_stripDetEleCollKey
std::optional< Acts::BoundTrackParameters > convertToActsParameters(const LocalMeasurementInfoInTracks &state) const
SG::ReadCondHandleKey< InDetDD::SiDetectorElementCollection > m_pixelDetEleCollKey
std::vector< int > map_index(int index, int low_bound, int high_bound, int threshold, int shift) const
Gaudi::Property< bool > m_doTruth
Truth association for plotting and debugging.
virtual StatusCode initialize() override
std::vector< std::string > m_featureNamesVec
std::vector< std::pair< int, int > > correct_indices(int phiIndex, int etaIndex, int rows, int columns) const
SG::ReadHandleKey< ActsTrk::MeasurementToTruthParticleAssociation > m_pixelClustersToTruth
SG::WriteHandleKey< xAOD::StripClusterContainer > m_xAODStripClusterFromInDetClusterKey
ToolHandle< ITracccTritonTool > m_tracccTrackingTool
const Amg::Vector2D & localPosition() const
return the local position reference
Identifier identify() const
return the identifier
const Amg::MatrixX & localCovariance() const
return const ref to the error matrix
const std::vector< Identifier > & rdoList() const
return the List of rdo identifiers (pointers)
void setChannelsInPhiEta(int channelsInPhi, int channelsInEta)
Sets the dimensions of the cluster in numbers of channels in phi (x) and eta (y) directions.
ConstVectorMap< 3 > globalPosition() const
Returns the global position of the pixel cluster.
void setChargelist(const std::vector< float > &charges)
Sets the list of charges of the channels building the cluster.
void setToTlist(const std::vector< int > &tots)
Sets the list of ToT of the channels building the cluster.
void setLVL1A(int lvl1a)
Sets the LVL1 accept.
void setRDOlist(const std::vector< Identifier > &rdolist)
Sets the list of identifiers of the channels building the cluster.
void setWidthInEta(float widthInEta)
Sets the width of the cluster in eta (y) direction.
ConstVectorMap< 3 > globalPosition() const
Returns the global position of the strip cluster.
void setRDOlist(const std::vector< Identifier > &rdolist)
Sets the list of identifiers of the channels building the cluster.
void setChannelsInPhi(int channelsInPhi)
Sets the dimensions of the cluster in numbers of channels in phi (x).
void setMeasurement(const DetectorIDHashType idHash, MeasVector< N > locPos, MeasMatrix< N > locCov)
Sets IdentifierHash, local position and local covariance of the measurement.
void setIdentifier(const DetectorIdentType measId)
Sets the full Identifier of the measurement.
std::string prefixFromTrackContainerName(const std::string &tracks)
Parse TrackContainer name to get the prefix for backends The name has to contain XYZTracks,...
Acts::TrackContainer< MutableTrackBackend, MutableTrackStateBackend, Acts::detail::ValueHolder > MutableTrackContainer
DetectorElementKey makeDetectorElementKey(xAOD::UncalibMeasType meas_type, unsigned int identifier_hash)
std::vector< std::string > tokenize(std::string_view the_str, std::string_view delimiters)
Splits the string into smaller substrings.
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
Definition index.py:1
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
PixelClusterContainer_v1 PixelClusterContainer
Define the version of the pixel cluster container.
StripCluster_v1 StripCluster
Define the version of the strip cluster class.
Eigen::Matrix< float, N, N > MeasMatrix
UncalibratedMeasurement_v1 UncalibratedMeasurement
Define the version of the uncalibrated measurement class.
Eigen::Matrix< float, N, 1 > MeasVector
Abrivation of the Matrix & Covariance definitions.
StripClusterContainer_v1 StripClusterContainer
Define the version of the strip cluster container.
MeasVector< N > toStorage(const AmgVector(N)&amgVec)
Converts the double precision of the AmgVector into the floating point storage precision of the MeasV...
PixelCluster_v1 PixelCluster
Define the version of the pixel cluster class.
static const Acts::GeometryIdentifier & getValue(const value_type &element)
std::vector< int64_t > athena_id
std::vector< float > covariances
bool operator()(const TracccCell &lhs, const TracccCell &rhs) const