File indexing completed on 2025-07-12 07:52:56
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Plugins/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 void Acts::RootMaterialMapIo::write(TFile& rFile,
0032 const GeometryIdentifier& geoID,
0033 const ISurfaceMaterial& surfaceMaterial,
0034 const Options& options) {
0035
0036 rFile.cd();
0037
0038
0039 auto homogeneousMaterial =
0040 dynamic_cast<const HomogeneousSurfaceMaterial*>(&surfaceMaterial);
0041 if (homogeneousMaterial != nullptr) {
0042 if (m_hTree == nullptr) {
0043 m_hTree = new TTree(options.homogeneousMaterialTreeName.c_str(),
0044 "Homogeneous Material Tree");
0045 connectForWrite(*m_hTree, m_homogenousMaterialTreePayload);
0046 }
0047 fillMaterialSlab(m_homogenousMaterialTreePayload,
0048 homogeneousMaterial->materialSlab());
0049 m_homogenousMaterialTreePayload.hGeoId = geoID.value();
0050 m_hTree->Fill();
0051 return;
0052 }
0053
0054
0055 auto bsMaterial =
0056 dynamic_cast<const BinnedSurfaceMaterial*>(&surfaceMaterial);
0057 if (bsMaterial != nullptr) {
0058
0059 const auto gvolID = geoID.volume();
0060 const auto gbouID = geoID.boundary();
0061 const auto glayID = geoID.layer();
0062 const auto gappID = geoID.approach();
0063 const auto gsenID = geoID.sensitive();
0064
0065 std::string tdName = options.folderSurfaceNameBase.c_str();
0066 tdName += m_cfg.volumePrefix + std::to_string(gvolID);
0067 tdName += m_cfg.portalPrefix + std::to_string(gbouID);
0068 tdName += m_cfg.layerPrefix + std::to_string(glayID);
0069 tdName += m_cfg.passivePrefix + std::to_string(gappID);
0070 tdName += m_cfg.sensitivePrefix + std::to_string(gsenID);
0071
0072 rFile.mkdir(tdName.c_str());
0073 rFile.cd(tdName.c_str());
0074
0075
0076
0077 auto& binningData = bsMaterial->binUtility().binningData();
0078
0079 auto bins = static_cast<int>(binningData.size());
0080 auto fBins = static_cast<float>(bins);
0081
0082
0083 TH1F n(m_cfg.nBinsHistName.c_str(), "bins; bin", bins, -0.5, fBins - 0.5);
0084
0085
0086 TH1F v(m_cfg.axisDirHistName.c_str(), "binning values; bin", bins, -0.5,
0087 fBins - 0.5);
0088
0089
0090 TH1F o(m_cfg.axisBoundaryTypeHistName.c_str(), "binning options; bin", bins,
0091 -0.5, fBins - 0.5);
0092
0093
0094 TH1F rmin(m_cfg.minRangeHistName.c_str(), "min; bin", bins, -0.5,
0095 fBins - 0.5);
0096
0097
0098 TH1F rmax(m_cfg.maxRangeHistName.c_str(), "max; bin", bins, -0.5,
0099 fBins - 0.5);
0100
0101
0102 for (auto [b, bData] : enumerate(binningData)) {
0103
0104 n.SetBinContent(static_cast<int>(b) + 1, static_cast<int>(bData.bins()));
0105 v.SetBinContent(static_cast<int>(b) + 1,
0106 static_cast<int>(bData.binvalue));
0107 o.SetBinContent(static_cast<int>(b) + 1, static_cast<int>(bData.option));
0108 rmin.SetBinContent(static_cast<int>(b) + 1, bData.min);
0109 rmax.SetBinContent(static_cast<int>(b) + 1, bData.max);
0110 }
0111 n.Write();
0112 v.Write();
0113 o.Write();
0114 rmin.Write();
0115 rmax.Write();
0116
0117
0118
0119 if (!options.indexedMaterial) {
0120 fillBinnedSurfaceMaterial(*bsMaterial);
0121 return;
0122 }
0123
0124
0125 if (m_gTree == nullptr) {
0126
0127 rFile.cd();
0128 m_gTree = new TTree(options.indexedMaterialTreeName.c_str(),
0129 "Indexed Material Tree");
0130 connectForWrite(*m_gTree, m_indexedMaterialTreePayload);
0131
0132 rFile.cd(tdName.c_str());
0133 }
0134 fillBinnedSurfaceMaterial(m_indexedMaterialTreePayload, *bsMaterial);
0135 return;
0136 }
0137 }
0138
0139 void Acts::RootMaterialMapIo::write(
0140 TFile& rFile, const TrackingGeometryMaterial& detectorMaterial,
0141 const Options& options) {
0142 const auto& [surfaceMaterials, volumeMaterials] = detectorMaterial;
0143 for (const auto& [geoID, sMaterial] : surfaceMaterials) {
0144 write(rFile, geoID, *sMaterial, options);
0145 }
0146 if (m_hTree != nullptr) {
0147 m_hTree->Write();
0148 }
0149 if (m_gTree != nullptr) {
0150 m_gTree->Write();
0151 }
0152 }
0153
0154 void Acts::RootMaterialMapIo::connectForWrite(
0155 TTree& rTree, MaterialTreePayload& treePayload) {
0156 if (&treePayload == &m_homogenousMaterialTreePayload) {
0157 rTree.Branch("hGeoId", &treePayload.hGeoId);
0158 }
0159 rTree.Branch(m_cfg.thicknessHistName.c_str(), &treePayload.ht);
0160 rTree.Branch(m_cfg.x0HistName.c_str(), &treePayload.hX0);
0161 rTree.Branch(m_cfg.l0HistName.c_str(), &treePayload.hL0);
0162 rTree.Branch(m_cfg.aHistName.c_str(), &treePayload.hA);
0163 rTree.Branch(m_cfg.zHistName.c_str(), &treePayload.hZ);
0164 rTree.Branch(m_cfg.rhoHistName.c_str(), &treePayload.hRho);
0165 }
0166
0167 void Acts::RootMaterialMapIo::connectForRead(TTree& rTree,
0168 MaterialTreePayload& treePayload) {
0169 if (&treePayload == &m_homogenousMaterialTreePayload) {
0170 rTree.SetBranchAddress("hGeoId", &treePayload.hGeoId);
0171 }
0172 rTree.SetBranchAddress(m_cfg.thicknessHistName.c_str(), &treePayload.ht);
0173 rTree.SetBranchAddress(m_cfg.x0HistName.c_str(), &treePayload.hX0);
0174 rTree.SetBranchAddress(m_cfg.l0HistName.c_str(), &treePayload.hL0);
0175 rTree.SetBranchAddress(m_cfg.aHistName.c_str(), &treePayload.hA);
0176 rTree.SetBranchAddress(m_cfg.zHistName.c_str(), &treePayload.hZ);
0177 rTree.SetBranchAddress(m_cfg.rhoHistName.c_str(), &treePayload.hRho);
0178 }
0179
0180 void Acts::RootMaterialMapIo::fillMaterialSlab(
0181 MaterialTreePayload& payload, const MaterialSlab& materialSlab) {
0182 payload.ht = materialSlab.thickness();
0183 payload.hX0 = materialSlab.material().X0();
0184 payload.hL0 = materialSlab.material().L0();
0185 payload.hA = materialSlab.material().Ar();
0186 payload.hZ = materialSlab.material().Z();
0187 payload.hRho = materialSlab.material().massDensity();
0188 }
0189
0190 void Acts::RootMaterialMapIo::fillBinnedSurfaceMaterial(
0191 const BinnedSurfaceMaterial& bsMaterial) {
0192 auto bins0 = static_cast<int>(bsMaterial.binUtility().bins(0));
0193 auto bins1 = static_cast<int>(bsMaterial.binUtility().bins(1));
0194 auto fBins0 = static_cast<float>(bins0);
0195 auto fBins1 = static_cast<float>(bins1);
0196
0197 TH2F t(m_cfg.thicknessHistName.c_str(), "thickness [mm] ;b0 ;b1", bins0, -0.5,
0198 fBins0 - 0.5, bins1, -0.5, fBins1 - 0.5);
0199 TH2F x0(m_cfg.x0HistName.c_str(), "X_{0} [mm] ;b0 ;b1", bins0, -0.5,
0200 fBins0 - 0.5, bins1, -0.5, fBins1 - 0.5);
0201 TH2F l0(m_cfg.l0HistName.c_str(), "#Lambda_{0} [mm] ;b0 ;b1", bins0, -0.5,
0202 fBins0 - 0.5, bins1, -0.5, fBins1 - 0.5);
0203 TH2F A(m_cfg.aHistName.c_str(), "X_{0} [mm] ;b0 ;b1", bins0, -0.5,
0204 fBins0 - 0.5, bins1, -0.5, fBins1 - 0.5);
0205 TH2F Z(m_cfg.zHistName.c_str(), "#Lambda_{0} [mm] ;b0 ;b1", bins0, -0.5,
0206 fBins0 - 0.5, bins1, -0.5, fBins1 - 0.5);
0207 TH2F rho(m_cfg.rhoHistName.c_str(), "#rho [g/mm^3] ;b0 ;b1", bins0, -0.5,
0208 fBins0 - 0.5, bins1, -0.5, fBins1 - 0.5);
0209
0210
0211 const auto& materialMatrix = bsMaterial.fullMaterial();
0212 for (auto [b1, materialVector] : enumerate(materialMatrix)) {
0213 for (auto [b0, mat] : enumerate(materialVector)) {
0214 t.SetBinContent(static_cast<int>(b0) + 1, static_cast<int>(b1) + 1,
0215 mat.thickness());
0216 x0.SetBinContent(static_cast<int>(b0) + 1, static_cast<int>(b1) + 1,
0217 mat.material().X0());
0218 l0.SetBinContent(static_cast<int>(b0) + 1, static_cast<int>(b1) + 1,
0219 mat.material().L0());
0220 A.SetBinContent(static_cast<int>(b0) + 1, static_cast<int>(b1) + 1,
0221 mat.material().Ar());
0222 Z.SetBinContent(static_cast<int>(b0) + 1, static_cast<int>(b1) + 1,
0223 mat.material().Z());
0224 rho.SetBinContent(static_cast<int>(b0) + 1, static_cast<int>(b1) + 1,
0225 mat.material().massDensity());
0226 }
0227 }
0228 t.Write();
0229 x0.Write();
0230 l0.Write();
0231 A.Write();
0232 Z.Write();
0233 rho.Write();
0234 }
0235
0236 void Acts::RootMaterialMapIo::fillBinnedSurfaceMaterial(
0237 MaterialTreePayload& payload, const BinnedSurfaceMaterial& bsMaterial) {
0238 std::size_t bins0 = bsMaterial.binUtility().bins(0);
0239 std::size_t bins1 = bsMaterial.binUtility().bins(1);
0240
0241 TH2I idx(m_cfg.indexHistName.c_str(), "indices; bin0; bin1",
0242 static_cast<int>(bins0), -0.5, static_cast<float>(bins0) - 0.5,
0243 static_cast<int>(bins1), -0.5, static_cast<float>(bins1) - 0.5);
0244
0245 const auto& materialMatrix = bsMaterial.fullMaterial();
0246 for (auto [b1, materialVector] : enumerate(materialMatrix)) {
0247 for (auto [b0, mat] : enumerate(materialVector)) {
0248 idx.SetBinContent(static_cast<int>(b0) + 1, static_cast<int>(b1) + 1,
0249 static_cast<float>(payload.index));
0250 payload.index++;
0251 fillMaterialSlab(payload, mat);
0252 m_gTree->Fill();
0253 }
0254 }
0255 idx.Write();
0256 }
0257
0258 Acts::TrackingGeometryMaterial Acts::RootMaterialMapIo::read(
0259 TFile& rFile, const Options& options) {
0260 TrackingGeometryMaterial detectorMaterial;
0261
0262 auto& [surfaceMaterials, volumeMaterials] = detectorMaterial;
0263
0264 auto homogeneousMaterialTree = dynamic_cast<TTree*>(
0265 rFile.Get(options.homogeneousMaterialTreeName.c_str()));
0266
0267
0268 if (homogeneousMaterialTree != nullptr) {
0269 connectForRead(*homogeneousMaterialTree, m_homogenousMaterialTreePayload);
0270 for (int i = 0; i < homogeneousMaterialTree->GetEntries(); ++i) {
0271 homogeneousMaterialTree->GetEntry(i);
0272 GeometryIdentifier geoID(m_homogenousMaterialTreePayload.hGeoId);
0273 MaterialSlab materialSlab(
0274 Material::fromMassDensity(m_homogenousMaterialTreePayload.hX0,
0275 m_homogenousMaterialTreePayload.hL0,
0276 m_homogenousMaterialTreePayload.hA,
0277 m_homogenousMaterialTreePayload.hZ,
0278 m_homogenousMaterialTreePayload.hRho),
0279 m_homogenousMaterialTreePayload.ht);
0280 auto homogeneousMaterial =
0281 std::make_shared<HomogeneousSurfaceMaterial>(materialSlab);
0282 surfaceMaterials.try_emplace(geoID, homogeneousMaterial);
0283 }
0284 }
0285
0286
0287 auto indexedMaterialTree =
0288 dynamic_cast<TTree*>(rFile.Get(options.indexedMaterialTreeName.c_str()));
0289 if (indexedMaterialTree != nullptr) {
0290 connectForRead(*indexedMaterialTree, m_indexedMaterialTreePayload);
0291 }
0292
0293
0294 TList* tlist = rFile.GetListOfKeys();
0295 auto tIter = tlist->MakeIterator();
0296 tIter->Reset();
0297
0298
0299 while (auto key = static_cast<TKey*>(tIter->Next())) {
0300
0301 std::string tdName(key->GetName());
0302
0303 ACTS_VERBOSE("Processing directory: " << tdName);
0304
0305
0306 std::vector<std::string> splitNames;
0307 iter_split(splitNames, tdName,
0308 boost::algorithm::first_finder(m_cfg.volumePrefix));
0309
0310 if (splitNames[0] == options.folderSurfaceNameBase) {
0311
0312 std::shared_ptr<const Acts::ISurfaceMaterial> sMaterial = nullptr;
0313
0314 boost::split(splitNames, splitNames[1], boost::is_any_of("_"));
0315 GeometryIdentifier::Value volID = std::stoi(splitNames[0]);
0316
0317 iter_split(splitNames, tdName,
0318 boost::algorithm::first_finder(m_cfg.portalPrefix));
0319 boost::split(splitNames, splitNames[1], boost::is_any_of("_"));
0320 GeometryIdentifier::Value bouID = std::stoi(splitNames[0]);
0321
0322 iter_split(splitNames, tdName,
0323 boost::algorithm::first_finder(m_cfg.layerPrefix));
0324 boost::split(splitNames, splitNames[1], boost::is_any_of("_"));
0325 GeometryIdentifier::Value layID = std::stoi(splitNames[0]);
0326
0327 iter_split(splitNames, tdName,
0328 boost::algorithm::first_finder(m_cfg.passivePrefix));
0329 boost::split(splitNames, splitNames[1], boost::is_any_of("_"));
0330 GeometryIdentifier::Value appID = std::stoi(splitNames[0]);
0331
0332 iter_split(splitNames, tdName,
0333 boost::algorithm::first_finder(m_cfg.sensitivePrefix));
0334 GeometryIdentifier::Value senID = std::stoi(splitNames[1]);
0335
0336
0337 auto geoID = GeometryIdentifier()
0338 .withVolume(volID)
0339 .withBoundary(bouID)
0340 .withLayer(layID)
0341 .withApproach(appID)
0342 .withSensitive(senID);
0343
0344 ACTS_VERBOSE("GeometryIdentifier re-constructed as " << geoID);
0345
0346 auto texturedSurfaceMaterial =
0347 readTextureSurfaceMaterial(rFile, tdName, indexedMaterialTree);
0348 surfaceMaterials.try_emplace(geoID, texturedSurfaceMaterial);
0349 }
0350 }
0351 return detectorMaterial;
0352 }
0353
0354 std::shared_ptr<const Acts::ISurfaceMaterial>
0355 Acts::RootMaterialMapIo::readTextureSurfaceMaterial(
0356 TFile& rFile, const std::string& tdName, TTree* indexedMaterialTree) {
0357 std::shared_ptr<const Acts::ISurfaceMaterial> texturedSurfaceMaterial =
0358 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 += Acts::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 }