Project
Loading...
Searching...
No Matches
ExternalModule.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12// Sandro Wenzel (CERN), 2026
13
16#include <filesystem>
18#include <TGeoManager.h>
19#include <TGeoVolume.h>
20#include <unordered_map>
21#include <unordered_set>
22#include <TGeoMaterial.h>
23#include <TGeoMedium.h>
25
26// ClassImp(o2::passive::ExternalModule)
27
28namespace o2::passive
29{
30
31ExternalModule::ExternalModule(const char* name, const char* long_title, ExternalModuleOptions options) : PassiveBase(name, long_title), mOptions(options)
32{
33}
34
35void ExternalModule::remapMedia(TGeoVolume* top_volume)
36{
37 std::unordered_map<TGeoMedium*, TGeoMedium*> medium_ptr_mapping;
38 std::unordered_set<TGeoVolume*> volumes_already_treated;
39 int counter = 1;
40
41 auto modulename = GetName();
42
43 // The transformer function
44 auto transform_media = [&](TGeoVolume* vol_) {
45 if (volumes_already_treated.find(vol_) != volumes_already_treated.end()) {
46 // this volume was already transformed
47 return;
48 }
49 volumes_already_treated.insert(vol_);
50
51 if (dynamic_cast<TGeoVolumeAssembly*>(vol_)) {
52 // do nothing for assemblies (they don't have a medium)
53 return;
54 }
55
56 auto medium = vol_->GetMedium();
57 if (!medium) {
58 return;
59 }
60
61 auto iter = medium_ptr_mapping.find(medium);
62 if (iter != medium_ptr_mapping.end()) {
63 // This medium has already been transformed, so
64 // we just update the volume
65 vol_->SetMedium(iter->second);
66 return;
67 } else {
68 std::cout << "Transforming media with name " << medium->GetName() << " for volume " << vol_->GetName() << "\n";
69
70 // we found a medium, not yet treated
71 auto curr_mat = medium->GetMaterial();
73
74 matmgr.Material(modulename, counter, curr_mat->GetName(), curr_mat->GetA(), curr_mat->GetZ(), curr_mat->GetDensity(), curr_mat->GetRadLen(), curr_mat->GetIntLen());
75 // TGeo medium params are stored in a flat array with the following convention
76 // fParams[0] = isvol;
77 // fParams[1] = ifield;
78 // fParams[2] = fieldm;
79 // fParams[3] = tmaxfd;
80 // fParams[4] = stemax;
81 // fParams[5] = deemax;
82 // fParams[6] = epsil;
83 // fParams[7] = stmin;
84 const auto isvol = medium->GetParam(0);
85 const auto isxfld = medium->GetParam(1);
86 const auto sxmgmx = medium->GetParam(2);
87 const auto tmaxfd = medium->GetParam(3);
88 const auto stemax = medium->GetParam(4);
89 const auto deemax = medium->GetParam(5);
90 const auto epsil = medium->GetParam(6);
91 const auto stmin = medium->GetParam(7);
92
93 matmgr.Medium(modulename, counter, medium->GetName(), counter, isvol, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin);
94
95 // there will be new Material and Medium objects; fetch them
96 auto new_med = matmgr.getTGeoMedium(modulename, counter);
97
98 // insert into cache
99 medium_ptr_mapping[medium] = new_med;
100 vol_->SetMedium(new_med);
101 counter++;
102 }
103 }; // end transformer lambda
104
105 // a generic volume walker
106 std::function<void(TGeoVolume*)> visit_volume;
107 visit_volume = [&](TGeoVolume* vol) -> void {
108 if (!vol) {
109 return;
110 }
111
112 // call the transformer
113 transform_media(vol);
114
115 // Recurse into daughters
116 const int nd = vol->GetNdaughters();
117 for (int i = 0; i < nd; ++i) {
118 TGeoNode* node = vol->GetNode(i);
119 if (!node) {
120 continue;
121 }
122 TGeoVolume* child = node->GetVolume();
123 if (!child) {
124 continue;
125 }
126
127 visit_volume(child);
128 }
129 };
130
131 visit_volume(top_volume);
132}
133
135{
136 // JIT the geom builder hook
137 if (!initGeomBuilderHook()) {
138 LOG(error) << " Could not load geometry builder hook";
139 return;
140 }
141
142 // otherwise execute it and obtain pointer to top most module volume
143 auto module_top = mGeomHook();
144 if (!module_top) {
145 LOG(error) << "No module found\n";
146 return;
147 }
148
149 remapMedia(const_cast<TGeoVolume*>(module_top));
150
151 // place it into the provided anchor volume (needs to exist)
152 auto anchor = gGeoManager->FindVolumeFast(mOptions.anchor_volume.c_str());
153 if (!anchor) {
154 LOG(error) << "Anchor volume " << mOptions.anchor_volume << " not found. Aborting";
155 return;
156 }
157 anchor->AddNode(const_cast<TGeoVolume*>(module_top), 1, const_cast<TGeoMatrix*>(mOptions.placement));
158}
159
160bool ExternalModule::initGeomBuilderHook()
161{
162 if (mOptions.root_macro_file.size() > 0) {
163 LOG(info) << "Initializing the hook for geometry module building";
164 auto expandedHookFileName = o2::utils::expandShellVarsInFileName(mOptions.root_macro_file);
165 if (std::filesystem::exists(expandedHookFileName)) {
166 // if this file exists we will compile the hook on the fly (the last one is an identifier --> maybe make it dependent on this class)
167 mGeomHook = o2::conf::GetFromMacro<GeomBuilderFcn>(mOptions.root_macro_file, "get_builder_hook_unchecked()", "function<TGeoVolume*()>", "o2_passive_extmodule_builder");
168 LOG(info) << "Hook initialized from file " << expandedHookFileName;
169 return true;
170 }
171 }
172 return false;
173}
174
175} // namespace o2::passive
std::unique_ptr< expressions::Node > node
int32_t i
static MaterialManager & Instance()
a common base class for passive modules - implementing generic functions
Definition PassiveBase.h:24
GLuint const GLchar * name
Definition glcorearb.h:781
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLuint counter
Definition glcorearb.h:3987
std::string expandShellVarsInFileName(std::string const &input)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"