Warning, file /EICrecon/src/algorithms/tracking/TrackSeeding.cc was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004 #include "TrackSeeding.h"
0005
0006 #include <Acts/Definitions/Algebra.hpp>
0007 #include <Acts/Definitions/Units.hpp>
0008 #include <Acts/EventData/Seed.hpp>
0009 #include <Acts/EventData/SpacePointProxy.hpp>
0010 #include <Acts/Seeding/SeedConfirmationRangeConfig.hpp>
0011 #include <Acts/Seeding/SeedFilter.hpp>
0012 #include <Acts/Seeding/SeedFilterConfig.hpp>
0013 #include <Acts/Seeding/SeedFinderConfig.hpp>
0014 #include <Acts/Seeding/SeedFinderOrthogonal.hpp>
0015 #include <Acts/Seeding/SeedFinderOrthogonalConfig.hpp>
0016 #include <Acts/Seeding/SeedFinderUtils.hpp>
0017 #include <Acts/Surfaces/PerigeeSurface.hpp>
0018 #include <Acts/Surfaces/Surface.hpp>
0019 #include <Acts/Utilities/KDTree.hpp> // IWYU pragma: keep FIXME KDTree missing in SeedFinderOrthogonal.hpp until Acts v23.0.0
0020 #include <Acts/Utilities/Result.hpp>
0021 #include <edm4eic/Cov6f.h>
0022 #include <edm4eic/EDM4eicVersion.h>
0023 #include <edm4hep/Vector2f.h>
0024 #include <edm4hep/Vector3f.h>
0025 #include <Eigen/Core>
0026 #include <Eigen/Geometry>
0027 #include <array>
0028 #include <cmath>
0029 #include <limits>
0030 #include <tuple>
0031
0032 namespace eicrecon {
0033
0034 void TrackSeeding::init() {
0035
0036
0037 m_seedFilterConfig.maxSeedsPerSpM = m_cfg.maxSeedsPerSpM_filter;
0038 m_seedFilterConfig.deltaRMin = m_cfg.deltaRMin;
0039 m_seedFilterConfig.seedConfirmation = m_cfg.seedConfirmation;
0040 m_seedFilterConfig.deltaInvHelixDiameter = m_cfg.deltaInvHelixDiameter;
0041 m_seedFilterConfig.impactWeightFactor = m_cfg.impactWeightFactor;
0042 m_seedFilterConfig.zOriginWeightFactor = m_cfg.zOriginWeightFactor;
0043 m_seedFilterConfig.compatSeedWeight = m_cfg.compatSeedWeight;
0044 m_seedFilterConfig.compatSeedLimit = m_cfg.compatSeedLimit;
0045 m_seedFilterConfig.seedWeightIncrement = m_cfg.seedWeightIncrement;
0046
0047 m_seedFilterConfig.centralSeedConfirmationRange = Acts::SeedConfirmationRangeConfig{
0048 .zMinSeedConf = m_cfg.zMinSeedConfCentral,
0049 .zMaxSeedConf = m_cfg.zMaxSeedConfCentral,
0050 .rMaxSeedConf = m_cfg.rMaxSeedConfCentral,
0051 .nTopForLargeR = m_cfg.nTopForLargeRCentral,
0052 .nTopForSmallR = m_cfg.nTopForSmallRCentral,
0053 .seedConfMinBottomRadius = m_cfg.seedConfMinBottomRadiusCentral,
0054 .seedConfMaxZOrigin = m_cfg.seedConfMaxZOriginCentral,
0055 .minImpactSeedConf = m_cfg.minImpactSeedConfCentral};
0056
0057 m_seedFilterConfig.forwardSeedConfirmationRange = Acts::SeedConfirmationRangeConfig{
0058 .zMinSeedConf = m_cfg.zMinSeedConfForward,
0059 .zMaxSeedConf = m_cfg.zMaxSeedConfForward,
0060 .rMaxSeedConf = m_cfg.rMaxSeedConfForward,
0061 .nTopForLargeR = m_cfg.nTopForLargeRForward,
0062 .nTopForSmallR = m_cfg.nTopForSmallRForward,
0063 .seedConfMinBottomRadius = m_cfg.seedConfMinBottomRadiusForward,
0064 .seedConfMaxZOrigin = m_cfg.seedConfMaxZOriginForward,
0065 .minImpactSeedConf = m_cfg.minImpactSeedConfForward};
0066
0067
0068 m_seedFinderConfig.seedFilter =
0069 std::make_unique<Acts::SeedFilter<proxy_type>>(m_seedFilterConfig);
0070 m_seedFinderConfig.rMax = m_cfg.rMax;
0071 m_seedFinderConfig.rMin = m_cfg.rMin;
0072 m_seedFinderConfig.deltaRMinTopSP = m_cfg.deltaRMinTopSP;
0073 m_seedFinderConfig.deltaRMaxTopSP = m_cfg.deltaRMaxTopSP;
0074 m_seedFinderConfig.deltaRMinBottomSP = m_cfg.deltaRMinBottomSP;
0075 m_seedFinderConfig.deltaRMaxBottomSP = m_cfg.deltaRMaxBottomSP;
0076 m_seedFinderConfig.collisionRegionMin = m_cfg.collisionRegionMin;
0077 m_seedFinderConfig.collisionRegionMax = m_cfg.collisionRegionMax;
0078 m_seedFinderConfig.zMin = m_cfg.zMin;
0079 m_seedFinderConfig.zMax = m_cfg.zMax;
0080 m_seedFinderConfig.maxSeedsPerSpM = m_cfg.maxSeedsPerSpM;
0081 m_seedFinderConfig.cotThetaMax = m_cfg.cotThetaMax;
0082 m_seedFinderConfig.sigmaScattering = m_cfg.sigmaScattering;
0083 m_seedFinderConfig.radLengthPerSeed = m_cfg.radLengthPerSeed;
0084 m_seedFinderConfig.minPt = m_cfg.minPt;
0085 m_seedFinderConfig.impactMax = m_cfg.impactMax;
0086 m_seedFinderConfig.rMinMiddle = m_cfg.rMinMiddle;
0087 m_seedFinderConfig.rMaxMiddle = m_cfg.rMaxMiddle;
0088 m_seedFinderConfig.deltaPhiMax = m_cfg.deltaPhiMax;
0089
0090 m_seedFinderOptions.beamPos = Acts::Vector2(m_cfg.beamPosX, m_cfg.beamPosY);
0091 m_seedFinderOptions.bFieldInZ = m_cfg.bFieldInZ;
0092
0093 m_seedFinderConfig = m_seedFinderConfig.calculateDerivedQuantities();
0094 m_seedFinderOptions = m_seedFinderOptions.calculateDerivedQuantities(m_seedFinderConfig);
0095 }
0096
0097 void TrackSeeding::process(const Input& input, const Output& output) const {
0098
0099 const auto [trk_hits] = input;
0100 auto [trk_seeds, trk_params] = output;
0101
0102 std::vector<const eicrecon::SpacePoint*> spacePoints = getSpacePoints(*trk_hits);
0103
0104 Acts::SeedFinderOrthogonal<proxy_type> finder(m_seedFinderConfig);
0105
0106
0107 Acts::SpacePointContainerConfig spConfig;
0108
0109
0110 Acts::SpacePointContainerOptions spOptions;
0111 spOptions.beamPos = {0., 0.};
0112
0113 SpacePointContainerType container(spacePoints);
0114 Acts::SpacePointContainer<decltype(container), Acts::detail::RefHolder> spContainer(
0115 spConfig, spOptions, container);
0116
0117 std::vector<Acts::Seed<proxy_type>> seeds = finder.createSeeds(m_seedFinderOptions, spContainer);
0118
0119
0120 for (const auto& seed : seeds) {
0121 const auto& sps = seed.sp();
0122
0123 auto seedToAdd = Acts::Seed<eicrecon::SpacePoint>(*sps[0]->externalSpacePoint(),
0124 *sps[1]->externalSpacePoint(),
0125 *sps[2]->externalSpacePoint());
0126 seedToAdd.setVertexZ(seed.z());
0127 seedToAdd.setQuality(seed.seedQuality());
0128
0129
0130 auto trackParams = estimateTrackParamsFromSeed(seedToAdd);
0131 if (!trackParams.has_value()) {
0132 debug("Failed to estimate track parameters from seed");
0133 continue;
0134 }
0135 trk_params->push_back(trackParams.value());
0136
0137
0138 auto trk_seed = trk_seeds->create();
0139 trk_seed.setPerigee({0.f, 0.f, 0.f});
0140 #if EDM4EIC_VERSION_MAJOR > 8 || (EDM4EIC_VERSION_MAJOR == 8 && EDM4EIC_VERSION_MINOR > 5)
0141 trk_seed.setQuality(seedToAdd.seedQuality());
0142 #endif
0143 trk_seed.setParams(trackParams.value());
0144 trk_seed.addToHits(*sps[0]->externalSpacePoint());
0145 trk_seed.addToHits(*sps[1]->externalSpacePoint());
0146 trk_seed.addToHits(*sps[2]->externalSpacePoint());
0147 }
0148
0149 for (auto& sp : spacePoints) {
0150 delete sp;
0151 }
0152 }
0153
0154 std::vector<const eicrecon::SpacePoint*>
0155 TrackSeeding::getSpacePoints(const edm4eic::TrackerHitCollection& trk_hits) {
0156 std::vector<const eicrecon::SpacePoint*> spacepoints;
0157
0158 for (const auto hit : trk_hits) {
0159 const eicrecon::SpacePoint* sp = new SpacePoint(hit);
0160 spacepoints.push_back(sp);
0161 }
0162
0163 return spacepoints;
0164 }
0165
0166 std::optional<edm4eic::MutableTrackParameters>
0167 TrackSeeding::estimateTrackParamsFromSeed(const Acts::Seed<SpacePoint>& seed) const {
0168 std::vector<std::pair<float, float>> xyHitPositions;
0169 std::vector<std::pair<float, float>> rzHitPositions;
0170 for (const auto& spptr : seed.sp()) {
0171 xyHitPositions.emplace_back(spptr->x(), spptr->y());
0172 rzHitPositions.emplace_back(spptr->r(), spptr->z());
0173 }
0174
0175 auto RX0Y0 = circleFit(xyHitPositions);
0176 float R = std::get<0>(RX0Y0);
0177 float X0 = std::get<1>(RX0Y0);
0178 float Y0 = std::get<2>(RX0Y0);
0179 if (!(std::isfinite(R) && std::isfinite(std::abs(X0)) && std::isfinite(std::abs(Y0)))) {
0180
0181 return {};
0182 }
0183 if (std::hypot(X0, Y0) < std::numeric_limits<decltype(std::hypot(X0, Y0))>::epsilon() ||
0184 !std::isfinite(std::hypot(X0, Y0))) {
0185
0186
0187 return {};
0188 }
0189
0190 auto slopeZ0 = lineFit(rzHitPositions);
0191 const auto xypos = findPCA(RX0Y0);
0192
0193
0194 int charge = determineCharge(xyHitPositions, xypos, RX0Y0);
0195
0196 float theta = atan(1. / std::get<0>(slopeZ0));
0197
0198 if (theta < 0) {
0199 theta += M_PI;
0200 }
0201 float eta = -log(tan(theta / 2.));
0202 float pt = R * m_cfg.bFieldInZ;
0203 float p = pt * cosh(eta);
0204 float qOverP = charge / p;
0205
0206
0207 auto xpos = xypos.first;
0208 auto ypos = xypos.second;
0209
0210 auto vxpos = -1. * charge * (ypos - Y0);
0211 auto vypos = charge * (xpos - X0);
0212
0213 auto phi = atan2(vypos, vxpos);
0214
0215 const float z0 = seed.z();
0216 auto perigee = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3(0, 0, 0));
0217 Acts::Vector3 global(xypos.first, xypos.second, z0);
0218
0219
0220 Acts::Vector2 localpos;
0221 Acts::Vector3 direction(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
0222
0223 auto local = perigee->globalToLocal(m_geoSvc->getActsGeometryContext(), global, direction);
0224
0225 if (!local.ok()) {
0226 return {};
0227 }
0228
0229 localpos = local.value();
0230
0231 auto trackparam = edm4eic::MutableTrackParameters();
0232 trackparam.setType(-1);
0233 trackparam.setLoc(
0234 {static_cast<float>(localpos(0)), static_cast<float>(localpos(1))});
0235 trackparam.setPhi(static_cast<float>(phi));
0236 trackparam.setTheta(theta);
0237 trackparam.setQOverP(qOverP);
0238 trackparam.setTime(10);
0239 edm4eic::Cov6f cov;
0240 cov(0, 0) = m_cfg.locaError / Acts::UnitConstants::mm;
0241 cov(1, 1) = m_cfg.locbError / Acts::UnitConstants::mm;
0242 cov(2, 2) = m_cfg.phiError / Acts::UnitConstants::rad;
0243 cov(3, 3) = m_cfg.thetaError / Acts::UnitConstants::rad;
0244 cov(4, 4) = m_cfg.qOverPError * Acts::UnitConstants::GeV;
0245 cov(5, 5) = m_cfg.timeError / Acts::UnitConstants::ns;
0246 trackparam.setCovariance(cov);
0247
0248 return trackparam;
0249 }
0250
0251 std::pair<float, float> TrackSeeding::findPCA(std::tuple<float, float, float>& circleParams) {
0252 const float R = std::get<0>(circleParams);
0253 const float X0 = std::get<1>(circleParams);
0254 const float Y0 = std::get<2>(circleParams);
0255
0256 const double R0 = std::hypot(X0, Y0);
0257
0258
0259 const double xmin = X0 * (1. - R / R0);
0260 const double ymin = Y0 * (1. - R / R0);
0261
0262 return std::make_pair(xmin, ymin);
0263 }
0264
0265 int TrackSeeding::determineCharge(std::vector<std::pair<float, float>>& positions,
0266 const std::pair<float, float>& PCA,
0267 std::tuple<float, float, float>& RX0Y0) {
0268
0269 const auto& firstpos = positions.at(0);
0270 auto hit_x = firstpos.first;
0271 auto hit_y = firstpos.second;
0272
0273 auto xpos = PCA.first;
0274 auto ypos = PCA.second;
0275
0276 float X0 = std::get<1>(RX0Y0);
0277 float Y0 = std::get<2>(RX0Y0);
0278
0279 Acts::Vector3 B_z(0, 0, 1);
0280 Acts::Vector3 radial(X0 - xpos, Y0 - ypos, 0);
0281 Acts::Vector3 hit(hit_x - xpos, hit_y - ypos, 0);
0282
0283 auto cross = radial.cross(hit);
0284
0285 float dot = cross.dot(B_z);
0286
0287 return copysign(1., -dot);
0288 }
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302 std::tuple<float, float, float>
0303 TrackSeeding::circleFit(std::vector<std::pair<float, float>>& positions) {
0304
0305 double meanX = 0;
0306 double meanY = 0;
0307 double weight = 0;
0308
0309 for (const auto& [x, y] : positions) {
0310 meanX += x;
0311 meanY += y;
0312 ++weight;
0313 }
0314 meanX /= weight;
0315 meanY /= weight;
0316
0317
0318
0319 double Mxx = 0;
0320 double Myy = 0;
0321 double Mxy = 0;
0322 double Mxz = 0;
0323 double Myz = 0;
0324 double Mzz = 0;
0325
0326 for (auto& [x, y] : positions) {
0327 double Xi = x - meanX;
0328 double Yi = y - meanY;
0329 double Zi = std::pow(Xi, 2) + std::pow(Yi, 2);
0330
0331 Mxy += Xi * Yi;
0332 Mxx += Xi * Xi;
0333 Myy += Yi * Yi;
0334 Mxz += Xi * Zi;
0335 Myz += Yi * Zi;
0336 Mzz += Zi * Zi;
0337 }
0338 Mxx /= weight;
0339 Myy /= weight;
0340 Mxy /= weight;
0341 Mxz /= weight;
0342 Myz /= weight;
0343 Mzz /= weight;
0344
0345
0346
0347 const double Mz = Mxx + Myy;
0348 const double Cov_xy = Mxx * Myy - Mxy * Mxy;
0349 const double Var_z = Mzz - Mz * Mz;
0350 const double A3 = 4 * Mz;
0351 const double A2 = -3 * Mz * Mz - Mzz;
0352 const double A1 = Var_z * Mz + 4 * Cov_xy * Mz - Mxz * Mxz - Myz * Myz;
0353 const double A0 = Mxz * (Mxz * Myy - Myz * Mxy) + Myz * (Myz * Mxx - Mxz * Mxy) - Var_z * Cov_xy;
0354 const double A22 = A2 + A2;
0355 const double A33 = A3 + A3 + A3;
0356
0357
0358
0359
0360 static constexpr int iter_max = 99;
0361 double x = 0;
0362 double y = A0;
0363
0364
0365 for (int iter = 0; iter < iter_max; ++iter) {
0366 const double Dy = A1 + x * (A22 + A33 * x);
0367 const double xnew = x - y / Dy;
0368 if ((xnew == x) || (!std::isfinite(xnew))) {
0369 break;
0370 }
0371
0372 const double ynew = A0 + xnew * (A1 + xnew * (A2 + xnew * A3));
0373 if (std::abs(ynew) >= std::abs(y)) {
0374 break;
0375 }
0376
0377 x = xnew;
0378 y = ynew;
0379 }
0380
0381
0382 const double DET = std::pow(x, 2) - x * Mz + Cov_xy;
0383 const double Xcenter = (Mxz * (Myy - x) - Myz * Mxy) / DET / 2;
0384 const double Ycenter = (Myz * (Mxx - x) - Mxz * Mxy) / DET / 2;
0385
0386
0387 float X0 = Xcenter + meanX;
0388 float Y0 = Ycenter + meanY;
0389 float R = std::sqrt(std::pow(Xcenter, 2) + std::pow(Ycenter, 2) + Mz);
0390 return std::make_tuple(R, X0, Y0);
0391 }
0392
0393 std::tuple<float, float> TrackSeeding::lineFit(std::vector<std::pair<float, float>>& positions) {
0394 double xsum = 0;
0395 double x2sum = 0;
0396 double ysum = 0;
0397 double xysum = 0;
0398 for (const auto& [r, z] : positions) {
0399 xsum = xsum + r;
0400 ysum = ysum + z;
0401 x2sum = x2sum + std::pow(r, 2);
0402 xysum = xysum + r * z;
0403 }
0404
0405 const auto npts = positions.size();
0406 const double denominator = (x2sum * npts - std::pow(xsum, 2));
0407 const float a = (xysum * npts - xsum * ysum) / denominator;
0408 const float b = (x2sum * ysum - xsum * xysum) / denominator;
0409 return std::make_tuple(a, b);
0410 }
0411
0412 }