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