LDMX Software
TrackersTrackingGeometry.cxx
1#include "Tracking/geo/TrackersTrackingGeometry.h"
2
3#include "Framework/Exception/Exception.h"
4
5namespace tracking::geo {
6
7const std::string TrackersTrackingGeometry::NAME = "TrackersTrackingGeometry";
8
9TrackersTrackingGeometry::TrackersTrackingGeometry(
10 const Acts::GeometryContext& gctx, const std::string& gdml,
11 double tracker_y_length, double tracker_z_length)
12 : TrackingGeometry(NAME, gctx, gdml) {
13 tagger_ = findDaughterByName(f_world_phys_vol_, "tagger_PV");
14 buildTaggerLayoutMap(tagger_, "tagger");
15 Acts::CuboidVolumeBuilder::VolumeConfig tagger_volume_cfg = buildVolumeConfig(
16 tagger_, tagger_layout_, tracker_y_length, tracker_z_length, "Tagger");
17
18 recoil_ = findDaughterByName(f_world_phys_vol_, "recoil_PV");
19 buildRecoilLayoutMap(recoil_, "recoil");
20 Acts::CuboidVolumeBuilder::VolumeConfig recoil_volume_cfg = buildVolumeConfig(
21 recoil_, recoil_layout_, tracker_y_length, tracker_z_length, "Recoil");
22
23 std::vector<Acts::CuboidVolumeBuilder::VolumeConfig> vol_builder_configs{
24 tagger_volume_cfg, recoil_volume_cfg};
25
26 // Create the builder
27 Acts::CuboidVolumeBuilder cvb;
28
29 Acts::CuboidVolumeBuilder::Config config;
30 config.position = {-200, 0., 0.};
31 // acts x = global z
32 // global z: -200 - 900/2 = -650 to -200 + 900/2 = 250 mm
33 // global y: -70 to 70
34 // global x: -240 to 240
35 config.length = {900, tracker_y_length, tracker_z_length};
36 config.volumeCfg = vol_builder_configs;
37
38 cvb.setConfig(config);
39
40 Acts::TrackingGeometryBuilder::Config tgb_cfg;
41 tgb_cfg.trackingVolumeBuilders.push_back(
42 [=](const auto& cxt, const auto& inner, const auto&) {
43 return cvb.trackingVolume(cxt, inner, nullptr);
44 });
45
46 Acts::TrackingGeometryBuilder tgb(tgb_cfg);
47 t_geometry_ = tgb.trackingGeometry(gctx_);
48
49 // dumpGeometry("./");
50 makeLayerSurfacesMap();
51}
52
53void TrackersTrackingGeometry::buildRecoilLayoutMap(G4VPhysicalVolume* pvol,
54 std::string surfacename) {
55 ldmx_log(trace) << "Building layout for the " << pvol->GetName()
56 << " tracker";
57 getAllDaughters(pvol);
58
59 // Get the global transform
60 Acts::Transform3 tracker_transform = getTransform(*pvol);
61
62 G4LogicalVolume* l_vol = pvol->GetLogicalVolume();
63 for (G4int i = 0; i < l_vol->GetNoDaughters(); i++) {
64 std::string sln = l_vol->GetDaughter(i)->GetName();
65 if (sln.find(surfacename) != std::string::npos) {
66 G4VPhysicalVolume* component0_volume{nullptr};
67 G4VPhysicalVolume* active_sensor{nullptr};
68 Acts::Transform3 ref1_transform = getTransform(*(l_vol->GetDaughter(i)));
69 int sensor_copy_nr = -999;
70
71 // recoil_l1(4)_axial(stereo)->LDMXRecoilL14ModuleVolume_component0_physvol
72 // This works for v12
73 if (sln.find("axial") != std::string::npos ||
74 sln.find("stereo") != std::string::npos) {
75 component0_volume =
76 findDaughterByName(l_vol->GetDaughter(i),
77 "LDMXRecoilL14ModuleVolume_component0_physvol");
78 if (!component0_volume)
79 EXCEPTION_RAISE("BadGeometry",
80 "Could not find component0 volume for L14 Recoil");
81 active_sensor = findDaughterByName(
82 component0_volume,
83 "LDMXRecoilL14ModuleVolume_component0Sensor0_physvol");
84
85 }
86
87 // recoil_l5_sensorX->LDMXRecoilL56ModuleVolume_component0_physvol
88 // This works for v12
89 else if (sln.find("l5_sensor") != std::string::npos ||
90 sln.find("l6_sensor") != std::string::npos) {
91 component0_volume =
92 findDaughterByName(l_vol->GetDaughter(i),
93 "LDMXRecoilL56ModuleVolume_component0_physvol");
94 if (!component0_volume)
95 EXCEPTION_RAISE("BadGeometry",
96 "Could not find component0 volume for L56 Recoil");
97 active_sensor = findDaughterByName(
98 component0_volume,
99 "LDMXRecoilL56ModuleVolume_component0Sensor0_physvol");
100 }
101
102 // recoil_PV tracker->recoil_l14_sensor_vol_PV->recoil_l14_active_sensor
103 // This works for v14
104 else if (sln.find("sensor_vol")) {
105 active_sensor =
106 findDaughterByName(l_vol->GetDaughter(i), "active_sensor");
107 sensor_copy_nr = l_vol->GetDaughter(i)->GetCopyNo();
108 }
109
110 else
111 EXCEPTION_RAISE("BadGeometry", "Could not build recoil layout");
112
113 if (!active_sensor)
114 EXCEPTION_RAISE("BadGeometry",
115 "Could not find ActiveSensor for recoil volume");
116
117 Acts::Transform3 ref2_transform = Acts::Transform3::Identity();
118
119 if (component0_volume)
120 ref2_transform = getTransform(*(component0_volume));
121
122 std::shared_ptr<Acts::PlaneSurface> sensor_surface = getSurfacePtr(
123 active_sensor, tracker_transform * ref1_transform * ref2_transform);
124
125 // Build the layout
126 if (sln == "recoil_l1_axial" || sln == "recoil_l1_stereo" ||
127 sensor_copy_nr == 10 || sensor_copy_nr == 20)
128 recoil_layout_["recoil_tracker_L1"].push_back(sensor_surface);
129
130 if (sln == "recoil_l2_axial" || sln == "recoil_l2_stereo" ||
131 sensor_copy_nr == 30 || sensor_copy_nr == 40)
132 recoil_layout_["recoil_tracker_L2"].push_back(sensor_surface);
133
134 if (sln == "recoil_l3_axial" || sln == "recoil_l3_stereo" ||
135 sensor_copy_nr == 50 || sensor_copy_nr == 60)
136 recoil_layout_["recoil_tracker_L3"].push_back(sensor_surface);
137
138 if (sln == "recoil_l4_axial" || sln == "recoil_l4_stereo" ||
139 sensor_copy_nr == 70 || sensor_copy_nr == 80)
140 recoil_layout_["recoil_tracker_L4"].push_back(sensor_surface);
141
142 if (sln == "recoil_l5_sensor1" || sln == "recoil_l5_sensor2" ||
143 sln == "recoil_l5_sensor3" || sln == "recoil_l5_sensor4" ||
144 sln == "recoil_l5_sensor5" || sln == "recoil_l5_sensor6" ||
145 sln == "recoil_l5_sensor7" || sln == "recoil_l5_sensor8" ||
146 sln == "recoil_l5_sensor9" || sln == "recoil_l5_sensor10" ||
147 (sensor_copy_nr >= 90 && sensor_copy_nr <= 99))
148
149 recoil_layout_["recoil_tracker_L5"].push_back(sensor_surface);
150
151 if (sln == "recoil_l6_sensor1" || sln == "recoil_l6_sensor2" ||
152 sln == "recoil_l6_sensor3" || sln == "recoil_l6_sensor4" ||
153 sln == "recoil_l6_sensor5" || sln == "recoil_l6_sensor6" ||
154 sln == "recoil_l6_sensor7" || sln == "recoil_l6_sensor8" ||
155 sln == "recoil_l6_sensor9" || sln == "recoil_l6_sensor10" ||
156 (sensor_copy_nr >= 100 && sensor_copy_nr <= 109))
157 recoil_layout_["recoil_tracker_L6"].push_back(sensor_surface);
158
159 } // found the daughter
160 } // loop on daughters
161} // BuildRecoilLayoutMap
162
163// This function gets the surfaces from the trackers and orders them in
164// ascending z_.
165
166void TrackersTrackingGeometry::buildTaggerLayoutMap(G4VPhysicalVolume* pvol,
167 std::string surfacename) {
168 ldmx_log(trace) << "Building layout for the " << pvol->GetName()
169 << " tracker";
170 // getAllDaughters(pvol);
171
172 // Get the global transform
173 Acts::Transform3 tracker_transform = getTransform(*pvol);
174
175 G4LogicalVolume* l_vol = pvol->GetLogicalVolume();
176 for (G4int i = 0; i < l_vol->GetNoDaughters(); i++) {
177 std::string sln = l_vol->GetDaughter(i)->GetName();
178
179 // To distinguish which layers need to be selected
180 if (sln.find(surfacename) != std::string::npos) {
181 // v12
182
183 // Box for the module_ (slightly bigger than the sensor)
184 // LDMXTaggerModuleVolume_physvol -> LDMXTaggerModuleVolume_component0Box,
185 // this is the sensor + inactive region
186 // LDMXTaggerModuleVolume_component0Box->
187 // LDMXTaggerModuleVolume_component0Sensor0Box, this is the sensor itself
188 // (active region)
189
190 // tagger_ -> LDMXTaggerModuleVolume_physvol1 ->
191 // LDMXTaggerModuleVolume_component0_physvol
192 // ->LDMXTaggerModuleVolume_component0Sensor0_physvol
193 // -> Get Box for the dimension: GetLogical->GetSolid
194 // For the positioning of the sensor:
195 // A position of physvol1 + position of the component0_physvol +
196 // position of the sensor physvol. Thickness I can grab it from the box,
197 // or I just hardcode it. S transform1 * transform2 * transform3
198 // ....
199
200 // v14
201 // tagger_PV->tagger_sensor_vol_PV->tagger_active_sensor
202 // Then use the copyNumber..
203
204 // Get the sensor volume placement
205 Acts::Transform3 ref1_transform = getTransform(*(l_vol->GetDaughter(i)));
206
207 G4VPhysicalVolume* component0_volume = findDaughterByName(
208 l_vol->GetDaughter(i), "LDMXTaggerModuleVolume_component0_physvol");
209
210 Acts::Transform3 ref2_transform = Acts::Transform3::Identity();
211 G4VPhysicalVolume* active_sensor = nullptr;
212 int sensor_copy_nr = -999;
213
214 // Get Component0 transform. v12
215 if (component0_volume) {
216 ref2_transform = getTransform(*(component0_volume));
217 active_sensor = findDaughterByName(
218 component0_volume,
219 "LDMXTaggerModuleVolume_component0Sensor0_physvol");
220 }
221 // v14
222 else {
223 active_sensor =
224 findDaughterByName(l_vol->GetDaughter(i), "active_sensor");
225 sensor_copy_nr = (l_vol->GetDaughter(i))->GetCopyNo();
226 }
227
228 if (!active_sensor) {
229 ldmx_log(fatal) << "Could not find the ActiveSensor for tagger volume "
230 << l_vol->GetDaughter(i)->GetName();
231 }
232
233 // Get the surface
234 std::shared_ptr<Acts::PlaneSurface> sensor_surface = getSurfacePtr(
235 active_sensor, tracker_transform * ref1_transform * ref2_transform);
236
237 if (sln == "LDMXTaggerModuleVolume_physvol1" ||
238 sln == "LDMXTaggerModuleVolume_physvol2" || sensor_copy_nr == 130 ||
239 sensor_copy_nr == 140)
240 tagger_layout_["tagger_tracker_L1"].push_back(sensor_surface);
241
242 if (sln == "LDMXTaggerModuleVolume_physvol3" ||
243 sln == "LDMXTaggerModuleVolume_physvol4" || sensor_copy_nr == 110 ||
244 sensor_copy_nr == 120)
245 tagger_layout_["tagger_tracker_L2"].push_back(sensor_surface);
246
247 if (sln == "LDMXTaggerModuleVolume_physvol5" ||
248 sln == "LDMXTaggerModuleVolume_physvol6" || sensor_copy_nr == 90 ||
249 sensor_copy_nr == 100)
250 tagger_layout_["tagger_tracker_L3"].push_back(sensor_surface);
251
252 if (sln == "LDMXTaggerModuleVolume_physvol7" ||
253 sln == "LDMXTaggerModuleVolume_physvol8" || sensor_copy_nr == 70 ||
254 sensor_copy_nr == 80)
255 tagger_layout_["tagger_tracker_L4"].push_back(sensor_surface);
256
257 if (sln == "LDMXTaggerModuleVolume_physvol9" ||
258 sln == "LDMXTaggerModuleVolume_physvol10" || sensor_copy_nr == 50 ||
259 sensor_copy_nr == 60)
260 tagger_layout_["tagger_tracker_L5"].push_back(sensor_surface);
261
262 if (sln == "LDMXTaggerModuleVolume_physvol11" ||
263 sln == "LDMXTaggerModuleVolume_physvol12" || sensor_copy_nr == 30 ||
264 sensor_copy_nr == 40)
265 tagger_layout_["tagger_tracker_L6"].push_back(sensor_surface);
266
267 if (sln == "LDMXTaggerModuleVolume_physvol13" ||
268 sln == "LDMXTaggerModuleVolume_physvol14" || sensor_copy_nr == 10 ||
269 sensor_copy_nr == 20)
270 tagger_layout_["tagger_tracker_L7"].push_back(sensor_surface);
271
272 } // found a silicon surface
273 } // loop on daughters
274} // build the layout
275
276std::shared_ptr<Acts::PlaneSurface> TrackersTrackingGeometry::getSurfacePtr(
277 G4VPhysicalVolume* pvol, Acts::Transform3 ref_trans) {
278 if (!pvol) {
279 ldmx_log(fatal) << "pvol is nullptr";
280 }
281
282 // Get the surface transform
283 Acts::Transform3 surface_transform = getTransform(*pvol);
284 // Compose the sensor_transform with the reference transform
285 surface_transform = ref_trans * surface_transform;
286
287 // Now transform to the tracker frame
288 Acts::Transform3 surface_transform_tracker = toTracker(surface_transform);
289
290 ldmx_log(trace) << "THE SENSOR TRANSFORM - TRANSLATION";
291 ldmx_log(trace) << surface_transform.translation()(0);
292 ldmx_log(trace) << surface_transform.translation()(1);
293 ldmx_log(trace) << surface_transform.translation()(2);
294 ldmx_log(trace) << "THE SENSOR TRANSFORM - ROTATION";
295 ldmx_log(trace) << surface_transform.rotation();
296
297 ldmx_log(trace) << "TO THE TRACKER FRAME";
298 ldmx_log(trace) << surface_transform_tracker.translation()(0);
299 ldmx_log(trace) << surface_transform_tracker.translation()(1);
300 ldmx_log(trace) << surface_transform_tracker.translation()(2);
301 ldmx_log(trace) << "THE SENSOR TRANSFORM - ROTATION";
302 ldmx_log(trace) << surface_transform_tracker.rotation();
303
304 // This material is defined in different units with respect what acts expects.
305 // I decided to hardcode here. TODO: fix this
306
307 /*
308 G4Material* sens_mat = _ActiveSensor->GetLogicalVolume()->GetMaterial();
309 ldmx_log(trace)<<"Checking the material of
310 "<<l_vol->GetDaughter(i)->GetName()<<std::endl; ldmx_log(trace)<<"With
311 sensor::"<<_ActiveSensor->GetName()<<std::endl;
312 ldmx_log(trace)<<sens_mat->GetName()<<std::endl;
313 ldmx_log(trace)<<"RL="<<sens_mat->GetRadlen()<<"
314 lambda="<<sens_mat->GetNuclearInterLength()<<std::endl;
315 ldmx_log(trace)<<"A="<<sens_mat->GetA()<<" Z="<<sens_mat->GetZ()<<"
316 rho="<<sens_mat->GetDensity()<<std::endl;
317
318
319 Acts::Material silicon =
320 Acts::Material::fromMassDensity(sens_mat->GetRadlen(),
321 sens_mat->GetNuclearInterLength(),
322 sens_mat->GetA(),
323 sens_mat->GetZ(),
324 sens_mat->GetDensity());
325 */
326
327 // Define the silicon material
328 Acts::Material silicon = Acts::Material::fromMassDensity(
329 95.7 * Acts::UnitConstants::mm, 465.2 * Acts::UnitConstants::mm, 28.03,
330 14., 2.32 * Acts::UnitConstants::g / Acts::UnitConstants::cm3);
331
332 // Get the active sensor box
333 G4Box* surface_solid = (G4Box*)(pvol->GetLogicalVolume()->GetSolid());
334
335 ldmx_log(trace) << "Sensor Dimensions";
336 ldmx_log(trace) << surface_solid->GetXHalfLength() << " "
337 << surface_solid->GetYHalfLength() << " "
338 << surface_solid->GetZHalfLength() << " ";
339
340 // Form the material slab
341 double thickness =
342 2 * surface_solid->GetZHalfLength() * Acts::UnitConstants::mm;
343 Acts::MaterialSlab silicon_slab(silicon, thickness);
344
345 // Get the bounds
346 std::shared_ptr<const Acts::RectangleBounds> rect_bounds =
347 std::make_shared<const Acts::RectangleBounds>(Acts::RectangleBounds(
348 surface_solid->GetXHalfLength() * Acts::UnitConstants::mm,
349 surface_solid->GetYHalfLength() * Acts::UnitConstants::mm));
350
351 // Form the active sensor surface
352 std::shared_ptr<Acts::PlaneSurface> surface =
353 Acts::Surface::makeShared<Acts::PlaneSurface>(surface_transform_tracker,
354 rect_bounds);
355 surface->assignSurfaceMaterial(
356 std::make_shared<Acts::HomogeneousSurfaceMaterial>(silicon_slab));
357
358 // Create an alignable detector element and assign it to the surface.
359 // The default transformation is the surface parsed transformation
360
361 auto det_element = std::make_shared<tracking::geo::DetectorElement>(
362 std::static_pointer_cast<Acts::Surface>(surface),
363 surface_transform_tracker, thickness);
364
365 // This is the call that modify the behaviour of surface->transform(gctx)
366 // After this call each surface will use the underlying detectorElement
367 // transformation which will take care of effectively reading the gctx
368
369 surface->assignDetectorElement(std::move(*det_element));
370 det_elements_.push_back(det_element);
371
372 return surface;
373}
374
375Acts::CuboidVolumeBuilder::VolumeConfig
376TrackersTrackingGeometry::buildVolumeConfig(
377 const G4VPhysicalVolume* detector,
378 const std::map<std::string,
379 std::vector<std::shared_ptr<const Acts::Surface>>>
380 layout,
381 double tracker_y_length, double tracker_z_length,
382 const std::string& volumeName) {
383 Acts::CuboidVolumeBuilder::VolumeConfig sub_det_volume_config;
384
385 // Get the transform wrt the world volume in tracker frame
386 Acts::Transform3 sub_det_transform = getTransform(*detector, true);
387
388 // Add 1mm to not make it sit on the first layer_ surface
389 Acts::Vector3 sub_det_position = {
390 sub_det_transform.translation()(0) - 1,
391 sub_det_transform.translation()(1),
392 sub_det_transform.translation()(2),
393 };
394
395 ldmx_log(trace) << sub_det_position;
396 // Get the size of the volume
397 G4Box* sub_det_box = (G4Box*)(detector->GetLogicalVolume()->GetSolid());
398
399 // In tracker coordinates. Add 1mm to compensate for the movement above
400 double x_length =
401 2 * (sub_det_box->GetZHalfLength() + 1) * Acts::UnitConstants::mm;
402 ldmx_log(info) << "x_length = " << x_length
403 << " y_length = " << tracker_y_length
404 << " z_length = " << tracker_z_length;
405
406 sub_det_volume_config.position = sub_det_position;
407 sub_det_volume_config.length = {x_length, tracker_y_length, tracker_z_length};
408 sub_det_volume_config.name = volumeName;
409
410 // Vacuum material
411 Acts::Material subdet_mat = Acts::Material();
412 sub_det_volume_config.volumeMaterial =
413 std::make_shared<Acts::HomogeneousVolumeMaterial>(subdet_mat);
414
415 std::vector<Acts::CuboidVolumeBuilder::LayerConfig> layer_config;
416
417 // Prepare the layers
418 for (auto& layer : layout) {
419 ldmx_log(trace) << layer.first << " : surfaces==>" << layer.second.size();
420
421 Acts::CuboidVolumeBuilder::LayerConfig lcfg;
422 lcfg.surfaces = layer.second;
423
424 // Get the surface thickness
425 double clearance = 0.01;
426 double thickness = layer.second.front()
427 ->surfaceMaterial()
428 ->materialSlab(Acts::Vector2{0., 0.})
429 .thickness();
430
431 lcfg.envelopeX = std::array<double, 2>{thickness / 2. + clearance,
432 thickness / 2. + clearance};
433 lcfg.active = true;
434 layer_config.push_back(lcfg);
435 }
436
437 sub_det_volume_config.layerCfg = layer_config;
438
439 return sub_det_volume_config;
440}
441
442} // namespace tracking::geo
Visualization.