EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ConvertDD4hepDetector.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file ConvertDD4hepDetector.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017-2018 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 
27 
28 #include <list>
29 #include <stdexcept>
30 
31 #include "TGeoManager.h"
32 
33 namespace Acts {
34 std::unique_ptr<const TrackingGeometry> convertDD4hepDetector(
35  dd4hep::DetElement worldDetElement, Logging::Level loggingLevel,
36  BinningType bTypePhi, BinningType bTypeR, BinningType bTypeZ,
37  double layerEnvelopeR, double layerEnvelopeZ, double defaultLayerThickness,
38  const std::function<void(std::vector<dd4hep::DetElement>& detectors)>&
39  sortSubDetectors,
41  std::shared_ptr<const IMaterialDecorator> matDecorator) {
42  // create local logger for conversion
43  ACTS_LOCAL_LOGGER(Acts::getDefaultLogger("DD4hepConversion", loggingLevel));
44  ACTS_INFO("Translating DD4hep geometry into Acts geometry");
45  // get the sub detectors of the world detector e.g. beampipe, pixel detector,
46  // strip detector
47  std::vector<dd4hep::DetElement> subDetectors;
48  // go through the detector hierarchies
49  collectSubDetectors_dd4hep(worldDetElement, subDetectors);
50  // sort to build detector from bottom to top
51  sortSubDetectors(subDetectors);
52  // the volume builders of the subdetectors
53  std::list<std::shared_ptr<const ITrackingVolumeBuilder>> volumeBuilders;
54  // the beam pipe volume builder needs special treatment and needs to be added
55  // in the end (beampipe exceeds length of all other subdetectors)
56  std::shared_ptr<const CylinderVolumeBuilder> beamPipeVolumeBuilder;
57  // loop over the sub detectors
58  for (auto& subDetector : subDetectors) {
59  ACTS_INFO("Translating DD4hep sub detector: " << subDetector.name());
60  // create volume builder
61  auto volBuilder = volumeBuilder_dd4hep(
62  subDetector, loggingLevel, bTypePhi, bTypeR, bTypeZ, layerEnvelopeR,
63  layerEnvelopeZ, defaultLayerThickness);
64  if (volBuilder) {
65  // distinguish beam pipe
66  if (volBuilder->getConfiguration().buildToRadiusZero) {
67  // check if beam pipe is already present
68  if (beamPipeVolumeBuilder) {
69  throw std::logic_error(
70  std::string("Beampipe has already been set! There can only "
71  "exist one beam pipe. Please check your "
72  "detector construction. Current volume name: ") +
73  volBuilder->getConfiguration().volumeName +
74  std::string(", name of volume, already set as beam pipe: ") +
75  beamPipeVolumeBuilder->getConfiguration().volumeName);
76  }
77  // set the beam pipe
78  beamPipeVolumeBuilder = volBuilder;
79  } else {
80  volumeBuilders.push_back(volBuilder);
81  }
82  }
83  }
84  // Finally add the beam pipe
85  if (beamPipeVolumeBuilder) {
86  volumeBuilders.push_back(beamPipeVolumeBuilder);
87  }
88 
89  std::vector<std::function<std::shared_ptr<TrackingVolume>(
90  const GeometryContext&, const TrackingVolumePtr&,
91  const VolumeBoundsPtr&)>>
92  volumeFactories;
93 
94  for (const auto& vb : volumeBuilders) {
95  volumeFactories.push_back(
96  [vb](const GeometryContext& vgctx,
97  const std::shared_ptr<const TrackingVolume>& inner,
98  const VolumeBoundsPtr&) {
99  return vb->trackingVolume(vgctx, inner);
100  });
101  }
102 
103  // create cylinder volume helper
104  auto volumeHelper = cylinderVolumeHelper_dd4hep();
105  // hand over the collected volume builders
107  tgbConfig.trackingVolumeHelper = volumeHelper;
108  tgbConfig.materialDecorator = std::move(matDecorator);
109  tgbConfig.trackingVolumeBuilders = std::move(volumeFactories);
110  auto trackingGeometryBuilder =
111  std::make_shared<const Acts::TrackingGeometryBuilder>(tgbConfig);
112  return (trackingGeometryBuilder->trackingGeometry(gctx));
113 }
114 
115 std::shared_ptr<const CylinderVolumeBuilder> volumeBuilder_dd4hep(
116  dd4hep::DetElement subDetector, Logging::Level loggingLevel,
117  BinningType bTypePhi, BinningType bTypeR, BinningType bTypeZ,
118  double layerEnvelopeR, double layerEnvelopeZ,
119  double defaultLayerThickness) {
120  // create cylinder volume helper
121  auto volumeHelper = cylinderVolumeHelper_dd4hep(loggingLevel);
122  // create local logger for conversion
123  ACTS_LOCAL_LOGGER(Acts::getDefaultLogger("D2A_Logger", loggingLevel));
124  ACTS_VERBOSE("Processing detector element: " << subDetector.name());
125 
126  Acts::ActsExtension* subDetExtension = nullptr;
127  // at this stage not every DetElement needs to have an Extension attached
128  try {
129  subDetExtension = subDetector.extension<Acts::ActsExtension>();
130  } catch (std::runtime_error& e) {
131  }
132  if (subDetector.type() == "compound") {
133  ACTS_VERBOSE("Subdetector : '"
134  << subDetector.name()
135  << "' has no ActsExtension and has type compound ");
136  ACTS_VERBOSE(
137  "handling as a compound volume (a hierachy of a "
138  "barrel-endcap structure) and resolving the "
139  "subvolumes...");
140  // Now create the Layerbuilders and Volumebuilder
141  // the layers
143  std::vector<dd4hep::DetElement> negativeLayers;
145  std::vector<dd4hep::DetElement> centralLayers;
147  std::vector<dd4hep::DetElement> positiveLayers;
148 
149  // the configuration object of the volume builder
151 
152  // go through sub volumes
153  std::vector<dd4hep::DetElement> compounds;
154  collectCompounds_dd4hep(subDetector, compounds);
155 
156  // get z position to distinguish positive & negative endcap
157  double zPos = 0.;
158  // flags to catch if sub volumes have been set already
159  bool nEndCap = false;
160  bool pEndCap = false;
161  bool barrel = false;
162  for (auto& volumeDetElement : compounds) {
163  ACTS_VERBOSE("Volume : '"
164  << subDetector.name()
165  << "'is a compound volume -> resolve now the sub volumes");
166 
167  // get the dimensions of the volume
168  TGeoShape* geoShape =
169  volumeDetElement.placement().ptr()->GetVolume()->GetShape();
170  // check if it has a shape (the other case should not happen)
171  if (geoShape != nullptr) {
172  zPos = volumeDetElement.placement()
173  .ptr()
174  ->GetMatrix()
175  ->GetTranslation()[2] *
177  } else {
178  throw std::logic_error(std::string("Volume of DetElement: ") +
179  volumeDetElement.name() +
180  std::string(" has no shape!"));
181  }
182  // check if it has a volume extension telling if it is a barrel or an
183  // endcap
184  ActsExtension* volumeExtension = nullptr;
185  try {
186  volumeExtension = volumeDetElement.extension<ActsExtension>();
187  } catch (std::runtime_error& e) {
188  throw std::logic_error(
189  std::string("Current DetElement: ") + volumeDetElement.name() +
190  std::string(" has no ActsExtension! At this stage it should be a "
191  "detector volume declared as Barrel or Endcap. Please"
192  "check your detector construction."));
193  }
194 
195  if (volumeExtension->hasType("endcap", "detector")) {
196  ACTS_VERBOSE(
197  std::string("Subvolume : '") + volumeDetElement.name() +
198  std::string("' is a disc volume -> handling as an endcap"));
199  if (zPos < 0.) {
200  if (nEndCap) {
201  throw std::logic_error(
202  "Negative Endcap was already given for this "
203  "hierachy! Please create a new "
204  "DD4hep_SubDetectorAssembly for the next "
205  "hierarchy.");
206  }
207  nEndCap = true;
208  ACTS_VERBOSE(" ->is negative endcap");
209  collectLayers_dd4hep(volumeDetElement, negativeLayers);
210  // Fill the volume material for barrel case
211  if (volumeExtension->hasType("boundary_material")) {
212  if (volumeExtension->hasValue("boundary_material_negative")) {
214  *volumeExtension, "boundary_material_negative",
215  {{"binPhi", Acts::closed}, {"binR", Acts::open}});
216  }
217  if (volumeExtension->hasValue("boundary_material_positive")) {
219  *volumeExtension, "boundary_material_positive",
220  {{"binPhi", Acts::closed}, {"binR", Acts::open}});
221  }
222  }
223  } else {
224  if (pEndCap) {
225  throw std::logic_error(
226  "Positive Endcap was already given for this "
227  "hierachy! Please create a new "
228  "DD4hep_SubDetectorAssembly for the next "
229  "hierarchy.");
230  }
231  pEndCap = true;
232  ACTS_VERBOSE(" ->is positive endcap");
233  collectLayers_dd4hep(volumeDetElement, positiveLayers);
234  // Fill the volume material for barrel case
235  if (volumeExtension->hasType("boundary_material")) {
236  if (volumeExtension->hasValue("boundary_material_negative")) {
238  *volumeExtension, "boundary_material_negative",
239  {{"binPhi", Acts::closed}, {"binR", Acts::open}});
240  }
241  if (volumeExtension->hasValue("boundary_material_positive")) {
243  *volumeExtension, "boundary_material_positive",
244  {{"binPhi", Acts::closed}, {"binR", Acts::open}});
245  }
246  }
247  }
248  } else if (volumeExtension->hasType("barrel", "detector")) {
249  if (barrel) {
250  throw std::logic_error(
251  "Barrel was already given for this "
252  "hierachy! Please create a new "
253  "DD4hep_SubDetectorAssembly for the next "
254  "hierarchy.");
255  }
256  barrel = true;
257  ACTS_VERBOSE("Subvolume : "
258  << volumeDetElement.name()
259  << " is a cylinder volume -> handling as a barrel");
260  collectLayers_dd4hep(volumeDetElement, centralLayers);
261  // Fill the volume material for barrel case
262  if (volumeExtension->hasType("boundary_material")) {
263  if (volumeExtension->hasValue("boundary_material_negative")) {
265  *volumeExtension, "boundary_material_negative",
266  {{"binPhi", Acts::closed}, {"binR", Acts::open}});
267  }
268  if (volumeExtension->hasValue("boundary_material_positive")) {
270  *volumeExtension, "boundary_material_positive",
271  {{"binPhi", Acts::closed}, {"binR", Acts::open}});
272  }
273  }
274  } else {
275  throw std::logic_error(
276  std::string("Current DetElement: ") + volumeDetElement.name() +
277  std::string(
278  " has wrong ActsExtension! At this stage it should be a "
279  "detector volume declared as Barrel or Endcap. Please "
280  "check your detector construction."));
281  }
282 
283  // Fill the volume material for the inner / outer cover
284  if (volumeExtension->hasType("boundary_material")) {
285  if (volumeExtension->hasValue("boundary_material_inner")) {
287  *volumeExtension, "boundary_material_inner",
288  {{"binPhi", Acts::closed}, {"binZ", Acts::open}});
289  }
290  if (volumeExtension->hasValue("boundary_material_outer")) {
292  *volumeExtension, "boundary_material_outer",
293  {{"binPhi", Acts::closed}, {"binZ", Acts::open}});
294  }
295  }
296  }
297 
298  if ((pEndCap && !nEndCap) || (!pEndCap && nEndCap)) {
299  throw std::logic_error(
300  "Only one Endcap is given for the current "
301  "hierarchy! Endcaps should always occur in "
302  "pairs. Please check your detector "
303  "construction.");
304  }
305 
306  // configure SurfaceArrayCreator
307  auto surfaceArrayCreator =
308  std::make_shared<const Acts::SurfaceArrayCreator>(
309  Acts::getDefaultLogger("D2A_SAC", loggingLevel));
310  // configure LayerCreator
312  lcConfig.surfaceArrayCreator = surfaceArrayCreator;
313  auto layerCreator = std::make_shared<const Acts::LayerCreator>(
314  lcConfig, Acts::getDefaultLogger("D2A_LAC", loggingLevel));
315  // configure DD4hepLayerBuilder
317  lbConfig.configurationName = subDetector.name();
318  lbConfig.layerCreator = layerCreator;
319  lbConfig.negativeLayers = negativeLayers;
320  lbConfig.centralLayers = centralLayers;
321  lbConfig.positiveLayers = positiveLayers;
322  lbConfig.bTypePhi = bTypePhi;
323  lbConfig.bTypeR = bTypeR;
324  lbConfig.bTypeZ = bTypeZ;
325  lbConfig.defaultThickness = defaultLayerThickness;
326  auto dd4hepLayerBuilder = std::make_shared<const Acts::DD4hepLayerBuilder>(
327  lbConfig,
328  Acts::getDefaultLogger(std::string("D2A_L:") + subDetector.name(),
329  loggingLevel));
330 
331  // Create the sub volume
332  // Dimensions are created automatically by adding a tolerance to the
333  // layer setup
334  cvbConfig.layerEnvelopeR = std::make_pair(layerEnvelopeR, layerEnvelopeR);
335  cvbConfig.layerEnvelopeZ = layerEnvelopeZ;
336  cvbConfig.trackingVolumeHelper = volumeHelper;
337  cvbConfig.volumeSignature = 0;
338  cvbConfig.volumeName = subDetector.name();
339  cvbConfig.layerBuilder = dd4hepLayerBuilder;
340  auto cylinderVolumeBuilder =
341  std::make_shared<const Acts::CylinderVolumeBuilder>(
342  cvbConfig,
343  Acts::getDefaultLogger(std::string("D2A_V:") + subDetector.name(),
344  loggingLevel));
345  return cylinderVolumeBuilder;
346 
347  } else if ((subDetExtension != nullptr) &&
348  (subDetExtension->hasType("passive cylinder", "layer") ||
349  subDetExtension->hasType("beampipe", "layer"))) {
350  ACTS_VERBOSE("Subdetector : " << subDetector.name()
351  << " - building a passive cylinder.");
352  if (subDetExtension->hasType("beampipe", "layer")) {
353  ACTS_VERBOSE("This is the beam pipe - will be built to r -> 0.");
354  }
355 
356  // get the dimensions of the volume
357  TGeoShape* geoShape =
358  subDetector.placement().ptr()->GetVolume()->GetShape();
359  TGeoTubeSeg* tube = dynamic_cast<TGeoTubeSeg*>(geoShape);
360  if (tube == nullptr) {
361  throw std::logic_error(
362  "Cylinder has wrong shape - needs to be TGeoTubeSeg!");
363  }
364  // get the dimension of TGeo and convert lengths
365  double rMin = tube->GetRmin() * UnitConstants::cm - layerEnvelopeR;
366  double rMax = tube->GetRmax() * UnitConstants::cm + layerEnvelopeR;
367  double halfZ = tube->GetDz() * UnitConstants::cm + layerEnvelopeZ;
368  ACTS_VERBOSE(
369  "Extracting cylindrical volume bounds ( rmin / rmax / "
370  "halfZ )= ( "
371  << rMin << " / " << rMax << " / " << halfZ << " )");
372 
373  std::shared_ptr<Acts::ISurfaceMaterial> plMaterial = nullptr;
374  if (subDetExtension->hasType("layer_material")) {
375  // get the possible material of the surounding volume
376  plMaterial = Acts::createProtoMaterial(
377  *subDetExtension, "layer_material_representing",
378  {{"binPhi", Acts::closed}, {"binZ", Acts::open}});
379  }
380 
381  // configure the passive layer builder
383  plbConfig.layerIdentification = subDetector.name();
384  plbConfig.centralLayerRadii = std::vector<double>(1, 0.5 * (rMax + rMin));
385  plbConfig.centralLayerHalflengthZ = std::vector<double>(1, halfZ);
386  plbConfig.centralLayerThickness = std::vector<double>(1, fabs(rMax - rMin));
387  plbConfig.centralLayerMaterial = {plMaterial};
388  auto pcLayerBuilder = std::make_shared<const Acts::PassiveLayerBuilder>(
389  plbConfig,
390  Acts::getDefaultLogger(std::string("D2A_PL:") + subDetector.name(),
391  loggingLevel));
392 
393  // the configuration object of the volume builder
395  cvbConfig.trackingVolumeHelper = volumeHelper;
396  cvbConfig.volumeSignature = 0;
397  cvbConfig.volumeName = subDetector.name();
398  cvbConfig.layerBuilder = pcLayerBuilder;
399  cvbConfig.layerEnvelopeR = {layerEnvelopeR, layerEnvelopeR};
400  cvbConfig.layerEnvelopeZ = layerEnvelopeZ;
401  cvbConfig.buildToRadiusZero = subDetExtension->hasType("beampipe", "layer");
402 
403  // beam pipe / passive cylinder volume builder
404  auto pcVolumeBuilder = std::make_shared<const Acts::CylinderVolumeBuilder>(
405  cvbConfig,
406  Acts::getDefaultLogger(std::string("D2A_V:") + subDetector.name(),
407  loggingLevel));
408  return pcVolumeBuilder;
409 
410  } else if ((subDetExtension != nullptr) &&
411  subDetExtension->hasType("barrel", "detector")) {
412  ACTS_VERBOSE("Subdetector: "
413  << subDetector.name()
414  << " is a (sensitive) Barrel volume - building barrel.");
416  std::vector<dd4hep::DetElement> centralLayers, centralVolumes;
417  collectLayers_dd4hep(subDetector, centralLayers);
418  collectVolumes_dd4hep(subDetector, centralVolumes);
419 
420  // configure SurfaceArrayCreator
421  auto surfaceArrayCreator =
422  std::make_shared<const Acts::SurfaceArrayCreator>(
423  Acts::getDefaultLogger("D2A_SAC", loggingLevel));
424  // configure LayerCreator
426  lcConfig.surfaceArrayCreator = surfaceArrayCreator;
427  auto layerCreator = std::make_shared<const Acts::LayerCreator>(
428  lcConfig, Acts::getDefaultLogger("D2A_LAC", loggingLevel));
429  // configure DD4hepLayerBuilder
431  lbConfig.configurationName = subDetector.name();
432  lbConfig.layerCreator = layerCreator;
433  lbConfig.centralLayers = centralLayers;
434  lbConfig.bTypePhi = bTypePhi;
435  lbConfig.bTypeZ = bTypeZ;
436  lbConfig.defaultThickness = defaultLayerThickness;
437  auto dd4hepLayerBuilder = std::make_shared<const Acts::DD4hepLayerBuilder>(
438  lbConfig,
439  Acts::getDefaultLogger(std::string("D2A_LB_") + subDetector.name(),
440  loggingLevel));
441 
442  // Configure DD4hepVolumeBuilder
444  vbConfig.configurationName = subDetector.name();
445  vbConfig.centralVolumes = centralVolumes;
446  auto dd4hepVolumeBuilder =
447  std::make_shared<const Acts::DD4hepVolumeBuilder>(
448  vbConfig,
449  Acts::getDefaultLogger(std::string("D2A_VB_") + subDetector.name(),
450  loggingLevel));
451 
452  // the configuration object of the volume builder
454  // get the dimensions of the volume
455  TGeoShape* geoShape =
456  subDetector.placement().ptr()->GetVolume()->GetShape();
457  // this should not happen
458  if (geoShape == nullptr) {
459  throw std::logic_error(std::string("Volume of DetElement: ") +
460  subDetector.name() +
461  std::string(" has no a shape!"));
462  }
463 
464  cvbConfig.layerEnvelopeR = std::make_pair(layerEnvelopeR, layerEnvelopeR);
465  cvbConfig.layerEnvelopeZ = layerEnvelopeZ;
466  cvbConfig.trackingVolumeHelper = volumeHelper;
467  cvbConfig.volumeSignature = 0;
468  cvbConfig.volumeName = subDetector.name();
469  cvbConfig.layerBuilder = dd4hepLayerBuilder;
470  cvbConfig.ctVolumeBuilder = dd4hepVolumeBuilder;
471  auto cylinderVolumeBuilder =
472  std::make_shared<const Acts::CylinderVolumeBuilder>(
473  cvbConfig,
474  Acts::getDefaultLogger(std::string("D2A_V:") + subDetector.name(),
475  loggingLevel));
476  return cylinderVolumeBuilder;
477 
478  } else {
479  ACTS_INFO(
480  "Subdetector with name : '"
481  << subDetector.name()
482  << "' has wrong ActsExtension for translation and is not of type "
483  "'compound'. If you want to have this DetElement be translated "
484  "into the tracking geometry you need add the right "
485  "ActsExtension (at this stage the subvolume needs to be "
486  "declared as beampipe or barrel) or if it is a compound "
487  "DetElement (containing a barrel-endcap hierarchy), the type "
488  "needs to be set to 'compound'.");
489  return nullptr;
490  }
491 }
492 
493 std::shared_ptr<const Acts::CylinderVolumeHelper> cylinderVolumeHelper_dd4hep(
494  Logging::Level loggingLevel) {
495  // create cylindervolumehelper which can be used by all instances
496  // hand over LayerArrayCreator
498  auto layerArrayCreator = std::make_shared<const Acts::LayerArrayCreator>(
499  lacConfig, Acts::getDefaultLogger(std::string("D2A_LAC"), loggingLevel));
500  // tracking volume array creator
502  auto trackingVolumeArrayCreator =
503  std::make_shared<const Acts::TrackingVolumeArrayCreator>(
504  tvacConfig,
505  Acts::getDefaultLogger(std::string("D2A_TVAC"), loggingLevel));
506  // configure the cylinder volume helper
508  cvhConfig.layerArrayCreator = layerArrayCreator;
509  cvhConfig.trackingVolumeArrayCreator = trackingVolumeArrayCreator;
510  auto cylinderVolumeHelper =
511  std::make_shared<const Acts::CylinderVolumeHelper>(
512  cvhConfig,
513  Acts::getDefaultLogger(std::string("D2A_CVH"), loggingLevel));
514 
515  return cylinderVolumeHelper;
516 }
517 
518 void collectCompounds_dd4hep(dd4hep::DetElement& detElement,
519  std::vector<dd4hep::DetElement>& compounds) {
520  const dd4hep::DetElement::Children& children = detElement.children();
521  for (auto& child : children) {
522  dd4hep::DetElement childDetElement = child.second;
523  Acts::ActsExtension* detExtension = nullptr;
524  try {
525  detExtension = childDetElement.extension<Acts::ActsExtension>();
526  } catch (std::runtime_error& e) {
527  }
528  if ((detExtension != nullptr) &&
529  (detExtension->hasType("barrel", "detector") ||
530  detExtension->hasType("endcap", "detector"))) {
531  compounds.push_back(childDetElement);
532  continue;
533  }
534  collectCompounds_dd4hep(childDetElement, compounds);
535  }
536 }
537 
538 void collectSubDetectors_dd4hep(dd4hep::DetElement& detElement,
539  std::vector<dd4hep::DetElement>& subdetectors) {
540  const dd4hep::DetElement::Children& children = detElement.children();
541  for (auto& child : children) {
542  dd4hep::DetElement childDetElement = child.second;
543  Acts::ActsExtension* detExtension = nullptr;
544  try {
545  detExtension = childDetElement.extension<Acts::ActsExtension>();
546  } catch (std::runtime_error& e) {
547  if (childDetElement.type() == "compound") {
548  subdetectors.push_back(childDetElement);
549  continue;
550  }
551  }
552  if ((detExtension != nullptr) &&
553  (detExtension->hasType("barrel", "detector") ||
554  detExtension->hasType("beampipe", "layer"))) {
555  subdetectors.push_back(childDetElement);
556  continue;
557  }
558  collectSubDetectors_dd4hep(childDetElement, subdetectors);
559  }
560 }
561 
562 void collectLayers_dd4hep(dd4hep::DetElement& detElement,
563  std::vector<dd4hep::DetElement>& layers) {
564  const dd4hep::DetElement::Children& children = detElement.children();
565  for (auto& child : children) {
566  dd4hep::DetElement childDetElement = child.second;
567  Acts::ActsExtension* detExtension = nullptr;
568  try {
569  detExtension = childDetElement.extension<Acts::ActsExtension>();
570  } catch (std::runtime_error& e) {
571  }
572  if ((detExtension != nullptr) && detExtension->hasType("layer")) {
573  layers.push_back(childDetElement);
574  continue;
575  }
576  collectLayers_dd4hep(childDetElement, layers);
577  }
578 }
579 
580 void collectVolumes_dd4hep(dd4hep::DetElement& detElement,
581  std::vector<dd4hep::DetElement>& volumes) {
582  const dd4hep::DetElement::Children& children = detElement.children();
583  for (auto& child : children) {
584  dd4hep::DetElement childDetElement = child.second;
585  Acts::ActsExtension* detExtension = nullptr;
586  try {
587  detExtension = childDetElement.extension<Acts::ActsExtension>();
588  } catch (std::runtime_error& e) {
589  }
590  if ((detExtension != nullptr) && detExtension->hasType("volume")) {
591  volumes.push_back(childDetElement);
592  continue;
593  }
594  collectVolumes_dd4hep(childDetElement, volumes);
595  }
596 }
597 } // End of namespace Acts