File indexing completed on 2025-10-14 08:01:15
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include "ActsExamples/Io/Root/RootMuonSpacePointWriter.hpp"
0018
0019 #include "Acts/Definitions/Units.hpp"
0020 #include "Acts/Seeding/detail/CompSpacePointAuxiliaries.hpp"
0021 #include "Acts/Surfaces/LineBounds.hpp"
0022 #include "Acts/Surfaces/RectangleBounds.hpp"
0023 #include "Acts/Surfaces/Surface.hpp"
0024 #include "Acts/Surfaces/TrapezoidBounds.hpp"
0025 #include "Acts/Utilities/Enumerate.hpp"
0026 #include "Acts/Utilities/VectorHelpers.hpp"
0027
0028 #include "TFile.h"
0029 #include "TTree.h"
0030
0031 using namespace Acts;
0032 using namespace Acts::UnitLiterals;
0033 using namespace Acts::VectorHelpers;
0034
0035
0036 constexpr GeometryIdentifier toChamberId(const GeometryIdentifier& id) {
0037 return GeometryIdentifier{}.withVolume(id.volume()).withLayer(id.layer());
0038 }
0039
0040
0041
0042 template <typename T, typename T1>
0043 void castPush(std::vector<T>& vec, const T1& val) {
0044
0045 const T castedVal = static_cast<T>(val);
0046 vec.push_back(castedVal);
0047
0048 }
0049
0050 constexpr double inDeg(const double radians) {
0051 if (Acts::abs(radians) < std::numeric_limits<float>::epsilon()) {
0052 return 0.;
0053 }
0054 using namespace Acts::UnitLiterals;
0055 return radians / 1._degree;
0056 }
0057 namespace ActsExamples {
0058 RootMuonSpacePointWriter::RootMuonSpacePointWriter(const Config& config,
0059 Logging::Level level)
0060 : WriterT(config.inputSpacePoints, "RootMuonSpacePointWriter", level),
0061 m_cfg{config} {
0062
0063 if (m_cfg.filePath.empty()) {
0064 throw std::invalid_argument("Missing file path");
0065 }
0066 if (m_cfg.treeName.empty()) {
0067 throw std::invalid_argument("Missing tree name");
0068 }
0069
0070
0071 m_file.reset(TFile::Open(m_cfg.filePath.c_str(), m_cfg.fileMode.c_str()));
0072 if (m_file == nullptr) {
0073 throw std::ios_base::failure("Could not open '" + m_cfg.filePath + "'");
0074 }
0075 m_file->cd();
0076 m_tree = new TTree(m_cfg.treeName.c_str(), m_cfg.treeName.c_str());
0077
0078 m_tree->Branch("event_id", &m_eventId);
0079 m_tree->Branch("spacePoint_bucketId", &m_bucketId);
0080 m_tree->Branch("spacePoint_geometryId", &m_geometryId);
0081 m_tree->Branch("spacePoint_muonId", &m_muonId);
0082 m_tree->Branch("spacePoint_localPosX", &m_localPositionX);
0083 m_tree->Branch("spacePoint_localPosY", &m_localPositionY);
0084 m_tree->Branch("spacePoint_localPosZ", &m_localPositionZ);
0085
0086 m_tree->Branch("spacePoint_sensorDirTheta", &m_sensorDirectionTheta);
0087 m_tree->Branch("spacePoint_sensorDirPhi", &m_sensorDirectionPhi);
0088
0089 m_tree->Branch("spacePoint_toNextDirTheta", &m_toNextSensorTheta);
0090 m_tree->Branch("spacePoint_toNextDirPhi", &m_toNextSensorPhi);
0091
0092 m_tree->Branch("spacePoint_covLoc0", &m_covLoc0);
0093 m_tree->Branch("spacePoint_covLoc1", &m_covLoc1);
0094 m_tree->Branch("spacePoint_covT", &m_covLocT);
0095
0096 m_tree->Branch("spacePoint_driftRadius", &m_driftR);
0097 m_tree->Branch("spacePoint_time", &m_time);
0098
0099 if (m_cfg.writeGlobal && m_cfg.trackingGeometry == nullptr) {
0100 throw std::runtime_error(
0101 "RootMuonSpacePointWriter() - Global coordinates can only be written "
0102 "with a tracking geometry");
0103 }
0104 if (m_cfg.writeGlobal) {
0105 m_tree->Branch("global_positionX", &m_globalPosX);
0106 m_tree->Branch("global_positionY", &m_globalPosY);
0107 m_tree->Branch("global_positionZ", &m_globalPosZ);
0108
0109 m_tree->Branch("global_lowEdgeX", &m_lowEdgeX);
0110 m_tree->Branch("global_lowEdgeY", &m_lowEdgeY);
0111 m_tree->Branch("global_lowEdgeZ", &m_lowEdgeZ);
0112
0113 m_tree->Branch("global_highEdgeX", &m_highEdgeX);
0114 m_tree->Branch("global_highEdgeY", &m_highEdgeY);
0115 m_tree->Branch("global_highEdgeZ", &m_highEdgeZ);
0116 }
0117 }
0118
0119 RootMuonSpacePointWriter::~RootMuonSpacePointWriter() = default;
0120 ProcessCode RootMuonSpacePointWriter::finalize() {
0121 m_file->cd();
0122 m_file->Write();
0123 m_file.reset();
0124 ACTS_INFO("Wrote muon spacepoints to tree '" << m_cfg.treeName << "' in '"
0125 << m_cfg.filePath << "'");
0126
0127 return ProcessCode::SUCCESS;
0128 }
0129 ProcessCode RootMuonSpacePointWriter::writeT(
0130 const AlgorithmContext& ctx, const MuonSpacePointContainer& hits) {
0131 std::lock_guard lock{m_mutex};
0132 m_eventId = ctx.eventNumber;
0133 const Acts::GeometryContext gctx{};
0134 for (const auto& [counter, bucket] : enumerate(hits)) {
0135 for (const MuonSpacePoint& writeMe : bucket) {
0136 ACTS_VERBOSE("Dump space point " << writeMe);
0137
0138 castPush(m_bucketId, counter);
0139 castPush(m_geometryId, writeMe.geometryId().value());
0140 castPush(m_muonId, writeMe.id().toInt());
0141 castPush(m_localPositionX, writeMe.localPosition().x());
0142 castPush(m_localPositionY, writeMe.localPosition().y());
0143 castPush(m_localPositionZ, writeMe.localPosition().z());
0144
0145 castPush(m_sensorDirectionTheta, inDeg(theta(writeMe.sensorDirection())));
0146 castPush(m_sensorDirectionPhi, inDeg(phi(writeMe.sensorDirection())));
0147
0148 castPush(m_toNextSensorTheta, inDeg(theta(writeMe.toNextSensor())));
0149 castPush(m_toNextSensorPhi, inDeg(phi(writeMe.toNextSensor())));
0150
0151 const auto& cov = writeMe.covariance();
0152 {
0153 using namespace Experimental::detail;
0154 using enum CompSpacePointAuxiliaries::ResidualIdx;
0155 castPush(m_covLoc0, cov[toUnderlying(nonBending)]);
0156 castPush(m_covLoc1, cov[toUnderlying(bending)]);
0157 castPush(m_covLocT, cov[toUnderlying(time)]);
0158 }
0159 castPush(m_driftR, writeMe.driftRadius());
0160 castPush(m_time, writeMe.time());
0161 if (!m_cfg.writeGlobal || writeMe.geometryId() == GeometryIdentifier{}) {
0162 continue;
0163 }
0164 const Surface* surface =
0165 m_cfg.trackingGeometry->findSurface(writeMe.geometryId());
0166 assert(surface != nullptr);
0167 const TrackingVolume* chambVol =
0168 m_cfg.trackingGeometry->findVolume(toChamberId(writeMe.geometryId()));
0169 assert(chambVol != nullptr);
0170
0171 const Vector3 globPos = chambVol->transform() *
0172 AngleAxis3{-90._degree, Vector3::UnitZ()} *
0173 writeMe.localPosition();
0174 castPush(m_globalPosX, globPos.x());
0175 castPush(m_globalPosY, globPos.y());
0176 castPush(m_globalPosZ, globPos.z());
0177
0178 const auto& bounds{surface->bounds()};
0179 const auto& trf{surface->transform(gctx)};
0180 Acts::Vector3 lowEdge{Vector3::Zero()};
0181 Acts::Vector3 highEdge{Vector3::Zero()};
0182 switch (bounds.type()) {
0183 using enum Acts::SurfaceBounds::BoundsType;
0184 case eLine: {
0185 const auto& lBounds = static_cast<const LineBounds&>(bounds);
0186 const double l = lBounds.get(LineBounds::eHalfLengthZ);
0187 lowEdge = trf * (-l * Vector3::UnitZ());
0188 highEdge = trf * (l * Vector3::UnitZ());
0189 break;
0190 }
0191 case eRectangle: {
0192 const auto& rBounds = static_cast<const RectangleBounds&>(bounds);
0193 const double l =
0194 rBounds.get(writeMe.measuresLoc1() ? RectangleBounds::eMaxX
0195 : RectangleBounds::eMaxY);
0196 const auto dimIdx =
0197 static_cast<std::uint32_t>(writeMe.measuresLoc1() == false);
0198 lowEdge = trf * (-l * Vector3::Unit(dimIdx));
0199 highEdge = trf * (l * Vector3::Unit(dimIdx));
0200 break;
0201 }
0202 case eTrapezoid: {
0203 ACTS_WARNING(__FILE__ << ":" << __LINE__ << " Implement me");
0204 break;
0205 }
0206
0207 default:
0208 ACTS_ERROR("Unsupported bounds " << surface->toString(gctx));
0209 return ProcessCode::ABORT;
0210 }
0211 castPush(m_lowEdgeX, lowEdge.x());
0212 castPush(m_lowEdgeY, lowEdge.y());
0213 castPush(m_lowEdgeZ, lowEdge.z());
0214 castPush(m_highEdgeX, highEdge.x());
0215 castPush(m_highEdgeY, highEdge.y());
0216 castPush(m_highEdgeZ, highEdge.z());
0217 }
0218 }
0219 m_tree->Fill();
0220
0221 m_geometryId.clear();
0222 m_bucketId.clear();
0223 m_muonId.clear();
0224 m_localPositionX.clear();
0225 m_localPositionY.clear();
0226 m_localPositionZ.clear();
0227 m_sensorDirectionTheta.clear();
0228 m_sensorDirectionPhi.clear();
0229 m_toNextSensorTheta.clear();
0230 m_toNextSensorPhi.clear();
0231 m_covLoc0.clear();
0232 m_covLoc1.clear();
0233 m_covLocT.clear();
0234 m_driftR.clear();
0235 m_time.clear();
0236
0237 m_globalPosX.clear();
0238 m_globalPosY.clear();
0239 m_globalPosZ.clear();
0240
0241 m_lowEdgeX.clear();
0242 m_lowEdgeY.clear();
0243 m_lowEdgeZ.clear();
0244
0245 m_highEdgeX.clear();
0246 m_highEdgeY.clear();
0247 m_highEdgeZ.clear();
0248 return ProcessCode::SUCCESS;
0249 }
0250
0251 }