Skip to content
Snippets Groups Projects
TrackProjector.cpp 8.89 KiB
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright (C) 2022 wfan, Whitney Armstrong, Sylvester Joosten

#include <algorithm>

// Gaudi
#include "GaudiAlg/GaudiAlgorithm.h"
#include "GaudiKernel/ToolHandle.h"
#include "GaudiAlg/Transformer.h"
#include "GaudiAlg/GaudiTool.h"
#include "GaudiKernel/RndmGenerators.h"
#include "Gaudi/Property.h"

#include "DDRec/CellIDPositionConverter.h"
#include "DDRec/SurfaceManager.h"
#include "DDRec/Surface.h"

#include "JugBase/DataHandle.h"
#include "JugBase/IGeoSvc.h"

#include "Acts/EventData/MultiTrajectory.hpp"
#include "Acts/EventData/MultiTrajectoryHelpers.hpp"

// Event Model related classes
#include "edm4eic/EDM4eicVersion.h"
#include "edm4eic/TrackerHitCollection.h"
#include "edm4eic/TrackParametersCollection.h"
#include "edm4eic/TrajectoryCollection.h"
#include "edm4eic/TrackSegmentCollection.h"
#include "JugTrack/IndexSourceLink.hpp"
#include "JugTrack/Track.hpp"
#include "JugTrack/Trajectories.hpp"

#include "Acts/Utilities/Helpers.hpp"
#include "Acts/Geometry/GeometryIdentifier.hpp"
#include "Acts/MagneticField/ConstantBField.hpp"
#include "Acts/MagneticField/InterpolatedBFieldMap.hpp"
#include "Acts/Propagator/EigenStepper.hpp"
#include "Acts/Surfaces/PerigeeSurface.hpp"

#include "edm4eic/vector_utils.h"

#include <cmath>

namespace Jug::Reco {

  /** Extrac the particles form fit trajectories.
   *
   * \ingroup tracking
   */
   class TrackProjector : public GaudiAlgorithm {
   private:
    DataHandle<TrajectoriesContainer>        m_inputTrajectories{"inputTrajectories", Gaudi::DataHandle::Reader, this};
    DataHandle<edm4eic::TrackSegmentCollection> m_outputTrackSegments{"outputTrackSegments", Gaudi::DataHandle::Writer, this};

    Gaudi::Property<unsigned int> m_firstInVolumeID{this, "firstInVolumeID", 0};
    Gaudi::Property<std::string> m_firstInVolumeName{this, "firstInVolumeName", ""};
    Gaudi::Property<float> m_firstSmallerThanZ{this, "firstSmallerThanZ", 0};
    Gaudi::Property<float> m_firstGreaterThanZ{this, "firstGreaterThanZ", 0};
    Gaudi::Property<float> m_firstGreaterThanR{this, "firstGreaterThanR", -1};

    Acts::GeometryContext m_geoContext;

    public:
    //  ill-formed: using GaudiAlgorithm::GaudiAlgorithm;
    TrackProjector(const std::string& name, ISvcLocator* svcLoc)
        : GaudiAlgorithm(name, svcLoc) {
          declareProperty("inputTrajectories", m_inputTrajectories,"");
          declareProperty("outputTrackSegments", m_outputTrackSegments, "");
        }

    StatusCode initialize() override {
      if (GaudiAlgorithm::initialize().isFailure())
        return StatusCode::FAILURE;
      return StatusCode::SUCCESS;
    }

