File indexing completed on 2026-11-06 09:27:29
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Io/Root/RootMaterialWriter.hpp"
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Geometry/ApproachDescriptor.hpp"
0013 #include "Acts/Geometry/BoundarySurfaceT.hpp"
0014 #include "Acts/Geometry/GeometryIdentifier.hpp"
0015 #include "Acts/Geometry/Layer.hpp"
0016 #include "Acts/Geometry/TrackingGeometry.hpp"
0017 #include "Acts/Geometry/TrackingVolume.hpp"
0018 #include "Acts/Material/BinnedSurfaceMaterial.hpp"
0019 #include "Acts/Material/IVolumeMaterial.hpp"
0020 #include "Acts/Material/InterpolatedMaterialMap.hpp"
0021 #include "Acts/Material/Material.hpp"
0022 #include "Acts/Material/MaterialGridHelper.hpp"
0023 #include "Acts/Material/TrackingGeometryMaterial.hpp"
0024 #include "Acts/Surfaces/Surface.hpp"
0025 #include "Acts/Surfaces/SurfaceArray.hpp"
0026 #include "Acts/Utilities/BinUtility.hpp"
0027 #include "Acts/Utilities/BinningData.hpp"
0028 #include "Acts/Utilities/Enumerate.hpp"
0029 #include "Acts/Utilities/Logger.hpp"
0030
0031 #include <cstddef>
0032 #include <ios>
0033 #include <stdexcept>
0034 #include <vector>
0035
0036 #include <TFile.h>
0037 #include <TH1.h>
0038 #include <TH2.h>
0039
0040 namespace ActsExamples {
0041
0042 RootMaterialWriter::RootMaterialWriter(const RootMaterialWriter::Config& config,
0043 Acts::Logging::Level level)
0044 : m_cfg(config),
0045 m_logger{Acts::getDefaultLogger("RootMaterialWriter", level)} {
0046
0047 if (m_cfg.accessorOptions.folderSurfaceNameBase.empty()) {
0048 throw std::invalid_argument("Missing surface folder name base");
0049 } else if (m_cfg.accessorOptions.folderVolumeNameBase.empty()) {
0050 throw std::invalid_argument("Missing volume folder name base");
0051 } else if (m_cfg.filePath.empty()) {
0052 throw std::invalid_argument("Missing file name");
0053 }
0054
0055
0056 m_outputFile = TFile::Open(m_cfg.filePath.c_str(), m_cfg.fileMode.c_str());
0057 if (m_outputFile == nullptr) {
0058 throw std::ios_base::failure("Could not open '" + m_cfg.filePath + "'");
0059 }
0060 }
0061
0062 void RootMaterialWriter::writeMaterial(
0063 const Acts::TrackingGeometryMaterial& detMaterial) {
0064
0065 m_outputFile->cd();
0066
0067 const auto& volumeMaps = detMaterial.volumeMaterials;
0068 if (!detMaterial.keyedSurfaces.empty()) {
0069 throw std::invalid_argument(
0070 "ROOT material output does not support stable keys; use JSON");
0071 }
0072
0073
0074 ActsPlugins::RootMaterialMapIo accessor(m_cfg.accessorConfig,
0075 m_logger->clone("RootMaterialMapIo"));
0076
0077 accessor.write(*m_outputFile, detMaterial, m_cfg.accessorOptions);
0078
0079
0080 for (auto& [key, value] : volumeMaps) {
0081
0082 const Acts::IVolumeMaterial* vMaterial = value.get();
0083 if (vMaterial == nullptr) {
0084 ACTS_WARNING("No material for volume " << key << " skipping");
0085 continue;
0086 }
0087
0088
0089 Acts::GeometryIdentifier geoID = key;
0090
0091 const auto gvolID = geoID.volume();
0092
0093
0094 std::string tdName = m_cfg.accessorOptions.folderVolumeNameBase.c_str();
0095 tdName += m_cfg.accessorConfig.volumePrefix + std::to_string(gvolID);
0096
0097
0098 m_outputFile->mkdir(tdName.c_str());
0099 m_outputFile->cd(tdName.c_str());
0100
0101 ACTS_VERBOSE("Writing out map at " << tdName);
0102
0103
0104 auto bvMaterial3D = dynamic_cast<const Acts::InterpolatedMaterialMap<
0105 Acts::MaterialMapLookup<Acts::MaterialGrid3D>>*>(vMaterial);
0106 auto bvMaterial2D = dynamic_cast<const Acts::InterpolatedMaterialMap<
0107 Acts::MaterialMapLookup<Acts::MaterialGrid2D>>*>(vMaterial);
0108
0109 int points = 1;
0110 if (bvMaterial3D != nullptr || bvMaterial2D != nullptr) {
0111
0112 std::vector<Acts::BinningData> binningData;
0113 if (bvMaterial3D != nullptr) {
0114 binningData = bvMaterial3D->binUtility().binningData();
0115 Acts::MaterialGrid3D grid = bvMaterial3D->getMapper().getGrid();
0116 points = static_cast<int>(grid.size());
0117 } else {
0118 binningData = bvMaterial2D->binUtility().binningData();
0119 Acts::MaterialGrid2D grid = bvMaterial2D->getMapper().getGrid();
0120 points = static_cast<int>(grid.size());
0121 }
0122
0123
0124 auto bins = static_cast<int>(binningData.size());
0125 auto fBins = static_cast<float>(bins);
0126
0127
0128 TH1F n(m_cfg.accessorConfig.nBinsHistName.c_str(), "bins; bin", bins,
0129 -0.5, fBins - 0.5);
0130
0131
0132 TH1F v(m_cfg.accessorConfig.axisDirHistName.c_str(),
0133 "binning values; bin", bins, -0.5, fBins - 0.5);
0134
0135
0136 TH1F o(m_cfg.accessorConfig.axisBoundaryTypeHistName.c_str(),
0137 "binning options; bin", bins, -0.5, fBins - 0.5);
0138
0139
0140 TH1F rmin(m_cfg.accessorConfig.minRangeHistName.c_str(), "min; bin", bins,
0141 -0.5, fBins - 0.5);
0142
0143
0144 TH1F rmax(m_cfg.accessorConfig.maxRangeHistName.c_str(), "max; bin", bins,
0145 -0.5, fBins - 0.5);
0146
0147
0148 for (const auto& [b, bData] : enumerate(binningData)) {
0149
0150 n.SetBinContent(static_cast<int>(b),
0151 static_cast<int>(binningData[b - 1].bins()));
0152 v.SetBinContent(static_cast<int>(b),
0153 static_cast<int>(binningData[b - 1].binvalue));
0154 o.SetBinContent(static_cast<int>(b),
0155 static_cast<int>(binningData[b - 1].option));
0156 rmin.SetBinContent(static_cast<int>(b), binningData[b - 1].min);
0157 rmax.SetBinContent(static_cast<int>(b), binningData[b - 1].max);
0158 }
0159 n.Write();
0160 v.Write();
0161 o.Write();
0162 rmin.Write();
0163 rmax.Write();
0164 }
0165
0166 auto fPoints = static_cast<float>(points);
0167 TH1F x0(m_cfg.accessorConfig.x0HistName.c_str(), "X_{0} [mm] ;gridPoint",
0168 points, -0.5, fPoints - 0.5);
0169 TH1F l0(m_cfg.accessorConfig.l0HistName.c_str(),
0170 "#Lambda_{0} [mm] ;gridPoint", points, -0.5, fPoints - 0.5);
0171 TH1F A(m_cfg.accessorConfig.aHistName.c_str(), "X_{0} [mm] ;gridPoint",
0172 points, -0.5, fPoints - 0.5);
0173 TH1F Z(m_cfg.accessorConfig.zHistName.c_str(),
0174 "#Lambda_{0} [mm] ;gridPoint", points, -0.5, fPoints - 0.5);
0175 TH1F rho(m_cfg.accessorConfig.rhoHistName.c_str(),
0176 "#rho [g/mm^3] ;gridPoint", points, -0.5, fPoints - 0.5);
0177
0178 if (points == 1) {
0179 auto mat = vMaterial->material({0, 0, 0});
0180 x0.SetBinContent(1, mat.X0());
0181 l0.SetBinContent(1, mat.L0());
0182 A.SetBinContent(1, mat.Ar());
0183 Z.SetBinContent(1, mat.Z());
0184 rho.SetBinContent(1, mat.massDensity());
0185 } else {
0186
0187 if (bvMaterial3D != nullptr) {
0188 Acts::MaterialGrid3D grid = bvMaterial3D->getMapper().getGrid();
0189 for (int point = 0; point < points; point++) {
0190 auto mat = Acts::Material(grid.at(point));
0191 if (!mat.isVacuum()) {
0192 x0.SetBinContent(point + 1, mat.X0());
0193 l0.SetBinContent(point + 1, mat.L0());
0194 A.SetBinContent(point + 1, mat.Ar());
0195 Z.SetBinContent(point + 1, mat.Z());
0196 rho.SetBinContent(point + 1, mat.massDensity());
0197 }
0198 }
0199 }
0200
0201 else if (bvMaterial2D != nullptr) {
0202 Acts::MaterialGrid2D grid = bvMaterial2D->getMapper().getGrid();
0203 for (int point = 0; point < points; point++) {
0204 auto mat = Acts::Material(grid.at(point));
0205 if (!mat.isVacuum()) {
0206 x0.SetBinContent(point + 1, mat.X0());
0207 l0.SetBinContent(point + 1, mat.L0());
0208 A.SetBinContent(point + 1, mat.Ar());
0209 Z.SetBinContent(point + 1, mat.Z());
0210 rho.SetBinContent(point + 1, mat.massDensity());
0211 }
0212 }
0213 }
0214 }
0215 x0.Write();
0216 l0.Write();
0217 A.Write();
0218 Z.Write();
0219 rho.Write();
0220 }
0221 }
0222
0223 RootMaterialWriter::~RootMaterialWriter() {
0224 if (m_outputFile != nullptr) {
0225 m_outputFile->Close();
0226 }
0227 }
0228
0229 void RootMaterialWriter::write(const Acts::TrackingGeometry& tGeometry) {
0230
0231 Acts::TrackingGeometryMaterial detMatMap;
0232 auto hVolume = tGeometry.highestTrackingVolume();
0233 if (hVolume != nullptr) {
0234 collectMaterial(*hVolume, detMatMap);
0235 }
0236
0237 writeMaterial(detMatMap);
0238 }
0239
0240 void RootMaterialWriter::collectMaterial(
0241 const Acts::TrackingVolume& tVolume,
0242 Acts::TrackingGeometryMaterial& detMatMap) {
0243
0244 if (tVolume.volumeMaterialPtr() != nullptr && m_cfg.processVolumes) {
0245 detMatMap.volumeMaterials[tVolume.geometryId()] =
0246 tVolume.volumeMaterialPtr();
0247 }
0248
0249
0250 if (tVolume.confinedLayers() != nullptr) {
0251 ACTS_VERBOSE("Collecting material for " << tVolume.volumeName()
0252 << " layers");
0253 for (auto& lay : tVolume.confinedLayers()->arrayObjects()) {
0254 collectMaterial(*lay, detMatMap);
0255 }
0256 }
0257
0258
0259 if (m_cfg.processBoundaries) {
0260 for (auto& bou : tVolume.boundarySurfaces()) {
0261 const auto& bSurface = bou->surfaceRepresentation();
0262 if (bSurface.surfaceMaterialSharedPtr() != nullptr) {
0263 detMatMap.surfaceMaterials[bSurface.geometryId()] =
0264 bSurface.surfaceMaterialSharedPtr();
0265 }
0266 }
0267 }
0268
0269
0270 if (tVolume.confinedVolumes() != nullptr) {
0271 for (auto& tvol : tVolume.confinedVolumes()->arrayObjects()) {
0272 collectMaterial(*tvol, detMatMap);
0273 }
0274 }
0275 }
0276
0277 void RootMaterialWriter::collectMaterial(
0278 const Acts::Layer& tLayer, Acts::TrackingGeometryMaterial& detMatMap) {
0279
0280 const auto& rSurface = tLayer.surfaceRepresentation();
0281 if (rSurface.surfaceMaterialSharedPtr() != nullptr &&
0282 m_cfg.processRepresenting) {
0283 detMatMap.surfaceMaterials[rSurface.geometryId()] =
0284 rSurface.surfaceMaterialSharedPtr();
0285 }
0286
0287
0288 if (tLayer.approachDescriptor() != nullptr && m_cfg.processApproaches) {
0289 for (auto& aSurface : tLayer.approachDescriptor()->containedSurfaces()) {
0290 if (aSurface->surfaceMaterialSharedPtr() != nullptr) {
0291 detMatMap.surfaceMaterials[aSurface->geometryId()] =
0292 aSurface->surfaceMaterialSharedPtr();
0293 }
0294 }
0295 }
0296
0297
0298 if (tLayer.surfaceArray() != nullptr && m_cfg.processSensitives) {
0299
0300 for (auto& sSurface : tLayer.surfaceArray()->surfaces()) {
0301 if (sSurface->surfaceMaterialSharedPtr() != nullptr) {
0302 detMatMap.surfaceMaterials[sSurface->geometryId()] =
0303 sSurface->surfaceMaterialSharedPtr();
0304 }
0305 }
0306 }
0307 }
0308
0309 }