Project
Loading...
Searching...
No Matches
CADGeometryUtils.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.
13
17#include <TGeoVolume.h>
18#include <TGeoNode.h>
19#include <TGeoMaterial.h>
20#include <TGeoMedium.h>
21#include <TInterpreter.h>
22#include <TROOT.h>
23#include <TString.h>
24#include <TGlobal.h>
25#include <fairlogger/Logger.h>
26#include <atomic>
27#include <cctype>
28#include <filesystem>
29#include <fstream>
30#include <functional>
31#include <string>
32#include <unordered_map>
33#include <unordered_set>
34#include <vector>
35
36namespace o2::cad
37{
38
39TGeoVolume* buildCADVolumeFromMacro(const std::string& macroFile, const std::string& instanceTag)
40{
41 if (macroFile.empty()) {
42 return nullptr;
43 }
44 auto expandedHookFileName = o2::utils::expandShellVarsInFileName(macroFile);
45 if (!std::filesystem::exists(expandedHookFileName)) {
46 LOG(error) << "External geometry macro " << expandedHookFileName << " does not exist";
47 return nullptr;
48 }
49
50 // JIT each macro into its own namespace, since every converter macro defines the same symbols; includes stay global.
51 std::ifstream macroStream(expandedHookFileName, std::ios::in);
52 if (!macroStream.is_open()) {
53 LOG(error) << "Cannot open external geometry macro " << expandedHookFileName;
54 return nullptr;
55 }
56 std::string preamble; // #include (and other top-level preprocessor) lines -> global scope
57 std::string body; // everything else -> wrapped into a unique namespace
58 std::string line;
59 while (std::getline(macroStream, line)) {
60 auto firstNonSpace = line.find_first_not_of(" \t");
61 if (firstNonSpace != std::string::npos && line[firstNonSpace] == '#') {
62 preamble += line + "\n";
63 } else {
64 body += line + "\n";
65 }
66 }
67
68 // build a unique, valid C++ identifier for the namespace
69 static std::atomic<int> instanceCounter{0};
70 std::string ns = std::string("o2_cadgeom_") + instanceTag + "_" + std::to_string(instanceCounter++);
71 for (auto& c : ns) {
72 if (!std::isalnum(static_cast<unsigned char>(c)) && c != '_') {
73 c = '_';
74 }
75 }
76
77 const std::string wrapped = preamble + "\nnamespace " + ns + " {\n" + body + "\n}\n";
78 if (!gInterpreter->Declare(wrapped.c_str())) {
79 LOG(error) << "Failed to JIT external geometry macro " << expandedHookFileName;
80 return nullptr;
81 }
82
83 // retrieve the builder hook from the unique namespace
84 const std::string globalName = "__" + ns + "_hook__";
85 gROOT->ProcessLine(Form("std::function<TGeoVolume*()> %s = %s::get_builder_hook_unchecked();",
86 globalName.c_str(), ns.c_str()));
87 auto global = gROOT->GetGlobal(globalName.c_str());
88 if (!global) {
89 LOG(error) << "Could not retrieve geometry builder hook from macro " << expandedHookFileName;
90 return nullptr;
91 }
92 auto hook = *reinterpret_cast<std::function<TGeoVolume*()>*>(global->GetAddress());
93 LOG(info) << "CAD geometry hook initialized from file " << expandedHookFileName << " (namespace " << ns << ")";
94
95 auto top = hook();
96 if (!top) {
97 LOG(error) << "CAD geometry macro " << expandedHookFileName << " did not return a top volume";
98 }
99 return top;
100}
101
102void remapCADMedia(TGeoVolume* top, const char* modulename)
103{
104 std::unordered_map<TGeoMedium*, TGeoMedium*> medium_ptr_mapping;
105 std::unordered_set<TGeoVolume*> volumes_already_treated;
106 // a material may back several media (the `_NF` twins), so materials are deduplicated apart from media
107 std::unordered_map<std::string, int> material_index;
108 int counter = 1;
109 int matcounter = 1;
110
111 // The transformer function
112 auto transform_media = [&](TGeoVolume* vol_) {
113 if (volumes_already_treated.find(vol_) != volumes_already_treated.end()) {
114 // this volume was already transformed
115 return;
116 }
117 volumes_already_treated.insert(vol_);
118
119 if (dynamic_cast<TGeoVolumeAssembly*>(vol_)) {
120 // do nothing for assemblies (they don't have a medium)
121 return;
122 }
123
124 auto medium = vol_->GetMedium();
125 if (!medium) {
126 return;
127 }
128
129 auto iter = medium_ptr_mapping.find(medium);
130 if (iter != medium_ptr_mapping.end()) {
131 // This medium has already been transformed, so
132 // we just update the volume
133 vol_->SetMedium(iter->second);
134 return;
135 } else {
136 LOG(info) << "Transforming media with name " << medium->GetName() << " for volume " << vol_->GetName();
137
138 // we found a medium, not yet treated
139 auto curr_mat = medium->GetMaterial();
141
142 // Register the material once, however many media wear it.
143 const std::string matname(curr_mat->GetName());
144 auto itmat = material_index.find(matname);
145 int imat;
146 if (itmat != material_index.end()) {
147 imat = itmat->second;
148 } else {
149 imat = matcounter++;
150 // A TGeoMixture goes through Mixture() so Geant keeps its element composition.
151 if (auto* mix = dynamic_cast<TGeoMixture*>(curr_mat)) {
152 const Int_t nel = mix->GetNelements();
153 std::vector<Float_t> a(nel), z(nel), w(nel);
154 for (Int_t i = 0; i < nel; ++i) {
155 a[i] = mix->GetAmixt()[i];
156 z[i] = mix->GetZmixt()[i];
157 w[i] = mix->GetWmixt()[i];
158 }
159 matmgr.Mixture(modulename, imat, curr_mat->GetName(), a.data(), z.data(),
160 curr_mat->GetDensity(), nel, w.data());
161 } else {
162 matmgr.Material(modulename, imat, curr_mat->GetName(), curr_mat->GetA(), curr_mat->GetZ(), curr_mat->GetDensity(), curr_mat->GetRadLen(), curr_mat->GetIntLen());
163 }
164 material_index[matname] = imat;
165 }
166 // TGeo medium params are stored in a flat array with the following convention
167 // fParams[0] = isvol;
168 // fParams[1] = ifield;
169 // fParams[2] = fieldm;
170 // fParams[3] = tmaxfd;
171 // fParams[4] = stemax;
172 // fParams[5] = deemax;
173 // fParams[6] = epsil;
174 // fParams[7] = stmin;
175 const auto isvol = medium->GetParam(0);
176 const auto isxfld = medium->GetParam(1);
177 const auto sxmgmx = medium->GetParam(2);
178 const auto tmaxfd = medium->GetParam(3);
179 const auto stemax = medium->GetParam(4);
180 const auto deemax = medium->GetParam(5);
181 const auto epsil = medium->GetParam(6);
182 const auto stmin = medium->GetParam(7);
183
184 matmgr.Medium(modulename, counter, medium->GetName(), imat, isvol, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin);
185
186 // there will be new Material and Medium objects; fetch them
187 auto new_med = matmgr.getTGeoMedium(modulename, counter);
188
189 // insert into cache
190 medium_ptr_mapping[medium] = new_med;
191 vol_->SetMedium(new_med);
192 counter++;
193 }
194 }; // end transformer lambda
195
196 // a generic volume walker
197 std::function<void(TGeoVolume*)> visit_volume;
198 visit_volume = [&](TGeoVolume* vol) -> void {
199 if (!vol) {
200 return;
201 }
202
203 // call the transformer
204 transform_media(vol);
205
206 // Recurse into daughters
207 const int nd = vol->GetNdaughters();
208 for (int i = 0; i < nd; ++i) {
209 TGeoNode* node = vol->GetNode(i);
210 if (!node) {
211 continue;
212 }
213 TGeoVolume* child = node->GetVolume();
214 if (!child) {
215 continue;
216 }
217
218 visit_volume(child);
219 }
220 };
221
222 visit_volume(top);
223}
224
225} // namespace o2::cad
Helpers to inject CAD-derived (TGeo) geometry into O2 simulation.
std::unique_ptr< expressions::Node > node
int32_t i
uint32_t c
Definition RawData.h:2
static MaterialManager & Instance()
GLdouble GLdouble GLdouble GLdouble top
Definition glcorearb.h:4077
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
GLuint counter
Definition glcorearb.h:3987
TGeoVolume * buildCADVolumeFromMacro(const std::string &macroFile, const std::string &instanceTag)
void remapCADMedia(TGeoVolume *top, const char *modulename)
std::string expandShellVarsInFileName(std::string const &input)
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"