|
28 | 28 | #include <Acts/Seeding/detail/CylindricalSpacePointGrid.hpp> |
29 | 29 | #include <Acts/Utilities/GridBinFinder.hpp> |
30 | 30 | #include <Acts/Utilities/RangeXD.hpp> |
| 31 | +#include <Acts/Definitions/TrackParametrization.hpp> |
| 32 | +#include <Acts/Seeding/EstimateTrackParamsFromSeed.hpp> |
31 | 33 |
|
32 | 34 | namespace o2::trk |
33 | 35 | { |
@@ -238,17 +240,143 @@ void TrackerACTS<nLayers>::createSeeds() |
238 | 240 | template <int nLayers> |
239 | 241 | bool TrackerACTS<nLayers>::estimateTrackParams(const SeedACTS& seed, o2::its::TrackITSExt& track) const |
240 | 242 | { |
| 243 | + const SpacePoint* sp0 = seed.bottom; |
| 244 | + const SpacePoint* sp1 = seed.middle; |
| 245 | + const SpacePoint* sp2 = seed.top; |
| 246 | + |
| 247 | + // Use ACTS parameter estimation |
| 248 | + Acts::Vector3 pos0{sp0->x, sp0->y, sp0->z}; |
| 249 | + Acts::Vector3 pos1{sp1->x, sp1->y, sp1->z}; |
| 250 | + Acts::Vector3 pos2{sp2->x, sp2->y, sp2->z}; |
| 251 | + |
| 252 | + // Magnetic field vector (along z-axis) |
| 253 | + Acts::Vector3 bField{0., 0., mBz * Acts::UnitConstants::T}; |
| 254 | + |
| 255 | + // Use the ACTS function with time parameter (t0 = 0) |
| 256 | + LOG(info) << "Calling ACTS estimateTrackParamsFromSeed with mag field " << mBz << " T"; |
| 257 | + LOG(info) << "Seed space points: (" << pos0.transpose() << "), (" << pos1.transpose() << "), (" << pos2.transpose() << ")"; |
| 258 | + |
| 259 | + Acts::FreeVector params; |
| 260 | + try { |
| 261 | + params = Acts::estimateTrackParamsFromSeed(pos0, 0.0, pos1, pos2, bField); |
| 262 | + } catch (const std::exception& e) { |
| 263 | + LOG(fatal) << "ACTS parameter estimation failed: " << e.what(); |
| 264 | + return false; |
| 265 | + } |
| 266 | + LOG(info) << "ACTS parameter estimation successful: x=" << params[Acts::eFreePos0] << " y=" << params[Acts::eFreePos1] |
| 267 | + << " z=" << params[Acts::eFreePos2] << " q/p=" << params[Acts::eFreeQOverP]; |
| 268 | + |
| 269 | + // Extract parameters from ACTS format |
| 270 | + const auto& p = params; |
| 271 | + // ACTS FreeVector: x, y, z, t, dir_x, dir_y, dir_z, q/|p| |
| 272 | + // Direction components are normalized (unit vector) |
| 273 | + float x = p[Acts::eFreePos0]; |
| 274 | + float y = p[Acts::eFreePos1]; |
| 275 | + float z = p[Acts::eFreePos2]; |
| 276 | + float qOverP = p[Acts::eFreeQOverP]; |
| 277 | + float pMag = 1.0f / std::abs(qOverP); // |p| = 1 / |q/p| (for unit charge) |
| 278 | + float px = p[Acts::eFreeDir0] * pMag; |
| 279 | + float py = p[Acts::eFreeDir1] * pMag; |
| 280 | + float pz = p[Acts::eFreeDir2] * pMag; |
| 281 | + |
| 282 | + // Calculate track parameters in O2 format |
| 283 | + float pt = std::hypot(px, py); |
| 284 | + float phi = std::atan2(py, px); |
| 285 | + float theta = std::atan2(pt, pz); |
| 286 | + float eta = -std::log(std::tan(theta / 2.0f)); |
| 287 | + |
| 288 | + // Set cluster indices from seed |
| 289 | + track.setExternalClusterIndex(sp0->layer, sp0->clusterId); |
| 290 | + track.setExternalClusterIndex(sp1->layer, sp1->clusterId); |
| 291 | + track.setExternalClusterIndex(sp2->layer, sp2->clusterId); |
| 292 | + |
| 293 | + // Set track parameters |
| 294 | + track.setX(x); |
| 295 | + track.setAlpha(phi); |
| 296 | + track.setY(y * std::cos(phi) - x * std::sin(phi)); |
| 297 | + track.setZ(z); |
| 298 | + track.setSnp(std::sin(phi - track.getAlpha())); |
| 299 | + track.setTgl(std::tan(o2::constants::math::PIHalf - theta)); |
| 300 | + |
| 301 | + // q/pT = q/|p| * |p|/pT = qOverP * |p| / pT = qOverP / (pT / |p|) = qOverP / sin(theta) |
| 302 | + // Or simply: charge / pT where charge = sign(qOverP) |
| 303 | + float charge = (qOverP > 0) ? 1.0f : -1.0f; |
| 304 | + track.setQ2Pt(charge / pt); |
| 305 | + |
| 306 | + LOG(info) << "Estimated track parameters"; |
241 | 307 | return true; |
242 | 308 | } |
243 | 309 |
|
244 | 310 | template <int nLayers> |
245 | 311 | void TrackerACTS<nLayers>::findTracks() |
246 | 312 | { |
| 313 | + return; // For now we only create seeds, track finding and fitting will be implemented in the next iterations |
| 314 | + int nTracks = 0; |
| 315 | + |
| 316 | + for (const auto& seed : mSeeds) { |
| 317 | + o2::its::TrackITSExt track; |
| 318 | + |
| 319 | + LOG(info) << "Estimating track parameters for seed with quality (pT) = " << seed.quality; |
| 320 | + if (!estimateTrackParams(seed, track)) { |
| 321 | + continue; |
| 322 | + } |
| 323 | + |
| 324 | + // Add track to TimeFrame |
| 325 | + const int rof = seed.middle->rof; |
| 326 | + if (mTimeFrame && rof >= 0 && rof < mTimeFrame->getNrof(0)) { |
| 327 | + LOG(info) << "Adding track to ROF " << rof; |
| 328 | + auto& tracks = mTimeFrame->getTracks(); |
| 329 | + // tracks.emplace_back(track); |
| 330 | + ++nTracks; |
| 331 | + } |
| 332 | + } |
| 333 | + LOG(info) << "Created " << nTracks << " tracks from " << mSeeds.size() << " seeds"; |
247 | 334 | } |
248 | 335 |
|
249 | 336 | template <int nLayers> |
250 | 337 | void TrackerACTS<nLayers>::computeTracksMClabels() |
251 | 338 | { |
| 339 | + return; // For now we skip MC labeling, will be implemented in the next iterations once we have track candidates to label |
| 340 | + if (!mTimeFrame || !mTimeFrame->hasMCinformation()) { |
| 341 | + return; |
| 342 | + } |
| 343 | + |
| 344 | + // MC labeling using majority voting on cluster labels |
| 345 | + for (int iROF = 0; iROF < mTimeFrame->getNrof(0); ++iROF) { |
| 346 | + for (auto& track : mTimeFrame->getTracks()) { |
| 347 | + std::vector<std::pair<MCCompLabel, size_t>> labelCounts; |
| 348 | + |
| 349 | + for (int iCluster = 0; iCluster < o2::its::TrackITSExt::MaxClusters; ++iCluster) { |
| 350 | + const int clusterIdx = track.getClusterIndex(iCluster); |
| 351 | + if (clusterIdx == o2::its::constants::UnusedIndex) { |
| 352 | + continue; |
| 353 | + } |
| 354 | + |
| 355 | + auto clusterLabels = mTimeFrame->getClusterLabels(iCluster, clusterIdx); |
| 356 | + for (const auto& label : clusterLabels) { |
| 357 | + auto it = std::find_if(labelCounts.begin(), labelCounts.end(), |
| 358 | + [&label](const auto& p) { return p.first == label; }); |
| 359 | + if (it != labelCounts.end()) { |
| 360 | + ++(it->second); |
| 361 | + } else { |
| 362 | + labelCounts.emplace_back(label, 1); |
| 363 | + } |
| 364 | + } |
| 365 | + } |
| 366 | + |
| 367 | + if (!labelCounts.empty()) { |
| 368 | + // Find label with most occurrences |
| 369 | + auto maxIt = std::max_element(labelCounts.begin(), labelCounts.end(), |
| 370 | + [](const auto& a, const auto& b) { return a.second < b.second; }); |
| 371 | + |
| 372 | + MCCompLabel trackLabel = maxIt->first; |
| 373 | + if (maxIt->second < static_cast<size_t>(track.getNumberOfClusters())) { |
| 374 | + trackLabel.setFakeFlag(); |
| 375 | + } |
| 376 | + mTimeFrame->getTracksLabel().emplace_back(trackLabel); |
| 377 | + } |
| 378 | + } |
| 379 | + } |
252 | 380 | } |
253 | 381 |
|
254 | 382 | template <int nLayers> |
|
0 commit comments