Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-07 07:59:15

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include "ActsExamples/AlignmentMillePede/MillePedeAlignmentSandbox.hpp"
0010 
0011 #include "Acts/Geometry/GeometryContext.hpp"
0012 #include "Acts/Geometry/GeometryIdentifier.hpp"
0013 #include "Acts/Material/MaterialInteraction.hpp"
0014 #include "Acts/Propagator/Navigator.hpp"
0015 #include "Acts/Propagator/Propagator.hpp"
0016 #include "Acts/Surfaces/Surface.hpp"
0017 #include "Acts/TrackFitting/GainMatrixSmoother.hpp"
0018 #include "Acts/TrackFitting/GainMatrixUpdater.hpp"
0019 #include "Acts/Utilities/Logger.hpp"
0020 #include "ActsExamples/EventData/IndexSourceLink.hpp"
0021 #include "ActsExamples/EventData/MeasurementCalibration.hpp"
0022 #include "ActsExamples/Framework/ProcessCode.hpp"
0023 #include "ActsPlugins/Mille/ActsToMille.hpp"
0024 
0025 #include <memory>
0026 
0027 namespace ActsExamples {
0028 
0029 MillePedeAlignmentSandbox::MillePedeAlignmentSandbox(
0030     Config cfg, std::unique_ptr<const Acts::Logger> logger)
0031     : IAlgorithm("MillePedeAlignmentSandbox", std::move(logger)),
0032       m_cfg(std::move(cfg)) {
0033   // initialize our handles
0034   if (m_cfg.inputMeasurements.empty()) {
0035     throw std::invalid_argument("Missing input measurement collection");
0036   }
0037   if (m_cfg.inputTracks.empty()) {
0038     throw std::invalid_argument("Missing input track collection");
0039   }
0040   m_inputTracks.initialize(m_cfg.inputTracks);
0041   m_inputMeasurements.initialize(m_cfg.inputMeasurements);
0042 
0043   // retrieve tracking geo
0044   m_trackingGeometry = m_cfg.trackingGeometry;
0045 
0046   // instantiate the alignment tool instance
0047   Acts::Navigator::Config navcfg{m_cfg.trackingGeometry};
0048   navcfg.resolvePassive = false;
0049   navcfg.resolveMaterial = true;
0050   navcfg.resolveSensitive = true;
0051   Acts::Navigator navigator(navcfg,
0052                             this->logger().cloneWithSuffix("Navigator"));
0053   Stepper stepper{m_cfg.magneticField};
0054   m_align = std::make_shared<Alignment>(
0055       Fitter(Propagator(stepper, Acts::Navigator(navcfg))));
0056 
0057   /// spawn a Mille binary to record our alignment inputs.
0058   /// You can specify root / csv / dat extensions for
0059   /// ROOT NTuple / plain text (careful: large files) or C-binary
0060   /// storage.
0061   /// The file will be automatically closed upon deletion.
0062   m_milleOut = Mille::spawnMilleRecord(m_cfg.milleOutput);
0063 }
0064 
0065 ProcessCode MillePedeAlignmentSandbox::execute(
0066     const AlgorithmContext& ctx) const {
0067   using TrackFitterOptions =
0068       Acts::KalmanFitterOptions<Acts::VectorMultiTrajectory>;
0069 
0070   // Read input data
0071   const auto& measurements = m_inputMeasurements(ctx);
0072   const auto& tracks = m_inputTracks(ctx);
0073 
0074   // Assign indices to the alignable surfaces
0075 
0076   // We wish to have a relation between alignment parameter indices and real
0077   // geometry. The unordered_map does not give us this - so perform a manual
0078   // sorting.
0079   std::vector<std::pair<Acts::GeometryIdentifier, const Acts::Surface*>>
0080       sortedGeo;
0081   sortedGeo.insert(sortedGeo.end(),
0082                    m_trackingGeometry->geoIdSurfaceMap().begin(),
0083                    m_trackingGeometry->geoIdSurfaceMap().end());
0084   std::sort(
0085       sortedGeo.begin(), sortedGeo.end(),
0086       [&](const std::pair<Acts::GeometryIdentifier, const Acts::Surface*>& lhs,
0087           const std::pair<Acts::GeometryIdentifier, const Acts::Surface*>&
0088               rhs) { return (lhs.first.layer() < rhs.first.layer()); });
0089 
0090   std::unordered_map<const Acts::Surface*, std::size_t> indexedAlignSurfaces;
0091   const Acts::Surface* firstSurf = nullptr;
0092   unsigned int iSurface = 0;
0093   for (auto& [geoID, surface] : sortedGeo) {
0094     // only consider sensitive surfaces
0095     if (!surface->isSensitive()) {
0096       continue;
0097     }
0098     // use the first sensitive surface as trajectory reference in the kalman
0099     if (firstSurf == nullptr) {
0100       firstSurf = surface;
0101     }
0102     if (!m_cfg.fixModules.contains(geoID)) {
0103       indexedAlignSurfaces.emplace(surface, iSurface);
0104       iSurface++;
0105     }
0106   }
0107 
0108   // Dirty hack: Overwrite the geometry context to remove knowledge
0109   // of injected alignment shift.
0110   // Detector will look misaligned and the injected correction can be fitted
0111   // out.
0112   // TODO: Replace if an appropriate non-hacky tool becomes available.
0113   Acts::GeometryContext dummyGeoCtx =
0114       Acts::GeometryContext::dangerouslyDefaultConstruct();
0115 
0116   // Pile of boilerplate code to get the Kalman fitter for the
0117   // alignment module ready to go
0118   IndexSourceLinkSurfaceAccessor slack{*m_trackingGeometry};
0119   Acts::KalmanFitterExtensions<Acts::VectorMultiTrajectory> extensions;
0120   ActsExamples::PassThroughCalibrator pcalibrator;
0121   MeasurementCalibratorAdapter calibrator(pcalibrator, measurements);
0122   extensions.calibrator.connect<&MeasurementCalibratorAdapter::calibrate>(
0123       &calibrator);
0124   Acts::GainMatrixUpdater kfUpdater;
0125   Acts::GainMatrixSmoother kfSmoother;
0126   extensions.updater.connect<
0127       &Acts::GainMatrixUpdater::operator()<Acts::VectorMultiTrajectory>>(
0128       &kfUpdater);
0129   extensions.smoother.connect<
0130       &Acts::GainMatrixSmoother::operator()<Acts::VectorMultiTrajectory>>(
0131       &kfSmoother);
0132   extensions.surfaceAccessor
0133       .connect<&ActsExamples::IndexSourceLinkSurfaceAccessor::operator()>(
0134           &slack);
0135   TrackFitterOptions kfOptions(
0136       dummyGeoCtx, ctx.magFieldContext, ctx.calibContext, extensions,
0137       Acts::PropagatorPlainOptions(dummyGeoCtx, ctx.magFieldContext),
0138       firstSurf);
0139 
0140   // loop over tracks in the event
0141   std::vector<Acts::SourceLink> trackSourceLinks;
0142   for (const auto& track : tracks) {
0143     // for starting parameters for the re-fit, ask the
0144     // existing CKF track
0145     Acts::BoundTrackParameters refPar = track.createParametersAtReference();
0146 
0147     // Collect source links from this track
0148     trackSourceLinks.clear();
0149     trackSourceLinks.reserve(track.nTrackStates());
0150     for (const auto& state : track.trackStates()) {
0151       trackSourceLinks.push_back(state.getUncalibratedSourceLink());
0152     }
0153 
0154     // get the TrackAlignmentState using the existing
0155     // alignment class. This will compute the needed
0156     // residuals and derivatives.
0157     auto aliStates = m_align->evaluateTrackAlignmentState(
0158         dummyGeoCtx, trackSourceLinks, refPar, kfOptions, indexedAlignSurfaces,
0159         ActsAlignment::AlignmentMask::All  // use this to restrict alignment
0160                                            // degrees of freedom if desired
0161     );
0162 
0163     // and, if successful, dump the information into our Mille record.
0164     if (aliStates.ok()) {
0165       const ActsAlignment::detail::TrackAlignmentState& state = *aliStates;
0166       ActsPlugins::ActsToMille::dumpToMille(state, *m_milleOut);
0167     }
0168   }
0169 
0170   return ProcessCode::SUCCESS;
0171 }
0172 
0173 ProcessCode MillePedeAlignmentSandbox::finalize() {
0174   m_milleOut.reset();  // ensure that we do the final write of our output
0175                        // before subsequent algos finalise.
0176   return ProcessCode::SUCCESS;
0177 }
0178 
0179 }  // namespace ActsExamples