File indexing completed on 2026-03-28 07:46:18
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsPlugins/Root/RootMaterialMapIo.hpp"
0010
0011 #include "Acts/Geometry/GeometryIdentifier.hpp"
0012 #include "Acts/Material/BinnedSurfaceMaterial.hpp"
0013 #include "Acts/Material/GridSurfaceMaterial.hpp"
0014 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
0015 #include "Acts/Material/Material.hpp"
0016 #include "Acts/Material/MaterialSlab.hpp"
0017 #include "Acts/Surfaces/Surface.hpp"
0018 #include "Acts/Utilities/Enumerate.hpp"
0019
0020 #include <TFile.h>
0021 #include <TH1I.h>
0022 #include <TH2F.h>
0023 #include <TKey.h>
0024 #include <TList.h>
0025 #include <TObject.h>
0026 #include <TTree.h>
0027 #include <boost/algorithm/string.hpp>
0028 #include <boost/algorithm/string/finder.hpp>
0029 #include <boost/algorithm/string/iter_find.hpp>
0030
0031 using namespace Acts;
0032
0033 void ActsPlugins::RootMaterialMapIo::write(
0034 TFile& rFile, const GeometryIdentifier& geoID,
0035 const ISurfaceMaterial& surfaceMaterial, const Options& options) {
0036
0037 rFile.cd();
0038
0039
0040 auto homogeneousMaterial =
0041 dynamic_cast<const HomogeneousSurfaceMaterial*>(&surfaceMaterial);
0042 if (homogeneousMaterial != nullptr) {
0043 if (m_hTree == nullptr) {
0044 m_hTree = new TTree(options.homogeneousMaterialTreeName.c_str(),
0045 "Homogeneous Material Tree");
0046 connectForWrite(*m_hTree, m_homogenousMaterialTreePayload);
0047 }
0048 fillMaterialSlab(m_homogenousMaterialTreePayload,
0049 homogeneousMaterial->materialSlab());
0050 m_homogenousMaterialTreePayload.hGeoId = geoID.value();
0051 m_hTree->Fill();
0052 return;
0053 }
0054
0055
0056 auto bsMaterial =
0057 dynamic_cast<const BinnedSurfaceMaterial*>(&surfaceMaterial);
0058 if (bsMaterial != nullptr) {
0059
0060 const auto gvolID = geoID.volume();
0061 const auto gbouID = geoID.boundary();
0062 const auto glayID = geoID.layer();
0063 const auto gappID = geoID.approach();
0064 const auto gsenID = geoID.sensitive();
0065
0066 std::string tdName = options.folderSurfaceNameBase.c_str();
0067 tdName += m_cfg.volumePrefix + std::to_string(gvolID);
0068 tdName += m_cfg.portalPrefix + std::to_string(gbouID);
0069 tdName += m_cfg.layerPrefix + std::to_string(glayID);
0070 tdName += m_cfg.passivePrefix + std::to_string(gappID);
0071 tdName += m_cfg.sensitivePrefix + std::to_string(gsenID);
0072
0073 rFile.mkdir(tdName.c_str());
0074 rFile.cd(tdName.c_str());
0075
0076
0077
0078 auto& binningData = bsMaterial->binUtility().binningData();
0079
0080 auto bins = static_cast<int>(binningData.size());
0081 auto fBins = static_cast<float>(bins);
0082
0083
0084 TH1F n(m_cfg.nBinsHistName.c_str(), "bins; bin", bins, -0.5, fBins - 0.5);
0085
0086
0087 TH1F v(m_cfg.axisDirHistName.c_str(), "binning values; bin", bins, -0.5,
0088 fBins - 0.5);
0089
0090
0091 TH1F o(m_cfg.axisBoundaryTypeHistName.c_str(), "binning options; bin", bins,
0092 -0.5, fBins - 0.5);
0093
0094
0095 TH1F rmin(m_cfg.minRangeHistName.c_str(), "min; bin", bins, -0.5,
0096 fBins - 0.5);
0097
0098
0099 TH1F rmax(m_cfg.maxRangeHistName.c_str(), "max; bin", bins, -0.5,
0100 fBins - 0.5);
0101
0102
0103 for (auto [b, bData] : enumerate(binningData)) {
0104
0105 n.SetBinContent(static_cast<int>(b) + 1, static_cast<int>(bData.bins()));
0106 v.SetBinContent(static_cast<int>(b) + 1,
0107 static_cast<int>(bData.binvalue));
0108 o.SetBinContent(static_cast<int>(b) + 1, static_cast<int>(bData.option));
0109 rmin.SetBinContent(static_cast<int>(b) + 1, bData.min);
0110 rmax.SetBinContent(static_cast<int>(b) + 1, bData.max);
0111 }
0112 n.Write();
0113 v.Write();
0114 o.Write();
0115 rmin.Write();
0116 rmax.Write();
0117
0118
0119
0120 if (!options.indexedMaterial) {
0121 fillBinnedSurfaceMaterial(*bsMaterial);
0122 return;
0123 }
0124
0125
0126 if (m_gTree == nullptr) {
0127
0128 rFile.cd();
0129 m_gTree = new TTree(options.indexedMaterialTreeName.c_str(),
0130 "Indexed Material Tree");
0131 connectForWrite(*m_gTree, m_indexedMaterialTreePayload);
0132
0133 rFile.cd(tdName.c_str());
0134 }
0135 fillBinnedSurfaceMaterial(m_indexedMaterialTreePayload, *bsMaterial);
0136 return;
0137 }
0138 }
0139
0140 void ActsPlugins::RootMaterialMapIo::write(
0141 TFile& rFile, const TrackingGeometryMaterial& detectorMaterial,
0142 const Options& options) {
0143 const auto& [surfaceMaterials, volumeMaterials] = detectorMaterial;
0144 for (const auto& [geoID, sMaterial] : surfaceMaterials) {
0145 write(rFile, geoID, *sMaterial, options);
0146 }
0147 if (m_hTree != nullptr) {
0148 m_hTree->Write();
0149 }
0150 if (m_gTree != nullptr) {
0151 m_gTree->Write();
0152 }
0153 }
0154
0155 void ActsPlugins::RootMaterialMapIo::connectForWrite(
0156 TTree& rTree, MaterialTreePayload& treePayload) {
0157 if (&treePayload == &m_homogenousMaterialTreePayload) {
0158 rTree.Branch("hGeoId", &treePayload.hGeoId);
0159 }
0160 rTree.Branch(m_cfg.thicknessHistName.c_str(), &treePayload.ht);
0161 rTree.Branch(m_cfg.x0HistName.c_str(), &treePayload.hX0);
0162 rTree.Branch(m_cfg.l0HistName.c_str(), &treePayload.hL0);
0163 rTree.Branch(m_cfg.aHistName.c_str(), &treePayload.hA);
0164 rTree.Branch(m_cfg.zHistName.c_str(), &treePayload.hZ);
0165 rTree.Branch(m_cfg.rhoHistName.c_str(), &treePayload.hRho);
0166 }
0167
0168 void ActsPlugins::RootMaterialMapIo::connectForRead(
0169 TTree& rTree, MaterialTreePayload& treePayload) {
0170 if (&treePayload == &m_homogenousMaterialTreePayload) {
0171 rTree.SetBranchAddress("hGeoId", &treePayload.hGeoId);
0172 }
0173 rTree.SetBranchAddress(m_cfg.thicknessHistName.c_str(), &treePayload.ht);
0174 rTree.SetBranchAddress(m_cfg.x0HistName.c_str(), &treePayload.hX0);
0175 rTree.SetBranchAddress(m_cfg.l0HistName.c_str(), &treePayload.hL0);
0176 rTree.SetBranchAddress(m_cfg.aHistName.c_str(), &treePayload.hA);
0177 rTree.SetBranchAddress(m_cfg.zHistName.c_str(), &treePayload.hZ);
0178 rTree.SetBranchAddress(m_cfg.rhoHistName.c_str(), &treePayload.hRho);
0179 }
0180
0181 void ActsPlugins::RootMaterialMapIo::fillMaterialSlab(
0182 MaterialTreePayload& payload, const MaterialSlab& materialSlab) {
0183 payload.ht = materialSlab.thickness();
0184 payload.hX0 = materialSlab.material().X0();
0185 payload.hL0 = materialSlab.material().L0();
0186 payload.hA = materialSlab.material().Ar();
0187 payload.hZ = materialSlab.material().Z();
0188 payload.hRho = materialSlab.material().massDensity();
0189 }
0190
0191 void ActsPlugins::RootMaterialMapIo::fillBinnedSurfaceMaterial(
0192 const BinnedSurfaceMaterial& bsMaterial) {
0193 auto bins0 = static_cast<int>(bsMaterial.binUtility().bins(0));
0194 auto bins1 = static_cast<int>(bsMaterial.binUtility().bins(1));
0195 auto fBins0 = static_cast<float>(bins0);
0196 auto fBins1 = static_cast<float>(bins1);
0197
0198 TH2F t(m_cfg.thicknessHistName.c_str(), "thickness [mm] ;b0 ;b1", bins0, -0.5,
0199 fBins0 - 0.5, bins1, -0.5, fBins1 - 0.5);
0200 TH2F x0(m_cfg.x0HistName.c_str(), "X_{0} [mm] ;b0 ;b1", bins0, -0.5,
0201 fBins0 - 0.5, bins1, -0.5, fBins1 - 0.5);
0202 TH2F l0(m_cfg.l0HistName.c_str(), "#Lambda_{0} [mm] ;b0 ;b1", bins0, -0.5,
0203 fBins0 - 0.5, bins1, -0.5, fBins1 - 0.5);
0204 TH2F A(m_cfg.aHistName.c_str(), "X_{0} [mm] ;b0 ;b1", bins0, -0.5,
0205 fBins0 - 0.5, bins1, -0.5, fBins1 - 0.5);
0206 TH2F Z(m_cfg.zHistName.c_str(), "#Lambda_{0} [mm] ;b0 ;b1", bins0, -0.5,
0207 fBins0 - 0.5, bins1, -0.5, fBins1 - 0.5);
0208 TH2F rho(m_cfg.rhoHistName.c_str(), "#rho [g/mm^3] ;b0 ;b1", bins0, -0.5,
0209 fBins0 - 0.5, bins1, -0.5, fBins1 - 0.5);
0210
0211
0212 const auto& materialMatrix = bsMaterial.fullMaterial();
0213 for (auto [b1, materialVector] : enumerate(materialMatrix)) {
0214 for (auto [b0, mat] : enumerate(materialVector)) {
0215 t.SetBinContent(static_cast<int>(b0) + 1, static_cast<int>(b1) + 1,
0216 mat.thickness());
0217 x0.SetBinContent(static_cast<int>(b0) + 1, static_cast<int>(b1) + 1,
0218 mat.material().X0());
0219 l0.SetBinContent(static_cast<int>(b0) + 1, static_cast<int>(b1) + 1,
0220 mat.material().L0());
0221 A.SetBinContent(static_cast<int>(b0) + 1, static_cast<int>(b1) + 1,
0222 mat.material().Ar());
0223 Z.SetBinContent(static_cast<int>(b0) + 1, static_cast<int>(b1) + 1,
0224 mat.material().Z());
0225 rho.SetBinContent(static_cast<int>(b0) + 1, static_cast<int>(b1) + 1,
0226 mat.material().massDensity());
0227 }
0228 }
0229 t.Write();
0230 x0.Write();
0231 l0.Write();
0232 A.Write();
0233 Z.Write();
0234 rho.Write();
0235 }
0236
0237 void ActsPlugins::RootMaterialMapIo::fillBinnedSurfaceMaterial(
0238 MaterialTreePayload& payload, const BinnedSurfaceMaterial& bsMaterial) {
0239 std::size_t bins0 = bsMaterial.binUtility().bins(0);
0240 std::size_t bins1 = bsMaterial.binUtility().bins(1);
0241
0242 TH2I idx(m_cfg.indexHistName.c_str(), "indices; bin0; bin1",
0243 static_cast<int>(bins0), -0.5, static_cast<float>(bins0) - 0.5,
0244 static_cast<int>(bins1), -0.5, static_cast<float>(bins1) - 0.5);
0245
0246 const auto& materialMatrix = bsMaterial.fullMaterial();
0247 for (auto [b1, materialVector] : enumerate(materialMatrix)) {
0248 for (auto [b0, mat] : enumerate(materialVector)) {
0249 idx.SetBinContent(static_cast<int>(b0) + 1, static_cast<int>(b1) + 1,
0250 static_cast<float>(payload.index));
0251 payload.index++;
0252 fillMaterialSlab(payload, mat);
0253 m_gTree->Fill();
0254 }
0255 }
0256 idx.Write();
0257 }
0258
0259 TrackingGeometryMaterial ActsPlugins::RootMaterialMapIo::read(
0260 TFile& rFile, const Options& options) {
0261 TrackingGeometryMaterial detectorMaterial;
0262
0263 auto& [surfaceMaterials, volumeMaterials] = detectorMaterial;
0264
0265 auto homogeneousMaterialTree = dynamic_cast<TTree*>(
0266 rFile.Get(options.homogeneousMaterialTreeName.c_str()));
0267
0268
0269 if (homogeneousMaterialTree != nullptr) {
0270 connectForRead(*homogeneousMaterialTree, m_homogenousMaterialTreePayload);
0271 for (int i = 0; i < homogeneousMaterialTree->GetEntries(); ++i) {
0272 homogeneousMaterialTree->GetEntry(i);
0273 GeometryIdentifier geoID(m_homogenousMaterialTreePayload.hGeoId);
0274 MaterialSlab materialSlab(
0275 Material::fromMassDensity(m_homogenousMaterialTreePayload.hX0,
0276 m_homogenousMaterialTreePayload.hL0,
0277 m_homogenousMaterialTreePayload.hA,
0278 m_homogenousMaterialTreePayload.hZ,
0279 m_homogenousMaterialTreePayload.hRho),
0280 m_homogenousMaterialTreePayload.ht);
0281 auto homogeneousMaterial =
0282 std::make_shared<HomogeneousSurfaceMaterial>(materialSlab);
0283 surfaceMaterials.try_emplace(geoID, homogeneousMaterial);
0284 }
0285 }
0286
0287
0288 auto indexedMaterialTree =
0289 dynamic_cast<TTree*>(rFile.Get(options.indexedMaterialTreeName.c_str()));
0290 if (indexedMaterialTree != nullptr) {
0291 connectForRead(*indexedMaterialTree, m_indexedMaterialTreePayload);
0292 }
0293
0294
0295 TList* tlist = rFile.GetListOfKeys();
0296 auto tIter = tlist->MakeIterator();
0297 tIter->Reset();
0298
0299
0300 while (auto key = static_cast<TKey*>(tIter->Next())) {
0301
0302 std::string tdName(key->GetName());
0303
0304 ACTS_VERBOSE("Processing directory: " << tdName);
0305
0306
0307 std::vector<std::string> splitNames;
0308 iter_split(splitNames, tdName,
0309 boost::algorithm::first_finder(m_cfg.volumePrefix));
0310
0311 if (splitNames[0] == options.folderSurfaceNameBase) {
0312
0313 std::shared_ptr<const ISurfaceMaterial> sMaterial = nullptr;
0314
0315 boost::split(splitNames, splitNames[1], boost::is_any_of("_"));
0316 GeometryIdentifier::Value volID = std::stoi(splitNames[0]);
0317
0318 iter_split(splitNames, tdName,
0319 boost::algorithm::first_finder(m_cfg.portalPrefix));
0320 boost::split(splitNames, splitNames[1], boost::is_any_of("_"));
0321 GeometryIdentifier::Value bouID = std::stoi(splitNames[0]);
0322
0323 iter_split(splitNames, tdName,
0324 boost::algorithm::first_finder(m_cfg.layerPrefix));
0325 boost::split(splitNames, splitNames[1], boost::is_any_of("_"));
0326 GeometryIdentifier::Value layID = std::stoi(splitNames[0]);
0327
0328 iter_split(splitNames, tdName,
0329 boost::algorithm::first_finder(m_cfg.passivePrefix));
0330 boost::split(splitNames, splitNames[1], boost::is_any_of("_"));
0331 GeometryIdentifier::Value appID = std::stoi(splitNames[0]);
0332
0333 iter_split(splitNames, tdName,
0334 boost::algorithm::first_finder(m_cfg.sensitivePrefix));
0335 GeometryIdentifier::Value senID = std::stoi(splitNames[1]);
0336
0337
0338 auto geoID = GeometryIdentifier()
0339 .withVolume(volID)
0340 .withBoundary(bouID)
0341 .withLayer(layID)
0342 .withApproach(appID)
0343 .withSensitive(senID);
0344
0345 ACTS_VERBOSE("GeometryIdentifier re-constructed as " << geoID);
0346
0347 auto texturedSurfaceMaterial =
0348 readTextureSurfaceMaterial(rFile, tdName, indexedMaterialTree);
0349 surfaceMaterials.try_emplace(geoID, texturedSurfaceMaterial);
0350 }
0351 }
0352 return detectorMaterial;
0353 }
0354
0355 std::shared_ptr<const ISurfaceMaterial>
0356 ActsPlugins::RootMaterialMapIo::readTextureSurfaceMaterial(
0357 TFile& rFile, const std::string& tdName, TTree* indexedMaterialTree) {
0358 std::shared_ptr<const ISurfaceMaterial> texturedSurfaceMaterial = nullptr;
0359
0360
0361 std::string nName = tdName + "/" + m_cfg.nBinsHistName;
0362 std::string vName = tdName + "/" + m_cfg.axisDirHistName;
0363 std::string oName = tdName + "/" + m_cfg.axisBoundaryTypeHistName;
0364 std::string minName = tdName + "/" + m_cfg.minRangeHistName;
0365 std::string maxName = tdName + "/" + m_cfg.maxRangeHistName;
0366
0367 auto n = dynamic_cast<TH1F*>(rFile.Get(nName.c_str()));
0368 auto v = dynamic_cast<TH1F*>(rFile.Get(vName.c_str()));
0369 auto o = dynamic_cast<TH1F*>(rFile.Get(oName.c_str()));
0370 auto minh = dynamic_cast<TH1F*>(rFile.Get(minName.c_str()));
0371 auto maxh = dynamic_cast<TH1F*>(rFile.Get(maxName.c_str()));
0372
0373 std::vector<const TH1*> hists{n, v, o, minh, maxh};
0374 if (std::ranges::any_of(hists,
0375 [](const auto* hist) { return hist == nullptr; })) {
0376 ACTS_ERROR(
0377 "Failed to read all required histograms for textured surface "
0378 "material from file: "
0379 << rFile.GetName());
0380 return nullptr;
0381 }
0382
0383
0384 BinUtility bUtility;
0385 for (int ib = 1; ib < n->GetNbinsX() + 1; ++ib) {
0386 auto nbins = static_cast<std::size_t>(n->GetBinContent(ib));
0387 auto val = static_cast<AxisDirection>(v->GetBinContent(ib));
0388 auto opt = static_cast<BinningOption>(o->GetBinContent(ib));
0389 auto rmin = static_cast<float>(minh->GetBinContent(ib));
0390 auto rmax = static_cast<float>(maxh->GetBinContent(ib));
0391 bUtility += BinUtility(nbins, rmin, rmax, opt, val);
0392 }
0393 ACTS_VERBOSE("Created " << bUtility);
0394
0395
0396 if (indexedMaterialTree == nullptr) {
0397
0398 std::string tName = tdName + "/" + m_cfg.thicknessHistName;
0399 std::string x0Name = tdName + "/" + m_cfg.x0HistName;
0400 std::string l0Name = tdName + "/" + m_cfg.l0HistName;
0401 std::string aName = tdName + "/" + m_cfg.aHistName;
0402 std::string zName = tdName + "/" + m_cfg.zHistName;
0403 std::string rhoName = tdName + "/" + m_cfg.rhoHistName;
0404
0405
0406 auto t = dynamic_cast<TH2F*>(rFile.Get(tName.c_str()));
0407 auto x0 = dynamic_cast<TH2F*>(rFile.Get(x0Name.c_str()));
0408 auto l0 = dynamic_cast<TH2F*>(rFile.Get(l0Name.c_str()));
0409 auto A = dynamic_cast<TH2F*>(rFile.Get(aName.c_str()));
0410 auto Z = dynamic_cast<TH2F*>(rFile.Get(zName.c_str()));
0411 auto rho = dynamic_cast<TH2F*>(rFile.Get(rhoName.c_str()));
0412
0413 hists = {t, x0, l0, A, Z, rho};
0414
0415
0416 if (std::ranges::all_of(hists,
0417 [](const auto* hist) { return hist != nullptr; })) {
0418
0419 int nbins0 = t->GetNbinsX();
0420 int nbins1 = t->GetNbinsY();
0421
0422 MaterialSlabMatrix materialMatrix(
0423 nbins1, MaterialSlabVector(nbins0, MaterialSlab::Nothing()));
0424
0425 for (int ib0 = 1; ib0 <= nbins0; ++ib0) {
0426 for (int ib1 = 1; ib1 <= nbins1; ++ib1) {
0427 auto dt = static_cast<float>(t->GetBinContent(ib0, ib1));
0428 if (dt > 0.) {
0429 auto dx0 = static_cast<float>(x0->GetBinContent(ib0, ib1));
0430 auto dl0 = static_cast<float>(l0->GetBinContent(ib0, ib1));
0431 auto da = static_cast<float>(A->GetBinContent(ib0, ib1));
0432 auto dz = static_cast<float>(Z->GetBinContent(ib0, ib1));
0433 auto drho = static_cast<float>(rho->GetBinContent(ib0, ib1));
0434
0435 const auto material =
0436 Material::fromMassDensity(dx0, dl0, da, dz, drho);
0437 materialMatrix[ib1 - 1][ib0 - 1] = MaterialSlab(material, dt);
0438 }
0439 }
0440 }
0441 texturedSurfaceMaterial = std::make_shared<const BinnedSurfaceMaterial>(
0442 bUtility, std::move(materialMatrix));
0443 }
0444 } else {
0445
0446 std::string indexName = tdName + "/" + m_cfg.indexHistName;
0447
0448 auto ih = dynamic_cast<TH2I*>(rFile.Get(indexName.c_str()));
0449 if (ih != nullptr) {
0450
0451 int nbins0 = ih->GetNbinsX();
0452 int nbins1 = ih->GetNbinsY();
0453
0454 MaterialSlabMatrix materialMatrix(
0455 nbins1, MaterialSlabVector(nbins0, MaterialSlab::Nothing()));
0456
0457 for (int ib0 = 1; ib0 <= nbins0; ++ib0) {
0458 for (int ib1 = 1; ib1 <= nbins1; ++ib1) {
0459 auto idx = static_cast<int>(ih->GetBinContent(ib0, ib1));
0460 indexedMaterialTree->GetEntry(idx);
0461 const auto material = Material::fromMassDensity(
0462 m_indexedMaterialTreePayload.hX0,
0463 m_indexedMaterialTreePayload.hL0, m_indexedMaterialTreePayload.hA,
0464 m_indexedMaterialTreePayload.hZ,
0465 m_indexedMaterialTreePayload.hRho);
0466 materialMatrix[ib1 - 1][ib0 - 1] =
0467 MaterialSlab(material, m_indexedMaterialTreePayload.ht);
0468 }
0469 }
0470 texturedSurfaceMaterial = std::make_shared<const BinnedSurfaceMaterial>(
0471 bUtility, std::move(materialMatrix));
0472 }
0473 }
0474
0475 return texturedSurfaceMaterial;
0476 }