    StatusCode execute() override {
      // input collection
      const auto* const trajectories = m_inputTrajectories.get();
      // create output collections
      auto* track_segments = m_outputTrackSegments.createAndPut();

      if (msgLevel(MSG::DEBUG)) {
        debug() << std::size(*trajectories) << " trajectories " << endmsg;
      }

      // Loop over the trajectories
      for (const auto& traj : *trajectories) {
        // Get the entry index for the single trajectory
        // The trajectory entry indices and the multiTrajectory
        const auto& mj        = traj.multiTrajectory();
        const auto& trackTips = traj.tips();
        if (msgLevel(MSG::DEBUG)) {
          debug() << "# of elements in trackTips " <<trackTips.size() << endmsg;
        }

        // Skip empty
        if (trackTips.empty()) {
          if (msgLevel(MSG::DEBUG)) {
            debug() << "Empty multiTrajectory." << endmsg;
          }
          continue;
        }
        auto& trackTip = trackTips.front();

        // Collect the trajectory summary info
        auto trajState       = Acts::MultiTrajectoryHelpers::trajectoryState(mj, trackTip);
        int  m_nMeasurements = trajState.nMeasurements;
        int  m_nStates       = trajState.nStates;
        int  m_nCalibrated   = 0;
        if (msgLevel(MSG::DEBUG)) {
          debug() << "n measurement in trajectory " << m_nMeasurements << endmsg;
          debug() << "n state in trajectory " << m_nStates << endmsg;
        }

        edm4eic::MutableTrackSegment track_segment;

        // visit the track points
        mj.visitBackwards(trackTip, [&](auto&& trackstate) {
          // get volume info
          auto geoID = trackstate.referenceSurface().geometryId();
          auto volume = geoID.volume();
          auto layer = geoID.layer();
          if (trackstate.hasCalibrated()) {
            m_nCalibrated++;
          }

          // get track state parameters and their covariances
          const auto& parameter = trackstate.predicted();
          const auto& covariance = trackstate.predictedCovariance();

          // convert local to global
          auto global = trackstate.referenceSurface().localToGlobal(
            m_geoContext,
            {parameter[Acts::eBoundLoc0], parameter[Acts::eBoundLoc1]},
            {0, 0, 0}
          );
          // global position
          const decltype(edm4eic::TrackPoint::position) position {
            static_cast<float>(global.x()),
            static_cast<float>(global.y()),
            static_cast<float>(global.z())
          };

          // local position
          const decltype(edm4eic::TrackParametersData::loc) loc {
            static_cast<float>(parameter[Acts::eBoundLoc0]),
            static_cast<float>(parameter[Acts::eBoundLoc1])
          };
          const decltype(edm4eic::TrackParametersData::locError) locError {
            static_cast<float>(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0)),
            static_cast<float>(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1)),
            static_cast<float>(covariance(Acts::eBoundLoc0, Acts::eBoundLoc1))
          };
          const decltype(edm4eic::TrackPoint::positionError) positionError{0, 0, 0};
          const decltype(edm4eic::TrackPoint::momentum) momentum = edm4eic::sphericalToVector(
            static_cast<float>(1.0 / std::abs(parameter[Acts::eBoundQOverP])),
            static_cast<float>(parameter[Acts::eBoundTheta]),
            static_cast<float>(parameter[Acts::eBoundPhi])
          );
          const decltype(edm4eic::TrackPoint::momentumError) momentumError {
            static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundTheta)),
            static_cast<float>(covariance(Acts::eBoundPhi, Acts::eBoundPhi)),
            static_cast<float>(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP)),
            static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundPhi)),
            static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundQOverP)),
            static_cast<float>(covariance(Acts::eBoundPhi, Acts::eBoundQOverP))
          };
          const float time{static_cast<float>(parameter(Acts::eBoundTime))};
          const float timeError{sqrt(static_cast<float>(covariance(Acts::eBoundTime, Acts::eBoundTime)))};
          const float theta(parameter[Acts::eBoundTheta]);
          const float phi(parameter[Acts::eBoundPhi]);
          const decltype(edm4eic::TrackPoint::directionError) directionError {
            static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundTheta)),
            static_cast<float>(covariance(Acts::eBoundPhi, Acts::eBoundPhi)),
            static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundPhi))
          };
          const float pathLength = static_cast<float>(trackstate.pathLength());
          const float pathLengthError = 0;

#if EDM4EIC_VERSION_MAJOR >= 3
          uint64_t surface = 0; // trackstate.referenceSurface().geometryId().value(); FIXME - ASAN is not happy with this
          uint32_t system = 0;
#endif

          // Store track point
          track_segment.addToPoints({
#if EDM4EIC_VERSION_MAJOR >= 3
            surface,
            system,
#endif
            position,
            positionError,
            momentum,
            momentumError,
            time,
            timeError,
            theta,
            phi,
            directionError,
            pathLength,
            pathLengthError
          });

          if (msgLevel(MSG::DEBUG)) {
            debug() << "******************************" << endmsg;
            debug() << "predicted variables: \n" << trackstate.predicted() << endmsg;
            debug() << "geoID = " << geoID << endmsg;
            debug() << "volume = " << volume << ", layer = " << layer << endmsg;
            debug() << "pathlength = " << pathLength << endmsg;
            debug() << "hasCalibrated = " << trackstate.hasCalibrated() << endmsg;
            debug() << "******************************" << endmsg;
          }
        });

        if (msgLevel(MSG::DEBUG)) {
          debug() << "n calibrated state in trajectory " << m_nCalibrated << endmsg;
        }

        // Add to output collection
        track_segments->push_back(track_segment);
      }

      return StatusCode::SUCCESS;
    }

  };
  // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
  DECLARE_COMPONENT(TrackProjector)

} // namespace Jug::Reco