File indexing completed on 2026-07-16 08:08:51
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Units.hpp"
0012 #include "Acts/Seeding/CompositeSpacePointLineFitter.hpp"
0013 #include "Acts/Seeding/CompositeSpacePointLineSeeder.hpp"
0014 #include "Acts/Utilities/Enumerate.hpp"
0015 #include "Acts/Utilities/Logger.hpp"
0016 #include "Acts/Utilities/StringHelpers.hpp"
0017 #include "Acts/Utilities/UnitVectors.hpp"
0018 #include "Acts/Utilities/VectorHelpers.hpp"
0019 #include "Acts/Utilities/detail/Polynomials.hpp"
0020
0021 #include <random>
0022 #include <ranges>
0023
0024 using namespace Acts;
0025 using namespace Acts::UnitLiterals;
0026 using namespace Acts::VectorHelpers;
0027 using namespace Acts::Experimental::detail;
0028 using namespace Acts::Experimental;
0029 using namespace Acts::detail::LineHelper;
0030 using namespace Acts::PlanarHelper;
0031
0032 using RandomEngine = std::mt19937;
0033
0034 using ResidualIdx = CompSpacePointAuxiliaries::ResidualIdx;
0035 using Line_t = CompSpacePointAuxiliaries::Line_t;
0036 using normal_t = std::normal_distribution<double>;
0037 using uniform = std::uniform_real_distribution<double>;
0038 using FitParIndex = CompSpacePointAuxiliaries::FitParIndex;
0039 using ParamVec_t = CompositeSpacePointLineFitter::ParamVec_t;
0040
0041 namespace ActsTests {
0042
0043 class FitTestSpacePoint {
0044 public:
0045
0046
0047
0048
0049
0050 FitTestSpacePoint(const Vector3& pos, const double driftR,
0051 const double driftRUncert,
0052 const std::optional<double> twinUncert = std::nullopt)
0053 : m_position{pos},
0054 m_driftR{driftR},
0055 m_measLoc0{twinUncert != std::nullopt} {
0056 using enum ResidualIdx;
0057 m_covariance[toUnderlying(bending)] = Acts::square(driftRUncert);
0058 m_covariance[toUnderlying(nonBending)] =
0059 Acts::square(twinUncert.value_or(0.));
0060 }
0061
0062
0063
0064
0065
0066
0067 FitTestSpacePoint(const Vector3& pos, const Vector3& wire,
0068 const double driftR, const double driftRUncert,
0069 const std::optional<double> twinUncert = std::nullopt)
0070 : m_position{pos},
0071 m_sensorDir{wire},
0072 m_driftR{driftR},
0073 m_measLoc0{twinUncert != std::nullopt} {
0074 using enum ResidualIdx;
0075 m_covariance[toUnderlying(bending)] = Acts::square(driftRUncert);
0076 m_covariance[toUnderlying(nonBending)] =
0077 Acts::square(twinUncert.value_or(0.));
0078 }
0079
0080
0081
0082
0083
0084
0085
0086 FitTestSpacePoint(const Vector3& stripPos, const Vector3& stripDir,
0087 const Vector3& toNext, const double uncertLoc0,
0088 const double uncertLoc1)
0089 : m_position{stripPos},
0090 m_sensorDir{stripDir},
0091 m_toNextSen{toNext},
0092 m_measLoc0{uncertLoc0 > 0.},
0093 m_measLoc1{uncertLoc1 > 0.} {
0094 using enum ResidualIdx;
0095 m_covariance[toUnderlying(nonBending)] = Acts::square(uncertLoc0);
0096 m_covariance[toUnderlying(bending)] = Acts::square(uncertLoc1);
0097 }
0098
0099 FitTestSpacePoint(const Vector3& stripPos, const Vector3& stripDir,
0100 const Vector3& toNext, const double time,
0101 const std::array<double, 3>& cov)
0102 : m_position{stripPos},
0103 m_sensorDir{stripDir},
0104 m_toNextSen{toNext},
0105 m_time{time},
0106 m_covariance{cov} {
0107 m_measLoc0 = m_covariance[toUnderlying(ResidualIdx::nonBending)] > 0.;
0108 m_measLoc1 = m_covariance[toUnderlying(ResidualIdx::bending)] > 0.;
0109 }
0110
0111
0112 const Vector3& localPosition() const { return m_position; }
0113
0114 const Vector3& sensorDirection() const { return m_sensorDir; }
0115
0116 const Vector3& toNextSensor() const { return m_toNextSen; }
0117
0118 const Vector3& planeNormal() const { return m_planeNorm; }
0119
0120 double driftRadius() const { return m_driftR.value_or(0.); }
0121
0122 const std::array<double, 3>& covariance() const { return m_covariance; }
0123
0124 double time() const { return m_time.value_or(0.); }
0125
0126 bool isStraw() const { return m_driftR.has_value(); }
0127
0128 bool hasTime() const { return m_time.has_value(); }
0129
0130 bool measuresLoc0() const { return m_measLoc0; }
0131
0132 bool measuresLoc1() const { return m_measLoc1 || isStraw(); }
0133
0134 void updateDriftR(const double updatedR) { m_driftR = updatedR; }
0135
0136 void updatePosition(const Vector3& newPos) { m_position = newPos; }
0137
0138 void updateTime(const double newTime) { m_time = newTime; }
0139
0140 void updateStatus(const bool newStatus) { m_isGood = newStatus; }
0141
0142 bool isGood() const { return m_isGood; }
0143
0144 std::size_t layer() const { return m_layer.value_or(0ul); }
0145
0146 void setLayer(const std::size_t lay) {
0147 if (!m_layer) {
0148 m_layer = lay;
0149 }
0150 }
0151
0152 private:
0153 Vector3 m_position{Vector3::Zero()};
0154 Vector3 m_sensorDir{Vector3::UnitX()};
0155 Vector3 m_toNextSen{Vector3::UnitY()};
0156 Vector3 m_planeNorm{m_sensorDir.cross(m_toNextSen).normalized()};
0157 std::optional<double> m_driftR{std::nullopt};
0158 std::optional<double> m_time{std::nullopt};
0159 std::array<double, 3> m_covariance{filledArray<double, 3>(0)};
0160 bool m_measLoc0{false};
0161 bool m_measLoc1{false};
0162 bool m_isGood{true};
0163 std::optional<std::size_t> m_layer{};
0164 };
0165
0166 static_assert(CompositeSpacePoint<FitTestSpacePoint>);
0167
0168 using Container_t = std::vector<std::shared_ptr<FitTestSpacePoint>>;
0169 static_assert(CompositeSpacePointContainer<Container_t>);
0170
0171 class SpCalibrator {
0172 public:
0173 SpCalibrator() = default;
0174
0175 explicit SpCalibrator(const Acts::Transform3& localToGlobal)
0176 : m_localToGlobal{localToGlobal} {}
0177
0178
0179 static double normalize(const double value, const double min,
0180 const double max) {
0181 return 2. * (std::clamp(value, min, max) - min) / (max - min) - 1.;
0182 }
0183
0184 static constexpr double s_minDriftTime = 0._ns;
0185 static constexpr double s_maxDriftTime = 741.324 * 1._ns;
0186
0187 static double normDriftTime(const double t) {
0188 return normalize(t, s_minDriftTime, s_maxDriftTime);
0189 }
0190
0191 static constexpr double s_timeNormFactor =
0192 2.0 / (s_maxDriftTime - s_minDriftTime);
0193
0194 static constexpr std::array<double, 9> s_TtoRcoeffs = {
0195 9.0102, 6.7419, -1.5829, 0.56475, -0.19245,
0196 0.019055, 0.030006, -0.034591, 0.023517};
0197
0198 static double driftRadius(const double t) {
0199 const double x = normDriftTime(t);
0200 double r{0.0};
0201 for (std::size_t n = 0; n < s_TtoRcoeffs.size(); ++n) {
0202 r += s_TtoRcoeffs[n] * Acts::detail::chebychevPolyTn(x, n);
0203 }
0204 return r;
0205 }
0206
0207 static double driftVelocity(const double t) {
0208 const double x = normDriftTime(t);
0209 double v{0.0};
0210 for (std::size_t n = 1; n < s_TtoRcoeffs.size(); ++n) {
0211 v += s_TtoRcoeffs[n] * Acts::detail::chebychevPolyUn(x, n, 1u);
0212 }
0213 return v * s_timeNormFactor;
0214 }
0215
0216 static double driftAcceleration(const double t) {
0217 const double x = normDriftTime(t);
0218 double a{0.0};
0219 for (std::size_t n = 2; n < s_TtoRcoeffs.size(); ++n) {
0220 a += s_TtoRcoeffs[n] * Acts::detail::chebychevPolyUn(x, n, 2u);
0221 }
0222 return a * Acts::square(s_timeNormFactor);
0223 }
0224
0225 static constexpr double s_minDriftRadius = 0.064502;
0226 static constexpr double s_maxDriftRadius = 14.566;
0227
0228 static double normDriftRadius(const double r) {
0229 return normalize(r, s_minDriftRadius, s_maxDriftRadius);
0230 }
0231
0232 static constexpr std::array<double, 5> s_RtoTcoeffs = {
0233 256.476, 349.056, 118.349, 18.748, -6.4142};
0234
0235 static double driftTime(const double r) {
0236 const double x = normDriftRadius(r);
0237 double t{0.0};
0238 for (std::size_t n = 0; n < s_RtoTcoeffs.size(); ++n) {
0239 t += s_RtoTcoeffs[n] * Acts::detail::legendrePoly(x, n);
0240 }
0241 return t * 1._ns;
0242 }
0243
0244 static constexpr std::array<double, 4> s_driftRUncertCoeffs{
0245 0.10826, -0.07182, 0.037597, -0.011712};
0246
0247 static double driftUncert(const double r) {
0248 const double x = normDriftRadius(r);
0249 double s{0.0};
0250 for (std::size_t n = 0; n < s_driftRUncertCoeffs.size(); ++n) {
0251 s += s_driftRUncertCoeffs[n] * Acts::detail::chebychevPolyTn(x, n);
0252 }
0253 return s;
0254 }
0255
0256
0257
0258
0259
0260 static double driftRadius(const Acts::CalibrationContext& ,
0261 const FitTestSpacePoint& measurement,
0262 const double timeOffSet) {
0263 if (!measurement.isStraw() || !measurement.isGood()) {
0264 return 0.;
0265 }
0266 return driftRadius(Acts::abs(measurement.time() - timeOffSet));
0267 }
0268
0269
0270
0271
0272
0273 static double driftVelocity(const Acts::CalibrationContext& ,
0274 const FitTestSpacePoint& measurement,
0275 const double timeOffSet) {
0276 if (!measurement.isStraw() || !measurement.isGood()) {
0277 return 0.;
0278 }
0279 return driftVelocity(Acts::abs(measurement.time() - timeOffSet));
0280 }
0281
0282
0283
0284
0285
0286 static double driftAcceleration(const Acts::CalibrationContext& ,
0287 const FitTestSpacePoint& measurement,
0288 const double timeOffSet) {
0289 if (!measurement.isStraw() || !measurement.isGood()) {
0290 return 0.;
0291 }
0292 return driftAcceleration(Acts::abs(measurement.time() - timeOffSet));
0293 }
0294
0295
0296
0297
0298
0299 double closestApproachDist(const Vector3& trackPos, const Vector3& trackDir,
0300 const FitTestSpacePoint& measurement) const {
0301 const Vector3 closePointOnLine =
0302 lineIntersect(measurement.localPosition(),
0303 measurement.sensorDirection(), trackPos, trackDir)
0304 .position();
0305 return (m_localToGlobal * closePointOnLine).norm();
0306 }
0307 std::shared_ptr<FitTestSpacePoint> calibrate(
0308 const Acts::CalibrationContext& , const Vector3& trackPos,
0309 const Vector3& trackDir, const double timeOffSet,
0310 const FitTestSpacePoint& sp) const {
0311 auto copySp = std::make_shared<FitTestSpacePoint>(sp);
0312 if (!copySp->measuresLoc0() || !copySp->measuresLoc1()) {
0313
0314 auto bestPos = lineIntersect(trackPos, trackDir, copySp->localPosition(),
0315 copySp->sensorDirection());
0316 copySp->updatePosition(bestPos.position());
0317 }
0318 if (copySp->isStraw()) {
0319 const double driftTime{copySp->time() - timeOffSet -
0320 closestApproachDist(trackPos, trackDir, sp) /
0321 PhysicalConstants::c};
0322 if (driftTime < 0) {
0323 copySp->updateStatus(false);
0324 copySp->updateDriftR(0.);
0325 } else {
0326 copySp->updateStatus(true);
0327 copySp->updateDriftR(Acts::abs(driftRadius(driftTime)));
0328 }
0329 }
0330 return copySp;
0331 }
0332
0333
0334
0335
0336
0337
0338 Container_t calibrate(const Acts::CalibrationContext& ctx,
0339 const Vector3& trackPos, const Vector3& trackDir,
0340 const double timeOffSet,
0341 const Container_t& uncalibCont) const {
0342 Container_t calibMeas{};
0343 std::ranges::transform(
0344 uncalibCont, std::back_inserter(calibMeas), [&](const auto& calibMe) {
0345 return calibrate(ctx, trackPos, trackDir, timeOffSet, *calibMe);
0346 });
0347 return uncalibCont;
0348 }
0349
0350
0351 void updateSigns(const Vector3& trackPos, const Vector3& trackDir,
0352 Container_t& measurements) const {
0353 auto signs =
0354 CompSpacePointAuxiliaries::strawSigns(trackPos, trackDir, measurements);
0355
0356 for (std::size_t s = 0; s < signs.size(); ++s) {
0357
0358 if (measurements[s]->isStraw()) {
0359 measurements[s]->updateDriftR(
0360 Acts::abs(measurements[s]->driftRadius()) * signs[s]);
0361 }
0362 }
0363 }
0364
0365
0366
0367 static double driftVelocity(const Acts::CalibrationContext& ,
0368 const FitTestSpacePoint& measurement) {
0369 if (!measurement.isStraw() || !measurement.isGood()) {
0370 return 0.;
0371 }
0372 return driftVelocity(driftTime(Acts::abs(measurement.driftRadius())));
0373 }
0374
0375
0376
0377 static double driftAcceleration(const Acts::CalibrationContext& ,
0378 const FitTestSpacePoint& measurement) {
0379 if (!measurement.isStraw() || !measurement.isGood()) {
0380 return 0.;
0381 }
0382 return driftAcceleration(driftTime(Acts::abs(measurement.driftRadius())));
0383 }
0384
0385 private:
0386 const Acts::Transform3 m_localToGlobal{Acts::Transform3::Identity()};
0387 };
0388
0389 static_assert(
0390 CompositeSpacePointCalibrator<SpCalibrator, Container_t, Container_t>);
0391 static_assert(
0392 CompositeSpacePointFastCalibrator<SpCalibrator, FitTestSpacePoint>);
0393
0394
0395 class SpSorter {
0396 protected:
0397
0398
0399
0400 SpSorter(const Container_t& hits, const SpCalibrator* calibrator)
0401 : m_calibrator{calibrator} {
0402 for (const auto& spPtr : hits) {
0403 auto& pushMe{spPtr->isStraw() ? m_straws : m_strips};
0404 if (spPtr->layer() >= pushMe.size()) {
0405 pushMe.resize(spPtr->layer() + 1);
0406 }
0407 pushMe[spPtr->layer()].push_back(spPtr);
0408 }
0409 }
0410
0411 public:
0412
0413 const std::vector<Container_t>& strawHits() const { return m_straws; }
0414
0415 const std::vector<Container_t>& stripHits() const { return m_strips; }
0416
0417
0418 bool goodCandidate(const FitTestSpacePoint& testPoint) const {
0419 return testPoint.isGood();
0420 }
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430 double candidateChi2(const CalibrationContext& , const Vector3& pos,
0431 const Vector3& dir, const double ,
0432 const FitTestSpacePoint& testSp) const {
0433 return CompSpacePointAuxiliaries::chi2Term(pos, dir, testSp);
0434 }
0435
0436 Container_t newContainer(const CalibrationContext& ) const {
0437 return Container_t{};
0438 }
0439
0440
0441
0442 void append(const CalibrationContext& cctx, const Vector3& pos,
0443 const Vector3& dir, const double t0,
0444 const FitTestSpacePoint& testSp,
0445 Container_t& outContainer) const {
0446 outContainer.push_back(m_calibrator->calibrate(cctx, pos, dir, t0, testSp));
0447 }
0448
0449 bool stopSeeding(const std::size_t lowerLayer,
0450 const std::size_t upperLayer) const {
0451 return lowerLayer >= upperLayer;
0452 }
0453 double strawRadius(const FitTestSpacePoint& ) const {
0454 return 15._mm;
0455 }
0456
0457 private:
0458 const SpCalibrator* m_calibrator{nullptr};
0459 std::vector<Container_t> m_straws{};
0460 std::vector<Container_t> m_strips{};
0461 };
0462
0463 static_assert(CompositeSpacePointSorter<SpSorter, Container_t>);
0464
0465
0466
0467
0468 Line_t generateLine(RandomEngine& engine, const Logger& logger) {
0469 using ParIndex = Line_t::ParIndex;
0470 Line_t::ParamVector linePars{};
0471 linePars[toUnderlying(ParIndex::phi)] =
0472 uniform{-120_degree, 120_degree}(engine);
0473 linePars[toUnderlying(ParIndex::x0)] = uniform{-500., 500.}(engine);
0474 linePars[toUnderlying(ParIndex::y0)] = uniform{-500., 500.}(engine);
0475 linePars[toUnderlying(ParIndex::theta)] =
0476 uniform{5_degree, 175_degree}(engine);
0477 if (Acts::abs(linePars[toUnderlying(ParIndex::theta)] - 90._degree) <
0478 3_degree) {
0479 return generateLine(engine, logger);
0480 }
0481 Line_t line{linePars};
0482
0483 ACTS_DEBUG(
0484 "\n\n\n"
0485 << __func__ << "() " << __LINE__ << " - Generated parameters "
0486 << std::format("theta: {:.2f}, phi: {:.2f}, y0: {:.1f}, x0: {:.1f}",
0487 linePars[toUnderlying(ParIndex::theta)] / 1._degree,
0488 linePars[toUnderlying(ParIndex::phi)] / 1._degree,
0489 linePars[toUnderlying(ParIndex::y0)],
0490 linePars[toUnderlying(ParIndex::x0)])
0491 << " --> " << toString(line.position()) << " + "
0492 << toString(line.direction()));
0493
0494 return line;
0495 }
0496
0497 class MeasurementGenerator {
0498 public:
0499 struct Config {
0500
0501 bool createStraws{true};
0502
0503 bool smearRadius{true};
0504
0505 bool twinStraw{false};
0506
0507 double twinStrawReso{5._cm};
0508
0509 bool createStrips{true};
0510
0511 bool smearStrips{true};
0512
0513 bool discretizeStrips{false};
0514
0515 bool combineSpacePoints{false};
0516
0517 double stripPitchLoc0{4._cm};
0518
0519 double stripPitchLoc1{3._cm};
0520
0521 std::vector<Vector3> stripDirLoc1 =
0522 std::vector<Vector3>(8, Vector3::UnitX());
0523
0524 std::vector<Vector3> stripDirLoc0 =
0525 std::vector<Vector3>(8, Vector3::UnitY());
0526
0527 Acts::CalibrationContext calibContext{};
0528
0529 Acts::Transform3 localToGlobal{Acts::Transform3::Identity()};
0530 };
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542 static Container_t spawn(const Line_t& line, const double t0,
0543 RandomEngine& engine, const Config& genCfg,
0544 const Logger& logger) {
0545
0546 const Vector3 posStaggering{0., std::cos(60._degree), std::sin(60._degree)};
0547
0548 const Vector3 negStaggering{0., -std::cos(60._degree),
0549 std::sin(60._degree)};
0550
0551 constexpr std::size_t nLayersPerMl = 8;
0552
0553 constexpr std::size_t nTubeLayers = nLayersPerMl * 2;
0554
0555 constexpr double chamberDistance = 3._m;
0556
0557 constexpr double tubeRadius = 15._mm;
0558
0559 constexpr double tubeLayerDist = 1.2_m;
0560
0561 constexpr double tubeStripDist = 30._cm;
0562
0563 constexpr double stripLayDist = 0.5_cm;
0564
0565 std::array<Vector3, nTubeLayers> tubePositions{
0566 filledArray<Vector3, nTubeLayers>(chamberDistance * Vector3::UnitZ())};
0567
0568 for (std::size_t l = 1; l < nTubeLayers; ++l) {
0569 const Vector3& layStag{l % 2 == 1 ? posStaggering : negStaggering};
0570 tubePositions[l] = tubePositions[l - 1] + 2. * tubeRadius * layStag;
0571
0572 if (l == nLayersPerMl) {
0573 tubePositions[l] += tubeLayerDist * Vector3::UnitZ();
0574 }
0575 }
0576
0577 ACTS_DEBUG("##############################################");
0578
0579 for (std::size_t l = 0; l < nTubeLayers; ++l) {
0580 ACTS_DEBUG(" *** " << (l + 1) << " - " << toString(tubePositions[l]));
0581 }
0582 ACTS_DEBUG("##############################################");
0583
0584 Container_t measurements{};
0585
0586
0587 if (genCfg.createStraws) {
0588 const SpCalibrator calibrator{genCfg.localToGlobal};
0589 for (const auto& [i_layer, stag] : enumerate(tubePositions)) {
0590 auto planeExtpLow =
0591 intersectPlane(line.position(), line.direction(), Vector3::UnitZ(),
0592 stag.z() - tubeRadius);
0593 auto planeExtpHigh =
0594 intersectPlane(line.position(), line.direction(), Vector3::UnitZ(),
0595 stag.z() + tubeRadius);
0596 ACTS_DEBUG("spawn() - Extrapolated to plane "
0597 << toString(planeExtpLow.position()) << " "
0598 << toString(planeExtpHigh.position()));
0599
0600 const auto dToFirstLow = static_cast<int>(std::ceil(
0601 (planeExtpLow.position().y() - stag.y()) / (2. * tubeRadius)));
0602 const auto dToFirstHigh = static_cast<int>(std::ceil(
0603 (planeExtpHigh.position().y() - stag.y()) / (2. * tubeRadius)));
0604
0605 const int dT = copySign(1, dToFirstHigh - dToFirstLow);
0606
0607
0608
0609 for (int tN = dToFirstLow - dT; tN != dToFirstHigh + 2 * dT; tN += dT) {
0610 Vector3 tube = stag + 2. * tN * tubeRadius * Vector3::UnitY();
0611 const double rad = Acts::abs(signedDistance(
0612 tube, Vector3::UnitX(), line.position(), line.direction()));
0613 if (rad > tubeRadius) {
0614 continue;
0615 }
0616
0617 const double smearedR =
0618 genCfg.smearRadius
0619 ? Acts::abs(
0620 normal_t{rad, SpCalibrator::driftUncert(rad)}(engine))
0621 : rad;
0622 if (smearedR > tubeRadius) {
0623 continue;
0624 }
0625
0626 if (genCfg.twinStraw) {
0627 const auto iSectWire = lineIntersect<3>(
0628 line.position(), line.direction(), tube, Vector3::UnitX());
0629 tube = iSectWire.position();
0630 tube[eX] = normal_t{tube[eX], genCfg.twinStrawReso}(engine);
0631 }
0632 ACTS_DEBUG("spawn() - Tube position: " << toString(tube)
0633 << ", radius: " << rad);
0634
0635 auto twinUncert =
0636 genCfg.twinStraw
0637 ? std::make_optional<double>(genCfg.twinStrawReso)
0638 : std::nullopt;
0639 auto& sp =
0640 measurements.emplace_back(std::make_unique<FitTestSpacePoint>(
0641 tube, smearedR, SpCalibrator::driftUncert(smearedR),
0642 twinUncert));
0643 sp->setLayer(i_layer);
0644 sp->updateTime(SpCalibrator::driftTime(sp->driftRadius()) + t0 +
0645 calibrator.closestApproachDist(line.position(),
0646 line.direction(), *sp) /
0647 PhysicalConstants::c);
0648 }
0649 }
0650 }
0651 if (genCfg.createStrips) {
0652
0653
0654
0655
0656
0657 auto discretize = [&genCfg, &engine](const Vector3& extPos,
0658 const std::size_t lay,
0659 const bool loc1) -> Vector3 {
0660 const double pitch =
0661 loc1 ? genCfg.stripPitchLoc1 : genCfg.stripPitchLoc0;
0662 assert(pitch > 0.);
0663
0664 const Vector3& stripDir =
0665 loc1 ? genCfg.stripDirLoc1.at(lay) : genCfg.stripDirLoc0.at(lay);
0666 const Vector3 stripNormal = stripDir.cross(Vector3::UnitZ());
0667 const double dist = stripNormal.dot(extPos);
0668 if (genCfg.smearStrips) {
0669 return normal_t{dist, pitch / std::sqrt(12)}(engine)*stripNormal;
0670 }
0671 if (genCfg.discretizeStrips) {
0672 return pitch *
0673 static_cast<int>(std::ceil((dist - 0.5 * pitch) / pitch)) *
0674 stripNormal;
0675 }
0676 return dist * stripNormal;
0677 };
0678
0679 const double stripCovLoc0 =
0680 Acts::square(genCfg.stripPitchLoc0) / std::sqrt(12.);
0681 const double stripCovLoc1 =
0682 Acts::square(genCfg.stripPitchLoc1) / std::sqrt(12.);
0683
0684 for (std::size_t sL = 0; sL < std::max(genCfg.stripDirLoc0.size(),
0685 genCfg.stripDirLoc1.size());
0686 ++sL) {
0687 const double distInZ = tubeStripDist + sL * stripLayDist;
0688 const double planeLow = tubePositions.front().z() - distInZ;
0689 const double planeHigh = tubePositions.back().z() + distInZ;
0690
0691 for (const double plane : {planeLow, planeHigh}) {
0692 const auto extp = intersectPlane(line.position(), line.direction(),
0693 Vector3::UnitZ(), plane);
0694 ACTS_VERBOSE("spawn() - Propagated line to "
0695 << toString(extp.position()) << ".");
0696
0697 if (genCfg.combineSpacePoints &&
0698 sL < std::min(genCfg.stripDirLoc0.size(),
0699 genCfg.stripDirLoc1.size())) {
0700 const Vector3 extpPos{discretize(extp.position(), sL, false) +
0701 discretize(extp.position(), sL, true) +
0702 plane * Vector3::UnitZ()};
0703 measurements.emplace_back(std::make_unique<FitTestSpacePoint>(
0704 extpPos, genCfg.stripDirLoc0.at(sL), genCfg.stripDirLoc1.at(sL),
0705 stripCovLoc0, stripCovLoc1));
0706 measurements.back()->setLayer(sL);
0707 } else {
0708 if (sL < genCfg.stripDirLoc0.size()) {
0709 const Vector3 extpPos{discretize(extp.position(), sL, false) +
0710 plane * Vector3::UnitZ()};
0711 measurements.emplace_back(std::make_unique<FitTestSpacePoint>(
0712 extpPos, genCfg.stripDirLoc0.at(sL),
0713 genCfg.stripDirLoc0.at(sL).cross(Vector3::UnitZ()),
0714 stripCovLoc0, 0.));
0715 auto& nM{*measurements.back()};
0716 nM.setLayer(sL);
0717 ACTS_VERBOSE("spawn() - Created loc0 strip @" << toString(nM)
0718 << ".");
0719 }
0720 if (sL < genCfg.stripDirLoc1.size()) {
0721 const Vector3 extpPos{discretize(extp.position(), sL, true) +
0722 plane * Vector3::UnitZ()};
0723 measurements.emplace_back(std::make_unique<FitTestSpacePoint>(
0724 extpPos, genCfg.stripDirLoc1.at(sL),
0725 genCfg.stripDirLoc1.at(sL).cross(Vector3::UnitZ()), 0.,
0726 stripCovLoc1));
0727 auto& nM{*measurements.back()};
0728 nM.setLayer(sL);
0729 ACTS_VERBOSE("spawn() - Created loc1 strip @" << toString(nM)
0730 << ".");
0731 }
0732 }
0733 }
0734 }
0735 }
0736 ACTS_DEBUG("Track hit in total " << measurements.size() << " sensors.");
0737 std::ranges::sort(measurements, [&line](const auto& spA, const auto& spB) {
0738 return line.direction().dot(spA->localPosition() - line.position()) <
0739 line.direction().dot(spB->localPosition() - line.position());
0740 });
0741 return measurements;
0742 }
0743 };
0744
0745
0746
0747
0748 ParamVec_t startParameters(const Line_t& line, const Container_t& hits) {
0749 ParamVec_t pars{};
0750
0751 double tanAlpha{0.};
0752 double tanBeta{0.};
0753
0754 auto firstPhi = std::ranges::find_if(
0755 hits, [](const auto& sp) { return sp->measuresLoc0(); });
0756 auto lastPhi =
0757 std::ranges::find_if(std::ranges::reverse_view(hits),
0758 [](const auto& sp) { return sp->measuresLoc0(); });
0759
0760 if (firstPhi != hits.end() && lastPhi != hits.rend()) {
0761 const Vector3 firstToLastPhi =
0762 (**lastPhi).localPosition() - (**firstPhi).localPosition();
0763 tanAlpha = firstToLastPhi.x() / firstToLastPhi.z();
0764
0765 pars[toUnderlying(FitParIndex::x0)] =
0766 (**lastPhi).localPosition().x() -
0767 (**lastPhi).localPosition().z() * tanAlpha;
0768 }
0769
0770 auto firstTube =
0771 std::ranges::find_if(hits, [](const auto& sp) { return sp->isStraw(); });
0772 auto lastTube =
0773 std::ranges::find_if(std::ranges::reverse_view(hits),
0774 [](const auto& sp) { return sp->isStraw(); });
0775
0776 if (firstTube != hits.end() && lastTube != hits.rend()) {
0777 const int signFirst =
0778 CompSpacePointAuxiliaries::strawSign(line, **firstTube);
0779 const int signLast = CompSpacePointAuxiliaries::strawSign(line, **lastTube);
0780
0781 auto seedPars = CompositeSpacePointLineSeeder::constructTangentLine(
0782 **lastTube, **firstTube,
0783 CompositeSpacePointLineSeeder::encodeAmbiguity(signLast, signFirst));
0784 tanBeta = std::tan(seedPars.theta);
0785 pars[toUnderlying(FitParIndex::y0)] = seedPars.y0;
0786 } else {
0787 auto firstEta = std::ranges::find_if(hits, [](const auto& sp) {
0788 return !sp->isStraw() && sp->measuresLoc1();
0789 });
0790 auto lastEta = std::ranges::find_if(
0791 std::ranges::reverse_view(hits),
0792 [](const auto& sp) { return !sp->isStraw() && sp->measuresLoc1(); });
0793
0794 if (firstEta != hits.end() && lastEta != hits.rend()) {
0795 const Vector3 firstToLastEta =
0796 (**lastEta).localPosition() - (**firstEta).localPosition();
0797 tanBeta = firstToLastEta.y() / firstToLastEta.z();
0798
0799 pars[toUnderlying(FitParIndex::y0)] =
0800 (**lastEta).localPosition().y() -
0801 (**lastEta).localPosition().z() * tanBeta;
0802 }
0803 }
0804 const Vector3 seedDir = makeDirectionFromAxisTangents(tanAlpha, tanBeta);
0805
0806 pars[toUnderlying(FitParIndex::theta)] = theta(seedDir);
0807 pars[toUnderlying(FitParIndex::phi)] = phi(seedDir);
0808 return pars;
0809 }
0810
0811 bool isGoodHit(const FitTestSpacePoint& sp) {
0812 return !sp.isStraw() || sp.isGood();
0813 };
0814
0815 }