File indexing completed on 2025-01-18 09:12:49
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Detector/Detector.hpp"
0012 #include "Acts/Detector/DetectorVolume.hpp"
0013 #include "Acts/Detector/GeometryIdGenerator.hpp"
0014 #include "Acts/Detector/PortalGenerators.hpp"
0015 #include "Acts/Detector/detail/CuboidalDetectorHelper.hpp"
0016 #include "Acts/EventData/detail/TestSourceLink.hpp"
0017 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0018 #include "Acts/Geometry/GeometryContext.hpp"
0019 #include "Acts/MagneticField/ConstantBField.hpp"
0020 #include "Acts/Navigation/DetectorNavigator.hpp"
0021 #include "Acts/Navigation/DetectorVolumeFinders.hpp"
0022 #include "Acts/Navigation/InternalNavigation.hpp"
0023 #include "Acts/Propagator/EigenStepper.hpp"
0024 #include "Acts/Propagator/Propagator.hpp"
0025 #include "Acts/Propagator/StraightLineStepper.hpp"
0026 #include "Acts/Seeding/PathSeeder.hpp"
0027 #include "Acts/Surfaces/BoundaryTolerance.hpp"
0028 #include "Acts/Surfaces/PlaneSurface.hpp"
0029 #include "Acts/Surfaces/RectangleBounds.hpp"
0030 #include "Acts/Tests/CommonHelpers/MeasurementsCreator.hpp"
0031 #include "Acts/Utilities/Logger.hpp"
0032
0033 #include <numbers>
0034
0035 BOOST_AUTO_TEST_SUITE(PathSeeder)
0036
0037 using namespace Acts;
0038 using namespace Acts::UnitLiterals;
0039
0040 using Axis = Acts::Axis<AxisType::Equidistant, AxisBoundaryType::Open>;
0041 using Grid = Acts::Grid<std::vector<SourceLink>, Axis, Axis>;
0042
0043 using TrackParameters = CurvilinearTrackParameters;
0044
0045 GeometryContext gctx;
0046
0047
0048 const double halfY = 10.;
0049 const double halfZ = 10.;
0050 const double deltaX = 10.;
0051 const double deltaYZ = 1.;
0052
0053 const Vector4 trueVertex(-5., 0., 0., 0);
0054 const std::vector<double> truePhis = {-0.15, -0.1, -0.05, 0, 0.05, 0.1, 0.15};
0055 const double trueTheta = std::numbers::pi / 2.;
0056 const double trueQOverP = 1. / 1._GeV;
0057
0058
0059
0060 class NoFieldIntersectionFinder {
0061 public:
0062 double m_tol = 1e-4;
0063
0064 std::vector<const Surface*> m_surfaces;
0065
0066
0067
0068
0069 std::vector<std::pair<GeometryIdentifier, Vector2>> operator()(
0070 const GeometryContext& geoCtx,
0071 const TrackParameters& trackParameters) const {
0072 Vector3 position = trackParameters.position();
0073 Vector3 direction = trackParameters.direction();
0074
0075 std::vector<std::pair<GeometryIdentifier, Vector2>> sIntersections;
0076
0077 for (auto& surface : m_surfaces) {
0078
0079 auto sMultiIntersection = surface->intersect(
0080 geoCtx, position, direction,
0081 BoundaryTolerance::AbsoluteCartesian(m_tol, m_tol));
0082
0083
0084 auto closestForward = sMultiIntersection.closestForward();
0085
0086
0087 if (closestForward.status() == IntersectionStatus::reachable &&
0088 closestForward.pathLength() > 0.0) {
0089 sIntersections.push_back(
0090 {closestForward.object()->geometryId(),
0091 surface
0092 ->globalToLocal(geoCtx, closestForward.position(),
0093 Vector3{0, 1, 0})
0094 .value()});
0095 continue;
0096 }
0097 }
0098 return sIntersections;
0099 }
0100 };
0101
0102
0103
0104
0105 class PathWidthProvider {
0106 public:
0107 std::pair<double, double> width;
0108
0109 std::pair<double, double> operator()(
0110 const GeometryContext& ,
0111 const GeometryIdentifier& ) const {
0112 return width;
0113 }
0114 };
0115
0116
0117
0118
0119 class TrackEstimator {
0120 public:
0121 Vector3 m_ip;
0122 SourceLinkSurfaceAccessor m_surfaceAccessor;
0123
0124 std::pair<TrackParameters, TrackParameters> operator()(
0125 const GeometryContext& geoCtx, const SourceLink& pivot) const {
0126 auto testSourceLink = pivot.get<detail::Test::TestSourceLink>();
0127 Vector3 pivot3 = m_surfaceAccessor(pivot)->localToGlobal(
0128 geoCtx, testSourceLink.parameters, Vector3{0, 1, 0});
0129
0130 Vector3 direction = (pivot3 - m_ip).normalized();
0131
0132 Vector4 ip = {m_ip.x(), m_ip.y(), m_ip.z(), 0};
0133 double qOverP = 1_e / 1._GeV;
0134 double phi = Acts::VectorHelpers::phi(direction);
0135 double theta = Acts::VectorHelpers::theta(direction);
0136 ParticleHypothesis particle = ParticleHypothesis::electron();
0137
0138 TrackParameters ipParams(ip, phi, theta, qOverP, std::nullopt, particle);
0139 TrackParameters firstLayerParams(ip, phi, theta, qOverP, std::nullopt,
0140 particle);
0141
0142 return {ipParams, firstLayerParams};
0143 }
0144 };
0145
0146
0147 struct ConstructSourceLinkGrid {
0148 SourceLinkSurfaceAccessor m_surfaceAccessor;
0149
0150 std::unordered_map<GeometryIdentifier, Grid> construct(
0151 std::vector<SourceLink> sourceLinks) {
0152
0153 std::unordered_map<GeometryIdentifier, Grid> lookupTable;
0154
0155
0156 for (int i : {14, 15, 16, 17}) {
0157 Axis xAxis(-halfY, halfY, 100);
0158 Axis yAxis(-halfZ, halfZ, 100);
0159
0160 Grid grid(std::make_tuple(xAxis, yAxis));
0161
0162 GeometryIdentifier geoId;
0163
0164 geoId.setSensitive(i);
0165
0166 lookupTable.insert({geoId, grid});
0167 }
0168
0169 for (auto& sl : sourceLinks) {
0170 auto tsl = sl.get<detail::Test::TestSourceLink>();
0171 auto id = tsl.m_geometryId;
0172
0173 auto bin = lookupTable.at(id).localBinsFromPosition(tsl.parameters);
0174 lookupTable.at(id).atLocalBins(bin).push_back(sl);
0175 }
0176
0177 return lookupTable;
0178 }
0179 };
0180
0181
0182 std::shared_ptr<Experimental::Detector> constructTelescopeDetector() {
0183 RotationMatrix3 rotation;
0184 double angle = 90_degree;
0185 Vector3 xPos(cos(angle), 0., sin(angle));
0186 Vector3 yPos(0., 1., 0.);
0187 Vector3 zPos(-sin(angle), 0., cos(angle));
0188 rotation.col(0) = xPos;
0189 rotation.col(1) = yPos;
0190 rotation.col(2) = zPos;
0191
0192
0193 auto surf0bounds = std::make_unique<RectangleBounds>(halfY, halfZ);
0194
0195 auto surf1bounds = std::make_unique<RectangleBounds>(halfY, halfZ);
0196
0197 auto surf2bounds = std::make_unique<RectangleBounds>(halfY, halfZ);
0198
0199 auto surf3bounds = std::make_unique<RectangleBounds>(halfY, halfZ);
0200
0201
0202 auto transform0 = Transform3::Identity();
0203 auto surf0 = Surface::makeShared<PlaneSurface>(
0204 transform0 * Transform3(rotation), std::move(surf0bounds));
0205 auto geoId0 = GeometryIdentifier();
0206 geoId0.setSensitive(1);
0207
0208 auto transform1 =
0209 Transform3::Identity() * Translation3(Vector3(2 * deltaX, 0, 0));
0210 auto surf1 = Surface::makeShared<PlaneSurface>(
0211 transform1 * Transform3(rotation), std::move(surf1bounds));
0212 auto geoId1 = GeometryIdentifier();
0213 geoId1.setSensitive(2);
0214
0215 auto transform2 =
0216 Transform3::Identity() * Translation3(Vector3(4 * deltaX, 0, 0));
0217 auto surf2 = Surface::makeShared<PlaneSurface>(
0218 transform2 * Transform3(rotation), std::move(surf2bounds));
0219 auto geoId2 = GeometryIdentifier();
0220 geoId2.setSensitive(3);
0221
0222 auto transform3 =
0223 Transform3::Identity() * Translation3(Vector3(6 * deltaX, 0, 0));
0224 auto surf3 = Surface::makeShared<PlaneSurface>(
0225 transform3 * Transform3(rotation), std::move(surf3bounds));
0226 auto geoId3 = GeometryIdentifier();
0227 geoId3.setSensitive(4);
0228
0229
0230 auto vol0bounds = std::make_unique<CuboidVolumeBounds>(
0231 deltaX, halfY + deltaYZ, halfZ + deltaYZ);
0232
0233 auto vol1bounds = std::make_unique<CuboidVolumeBounds>(
0234 deltaX, halfY + deltaYZ, halfZ + deltaYZ);
0235
0236 auto vol2bounds = std::make_unique<CuboidVolumeBounds>(
0237 deltaX, halfY + deltaYZ, halfZ + deltaYZ);
0238
0239 auto vol3bounds = std::make_unique<CuboidVolumeBounds>(
0240 deltaX, halfY + deltaYZ, halfZ + deltaYZ);
0241
0242
0243 auto vol0 = Experimental::DetectorVolumeFactory::construct(
0244 Experimental::defaultPortalAndSubPortalGenerator(), gctx, "vol0",
0245 transform0, std::move(vol0bounds), {surf0}, {},
0246 Experimental::tryNoVolumes(), Experimental::tryAllPortalsAndSurfaces());
0247
0248 auto vol1 = Experimental::DetectorVolumeFactory::construct(
0249 Experimental::defaultPortalAndSubPortalGenerator(), gctx, "vol1",
0250 transform1, std::move(vol1bounds), {surf1}, {},
0251 Experimental::tryNoVolumes(), Experimental::tryAllPortalsAndSurfaces());
0252
0253 auto vol2 = Experimental::DetectorVolumeFactory::construct(
0254 Experimental::defaultPortalAndSubPortalGenerator(), gctx, "vol2",
0255 transform2, std::move(vol2bounds), {surf2}, {},
0256 Experimental::tryNoVolumes(), Experimental::tryAllPortalsAndSurfaces());
0257
0258 auto vol3 = Experimental::DetectorVolumeFactory::construct(
0259 Experimental::defaultPortalAndSubPortalGenerator(), gctx, "vol3",
0260 transform3, std::move(vol3bounds), {surf3}, {},
0261 Experimental::tryNoVolumes(), Experimental::tryAllPortalsAndSurfaces());
0262
0263 std::vector<std::shared_ptr<Experimental::DetectorVolume>> volumes = {
0264 vol0, vol1, vol2, vol3};
0265
0266
0267 auto portalContainer = Experimental::detail::CuboidalDetectorHelper::connect(
0268 gctx, volumes, AxisDirection::AxisX, {}, Logging::INFO);
0269
0270
0271
0272
0273 int id = 1;
0274
0275
0276 for (auto& volume : volumes) {
0277 volume->assignGeometryId(id);
0278 id++;
0279 }
0280
0281 for (auto& volume : volumes) {
0282 for (auto& port : volume->portalPtrs()) {
0283 if (port->surface().geometryId() == 0) {
0284 port->surface().assignGeometryId(id);
0285 id++;
0286 }
0287 }
0288 }
0289
0290 for (auto& surf : {surf0, surf1, surf2, surf3}) {
0291 auto geoId = GeometryIdentifier();
0292 geoId.setSensitive(id);
0293 surf->assignGeometryId(geoId);
0294 id++;
0295 }
0296
0297 auto detector = Experimental::Detector::makeShared(
0298 "TelescopeDetector", volumes, Experimental::tryRootVolumes());
0299
0300 return detector;
0301 }
0302
0303 std::vector<SourceLink> createSourceLinks(
0304 const GeometryContext& geoCtx, const Experimental::Detector& detector) {
0305 NoFieldIntersectionFinder intersectionFinder;
0306
0307 for (auto volume : detector.volumes()) {
0308 for (auto surface : volume->surfaces()) {
0309 intersectionFinder.m_surfaces.push_back(surface);
0310 }
0311 }
0312
0313 std::vector<SourceLink> sourceLinks;
0314 for (double phi : truePhis) {
0315 TrackParameters trackParameters(trueVertex, phi, trueTheta, trueQOverP,
0316 std::nullopt,
0317 ParticleHypothesis::electron());
0318
0319 auto intersections = intersectionFinder(geoCtx, trackParameters);
0320
0321 SquareMatrix2 cov = SquareMatrix2::Identity();
0322
0323 for (auto& [id, refPoint] : intersections) {
0324 detail::Test::TestSourceLink sourceLink(eBoundLoc0, eBoundLoc1, refPoint,
0325 cov, id, id.value());
0326
0327 SourceLink sl{sourceLink};
0328 sourceLinks.push_back(sl);
0329 }
0330 }
0331
0332 return sourceLinks;
0333 }
0334
0335 BOOST_AUTO_TEST_CASE(PathSeederZeroField) {
0336 using SurfaceAccessor =
0337 detail::Test::Experimental::TestSourceLinkSurfaceAccessor;
0338
0339
0340 auto detector = constructTelescopeDetector();
0341
0342
0343 auto sourceLinks = createSourceLinks(gctx, *detector);
0344
0345
0346 auto pathSeederCfg = Acts::PathSeeder::Config();
0347
0348
0349 SurfaceAccessor surfaceAccessor{*detector};
0350 auto sourceLinkGridConstructor = ConstructSourceLinkGrid();
0351 sourceLinkGridConstructor.m_surfaceAccessor
0352 .connect<&SurfaceAccessor::operator()>(&surfaceAccessor);
0353
0354
0355 std::unordered_map<GeometryIdentifier, Grid> sourceLinkGrid =
0356 sourceLinkGridConstructor.construct(sourceLinks);
0357
0358
0359
0360 TrackEstimator trackEstimator;
0361 trackEstimator.m_ip = Vector3(-5., 0., 0.);
0362 trackEstimator.m_surfaceAccessor.connect<&SurfaceAccessor::operator()>(
0363 &surfaceAccessor);
0364 pathSeederCfg.trackEstimator.connect<&TrackEstimator::operator()>(
0365 &trackEstimator);
0366
0367
0368 NoFieldIntersectionFinder intersectionFinder;
0369 for (auto volume : detector->volumes()) {
0370 for (auto surface : volume->surfaces()) {
0371 intersectionFinder.m_surfaces.push_back(surface);
0372 }
0373 }
0374 pathSeederCfg.intersectionFinder
0375 .connect<&NoFieldIntersectionFinder::operator()>(&intersectionFinder);
0376
0377
0378 PathWidthProvider pathWidthProvider;
0379
0380 pathSeederCfg.pathWidthProvider.connect<&PathWidthProvider::operator()>(
0381 &pathWidthProvider);
0382
0383 GeometryIdentifier geoId;
0384 geoId.setSensitive(14);
0385 pathSeederCfg.refLayerIds.push_back(geoId);
0386
0387
0388 Acts::PathSeeder pathSeeder(pathSeederCfg);
0389
0390
0391 pathWidthProvider.width = {1e-3, 1e-3};
0392
0393 std::vector<Acts::PathSeeder::PathSeed> seeds;
0394
0395
0396 pathSeeder.findSeeds(gctx, sourceLinkGrid, seeds);
0397
0398
0399 BOOST_CHECK_EQUAL(seeds.size(), 7);
0400
0401 for (std::size_t i = 0; i < seeds.size(); i++) {
0402 auto seed = seeds.at(i);
0403 BOOST_CHECK_EQUAL(seed.second.size(), 4);
0404 BOOST_CHECK_EQUAL(seed.first.phi(), truePhis.at(i));
0405 BOOST_CHECK_EQUAL(seed.first.theta(), trueTheta);
0406 BOOST_CHECK_EQUAL(seed.first.qOverP(), trueQOverP);
0407 }
0408 }
0409
0410 BOOST_AUTO_TEST_SUITE_END()