LDMX Software
TrackingGeometry.cxx
1
2#include "Tracking/geo/TrackingGeometry.h"
3
4#include "Framework/Exception/Exception.h"
5
6namespace tracking::geo {
7
13class SilentG4 : public G4UIsession {
14 public:
15 SilentG4() = default;
16 ~SilentG4() = default;
17 G4UIsession* SessionStart() { return nullptr; }
18 G4int ReceiveG4cout(const G4String&) { return 0; }
19 G4int ReceiveG4cerr(const G4String&) { return 0; }
20};
21
22TrackingGeometry::TrackingGeometry(const std::string& name,
23 const Acts::GeometryContext& gctx,
24 const std::string& gdml)
25 : framework::ConditionsObject(name), gctx_{gctx}, gdml_{gdml} {
26 // Build The rotation matrix to the tracking frame
27 // Rotate the sensors to be orthogonal to X
28 double rotation_angle = M_PI * 0.5;
29
30 // 0 0 -1
31 // 0 1 0
32 // 1 0 0
33
34 // This rotation is needed to have the plane orthogonal to the X direction.
35 // Rotation of the surfaces
36 Acts::Vector3 x_pos1(cos(rotation_angle), 0., sin(rotation_angle));
37 Acts::Vector3 y_pos1(0., 1., 0.);
38 Acts::Vector3 z_pos1(-sin(rotation_angle), 0., cos(rotation_angle));
39
40 y_rot_.col(0) = x_pos1;
41 y_rot_.col(1) = y_pos1;
42 y_rot_.col(2) = z_pos1;
43
44 // Rotate the sensors to put them in the proper orientation in Z
45 Acts::Vector3 x_pos2(1., 0., 0.);
46 Acts::Vector3 y_pos2(0., cos(rotation_angle), sin(rotation_angle));
47 Acts::Vector3 z_pos2(0., -sin(rotation_angle), cos(rotation_angle));
48
49 x_rot_.col(0) = x_pos2;
50 x_rot_.col(1) = y_pos2;
51 x_rot_.col(2) = z_pos2;
52
64 std::unique_ptr<SilentG4> silence;
65 if (G4RunManager::GetRunManager() == nullptr) {
66 // no run manager ==> no simulation
67 silence = std::make_unique<SilentG4>();
68 // these lines compied from G4UImanager::SetCoutDestination
69 // to avoid creating G4UImanager unnecessarily
70 G4coutbuf.SetDestination(silence.get());
71 G4cerrbuf.SetDestination(silence.get());
72 }
73
74 // Get the world volume
75 G4GDMLParser parser;
76
77 // Validation requires internet
78 parser.Read(gdml_, false);
79
80 // Extract field map filename from GDML auxiliary data and resolve full path.
81 // GDML path: .../data/detectors/<det>/detector.gdml
82 // Field map: .../data/fieldmap/<filename>
83 const G4GDMLAuxListType* aux_list = parser.GetAuxList();
84 for (const auto& aux : *aux_list) {
85 if (aux.type == "MagneticField") {
86 for (const auto& sub : *aux.auxList) {
87 if (sub.type == "File") {
88 boost::filesystem::path fmap(std::string(sub.value));
89 if (fmap.is_absolute()) {
90 field_map_file_ = fmap.string();
91 } else {
92 boost::filesystem::path prefix = boost::filesystem::path(gdml_)
93 .parent_path()
94 .parent_path()
95 .parent_path();
96 field_map_file_ = (prefix / "fieldmap" / fmap).string();
97 }
98 break;
99 }
100 }
101 break;
102 }
103 }
104
105 if (field_map_file_.empty()) {
106 ldmx_log(warn) << "TrackingGeometry: no MagneticField/File auxiliary "
107 "entry found in '"
108 << gdml_ << "' — tracking will use a zero B-field";
109 }
110
111 f_world_phys_vol_ = parser.GetWorldVolume();
112
113 if (silence) {
114 // we created the session and silenced G4
115 // undo that now incase others have use for G4
116 // nullptr => standard (ldmx_log(trace) and std::cerr)
117 G4coutbuf.SetDestination(nullptr);
118 G4cerrbuf.SetDestination(nullptr);
119 }
120}
121
122G4VPhysicalVolume* TrackingGeometry::findDaughterByName(G4VPhysicalVolume* pvol,
123 G4String name) {
124 G4LogicalVolume* lvol = pvol->GetLogicalVolume();
125 for (G4int i = 0; i < lvol->GetNoDaughters(); i++) {
126 G4VPhysicalVolume* f_daughter_phys_vol = lvol->GetDaughter(i);
127 std::string d_name = f_daughter_phys_vol->GetName();
128 if (d_name.find(name) != std::string::npos) return f_daughter_phys_vol;
129 // if (fDaughterPhysVol->GetName() == name) return fDaughterPhysVol;
130 }
131
132 return nullptr;
133}
134
135void TrackingGeometry::getAllDaughters(G4VPhysicalVolume* pvol) {
136 G4LogicalVolume* lvol = pvol->GetLogicalVolume();
137
138 ldmx_log(trace) << "Checking daughters of ::" << pvol->GetName();
139
140 for (G4int i = 0; i < lvol->GetNoDaughters(); i++) {
141 G4VPhysicalVolume* f_daughter_phys_vol = lvol->GetDaughter(i);
142
143 ldmx_log(trace) << "name::" << f_daughter_phys_vol->GetName();
144 ldmx_log(trace) << "pos_::" << f_daughter_phys_vol->GetTranslation();
145 ldmx_log(trace)
146 << "n_dau::"
147 << f_daughter_phys_vol->GetLogicalVolume()->GetNoDaughters();
148 ldmx_log(trace) << "replica::" << f_daughter_phys_vol->IsReplicated();
149 ldmx_log(trace) << "copyNR::" << f_daughter_phys_vol->GetCopyNo();
150
151 getAllDaughters(f_daughter_phys_vol);
152 }
153}
154
155// Retrieve the layers from a physical volume
156// void TrackingGeometry::getComponentLayer(G4VPhysicalVolume* pvol,
157// std::string layer_name,
158// std::string component_type,
159// std::vector<std::reference_wrapper<G4PhysicalVolume>>
160// & components) {
161
162// G4LogicalVolume* l_vol = pvol->GetLogicalVolume();
163// for (G4int i=0; i<l_vol->GetNoDaughters(); i++) {
164
165// }
166
167//}
168
169void TrackingGeometry::dumpGeometry(const std::string& outputDir,
170 const Acts::GeometryContext& gctx) const {
171 if (!t_geometry_) return;
172
173 {
174 ldmx_log(trace) << __PRETTY_FUNCTION__;
175
176 for (auto const& surface_id : layer_surface_map_) {
177 ldmx_log(trace) << " " << surface_id.first;
178 ldmx_log(trace) << " Check the surface";
179 // surfaceId.second->toStream(gctx, ldmx_log(trace));
180 surface_id.second->toStream(gctx);
181 ldmx_log(trace) << " GeometryID: " << surface_id.second->geometryId();
182 ldmx_log(trace) << " GeometryID value: "
183 << surface_id.second->geometryId().value();
184 }
185 }
186
187 // Should fail if already exists
188 boost::filesystem::create_directory(outputDir);
189
190 double output_scalor = 1.0;
191 size_t output_precision = 6;
192
193 Acts::ObjVisualization3D obj_vis(output_precision, output_scalor);
194 Acts::ViewConfig container_view = Acts::ViewConfig({220, 220, 220});
195 Acts::ViewConfig volume_view = Acts::ViewConfig({220, 220, 0});
196 Acts::ViewConfig sensitive_view = Acts::ViewConfig({0, 180, 240});
197 Acts::ViewConfig passive_view = Acts::ViewConfig({240, 280, 0});
198 Acts::ViewConfig grid_view = Acts::ViewConfig({220, 0, 0});
199
200 Acts::GeometryView3D::drawTrackingVolume(
201 obj_vis, *(t_geometry_->highestTrackingVolume()), gctx, container_view,
202 volume_view, passive_view, sensitive_view, grid_view, true, "", ".");
203}
204
205// This method gets the transform from the physical volume to the tracking frame
206Acts::Transform3 TrackingGeometry::getTransform(const G4VPhysicalVolume& phex,
207 bool toTrackingFrame) const {
208 Acts::Vector3 pos(phex.GetTranslation().x(), phex.GetTranslation().y(),
209 phex.GetTranslation().z());
210
211 Acts::RotationMatrix3 rotation;
212 convertG4Rot(phex.GetRotation(), rotation);
213
214 // rotate to the tracking frame
215 if (toTrackingFrame) {
216 pos(0) = phex.GetTranslation().z();
217 pos(1) = phex.GetTranslation().x();
218 pos(2) = phex.GetTranslation().y();
219 rotation = x_rot_ * y_rot_ * rotation;
220 }
221
222 Acts::Translation3 translation(pos);
223
224 Acts::Transform3 transform(translation * rotation);
225
226 return transform;
227}
228
229// This method returns the transformation to the tracker coordinates z_->x_
230// x_->y_ y_->z_
231Acts::Transform3 TrackingGeometry::toTracker(
232 const Acts::Transform3& trans) const {
233 Acts::Vector3 pos{trans.translation()(2), trans.translation()(0),
234 trans.translation()(1)};
235
236 Acts::RotationMatrix3 rotation = trans.rotation();
237 rotation = x_rot_ * y_rot_ * rotation;
238
239 Acts::Translation3 translation(pos);
240 Acts::Transform3 transform(translation * rotation);
241
242 return transform;
243}
244
245// Convert rotation
246void TrackingGeometry::convertG4Rot(const G4RotationMatrix* g4rot,
247 Acts::RotationMatrix3& rot) const {
248 // If the rotation is the identity then g4rot will be a null ptr.
249 // So then check it and fill rot accordingly
250
251 rot = Acts::RotationMatrix3::Identity();
252
253 if (g4rot) {
254 rot(0, 0) = g4rot->xx();
255 rot(0, 1) = g4rot->xy();
256 rot(0, 2) = g4rot->xz();
257
258 rot(1, 0) = g4rot->yx();
259 rot(1, 1) = g4rot->yy();
260 rot(1, 2) = g4rot->yz();
261
262 rot(2, 0) = g4rot->zx();
263 rot(2, 1) = g4rot->zy();
264 rot(2, 2) = g4rot->zz();
265 }
266}
267
268// Convert translation
269
270Acts::Vector3 TrackingGeometry::convertG4Pos(const G4ThreeVector& g4pos) const {
271 Acts::Vector3 trans{g4pos.x(), g4pos.y(), g4pos.z()};
272
273 {
274 ldmx_log(trace) << "g4pos::" << g4pos;
275 ldmx_log(trace) << "trans" << trans;
276 }
277
278 return trans;
279}
280
281void TrackingGeometry::getSurfaces(
282 std::vector<const Acts::Surface*>& surfaces) const {
283 if (!t_geometry_)
284 EXCEPTION_RAISE("BadGeometry",
285 "TrackingGeometry::getSurfaces tGeometry is null");
286
287 const Acts::TrackingVolume* t_volume = t_geometry_->highestTrackingVolume();
288 if (t_volume->confinedVolumes()) {
289 for (auto volume : t_volume->confinedVolumes()->arrayObjects()) {
290 if (volume->confinedLayers()) {
291 for (const auto& layer : volume->confinedLayers()->arrayObjects()) {
292 if (layer->layerType() == Acts::navigation) continue;
293 for (auto surface : layer->surfaceArray()->surfaces()) {
294 if (surface) {
295 surfaces.push_back(surface);
296
297 } // surface exists
298 } // surfaces
299 } // layers objects
300 } // confined layers
301 } // volumes objects
302 } // confined volumes
303}
304
305void TrackingGeometry::makeLayerSurfacesMap() {
306 std::vector<const Acts::Surface*> surfaces;
307 getSurfaces(surfaces);
308
309 for (auto& surface : surfaces) {
310 // Layers from 1 to 14 - for the tagger
311 // unsigned int layerId = (surface->geometryId().layer() / 2) ; // Old 1
312 // sensor per layer_
313
314 unsigned int volume_id = surface->geometryId().volume();
315 unsigned int layer_id = (surface->geometryId().layer() /
316 2); // set layer_ ID from 1 to 7 for the tagger
317 // and from 1 to 6 for the recoil
318 unsigned int sensor_id =
319 surface->geometryId().sensitive() -
320 1; // set sensor ID from 0 to 1 for the tagger and from 0 to 9 for the
321 // axial sensors in the back layers of the recoil
322
323 ldmx_log(trace) << "VolumeID " << volume_id << " LayerId " << layer_id
324 << " sensorId " << sensor_id;
325
326 // surface ID = vol * 1000 + ly * 100 + sensor
327 unsigned int surface_id = volume_id * 1000 + layer_id * 100 + sensor_id;
328
329 layer_surface_map_[surface_id] = surface;
330
331 } // surfaces loop
332}
333
334} // namespace tracking::geo
This class throws away all of the messages from Geant4.
TrackingGeometry(const std::string &name, const Acts::GeometryContext &gctx, const std::string &gdml)
All classes in the ldmx-sw project use this namespace.
Visualization.