Analysis Software
Documentation for sPHENIX simulation 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 
30 
31 #include <array>
32 #include <cmath>
33 #include <list>
34 #include <map>
35 #include <regex>
36 #include <sstream>
37 #include <stdexcept>
38 #include <string>
39 #include <utility>
40 
41 #include "DD4hep/DetType.h"
42 #include "DDRec/DetectorData.h"
43 #include "TGeoManager.h"
44 
45 namespace Acts {
46 class IMaterialDecorator;
47 class ISurfaceMaterial;
48 class TrackingGeometry;
49 class TrackingVolume;
50 
51 namespace {
52 struct DebugVisitor {
53  std::string operator()(int value) { return std::to_string(value); }
54 
55  std::string operator()(double value) { return std::to_string(value); }
56 
57  std::string operator()(std::string value) { return value; }
58 };
59 } // namespace
60 
61 std::unique_ptr<const TrackingGeometry> convertDD4hepDetector(
62  dd4hep::DetElement worldDetElement, const Logger& logger,
63  BinningType bTypePhi, BinningType bTypeR, BinningType bTypeZ,
64  double layerEnvelopeR, double layerEnvelopeZ, double defaultLayerThickness,
65  const std::function<void(std::vector<dd4hep::DetElement>& detectors)>&
66  sortSubDetectors,
68  std::shared_ptr<const IMaterialDecorator> matDecorator,
69  std::shared_ptr<const GeometryIdentifierHook> geometryIdentifierHook) {
70  // create local logger for conversion
71  ACTS_INFO("Translating DD4hep geometry into Acts geometry");
72  // get the sub detectors of the world detector e.g. beampipe, pixel detector,
73  // strip detector
74  std::vector<dd4hep::DetElement> subDetectors;
75  // go through the detector hierarchies
76  collectSubDetectors_dd4hep(worldDetElement, subDetectors, logger);
77  ACTS_VERBOSE("Collected " << subDetectors.size() << " sub detectors");
78  // sort to build detector from bottom to top
79  sortSubDetectors(subDetectors);
80  // the volume builders of the subdetectors
81  std::list<std::shared_ptr<const ITrackingVolumeBuilder>> volumeBuilders;
82  // the beam pipe volume builder needs special treatment and needs to be added
83  // in the end (beampipe exceeds length of all other subdetectors)
84  std::shared_ptr<const CylinderVolumeBuilder> beamPipeVolumeBuilder;
85  // loop over the sub detectors
86  for (auto& subDetector : subDetectors) {
87  ACTS_INFO("Translating DD4hep sub detector: " << subDetector.name());
88 
89  const dd4hep::rec::VariantParameters* params =
90  subDetector.extension<dd4hep::rec::VariantParameters>(false);
91 
92  if (params != nullptr) {
93  ACTS_VERBOSE("VariantParameters from DD4hep:");
94  for (const auto& [k, v] : params->variantParameters) {
95  ACTS_VERBOSE("- " << k << ": "
96  << boost::apply_visitor(DebugVisitor{}, v));
97  }
98  }
99 
100  // create volume builder
101  auto volBuilder = volumeBuilder_dd4hep(
102  subDetector, logger, bTypePhi, bTypeR, bTypeZ, layerEnvelopeR,
103  layerEnvelopeZ, defaultLayerThickness);
104  if (volBuilder) {
105  // distinguish beam pipe
106  if (volBuilder->getConfiguration().buildToRadiusZero) {
107  // check if beam pipe is already present
108  if (beamPipeVolumeBuilder) {
109  throw std::logic_error(
110  std::string("Beampipe has already been set! There can only "
111  "exist one beam pipe. Please check your "
112  "detector construction. Current volume name: ") +
113  volBuilder->getConfiguration().volumeName +
114  std::string(", name of volume, already set as beam pipe: ") +
115  beamPipeVolumeBuilder->getConfiguration().volumeName);
116  }
117  // set the beam pipe
118  beamPipeVolumeBuilder = volBuilder;
119  } else {
120  volumeBuilders.push_back(volBuilder);
121  }
122  }
123  }
124  // Finally add the beam pipe
125  if (beamPipeVolumeBuilder) {
126  volumeBuilders.push_back(beamPipeVolumeBuilder);
127  }
128 
129  std::vector<std::function<std::shared_ptr<TrackingVolume>(
130  const GeometryContext&, const TrackingVolumePtr&,
131  const VolumeBoundsPtr&)>>
132  volumeFactories;
133 
134  for (const auto& vb : volumeBuilders) {
135  volumeFactories.push_back(
136  [vb](const GeometryContext& vgctx,
137  const std::shared_ptr<const TrackingVolume>& inner,
138  const VolumeBoundsPtr&) {
139  return vb->trackingVolume(vgctx, inner);
140  });
141  }
142 
143  // create cylinder volume helper
144  auto volumeHelper = cylinderVolumeHelper_dd4hep(logger);
145  // hand over the collected volume builders
147  tgbConfig.trackingVolumeHelper = volumeHelper;
148  tgbConfig.materialDecorator = std::move(matDecorator);
149  tgbConfig.trackingVolumeBuilders = std::move(volumeFactories);
150  tgbConfig.geometryIdentifierHook = std::move(geometryIdentifierHook);
151  auto trackingGeometryBuilder =
152  std::make_shared<const Acts::TrackingGeometryBuilder>(tgbConfig);
153  return (trackingGeometryBuilder->trackingGeometry(gctx));
154 }
155 
156 std::shared_ptr<const CylinderVolumeBuilder> volumeBuilder_dd4hep(
157  dd4hep::DetElement subDetector, const Logger& logger, BinningType bTypePhi,
158  BinningType bTypeR, BinningType bTypeZ, double layerEnvelopeR,
159  double layerEnvelopeZ, double defaultLayerThickness) {
160  // create cylinder volume helper
161  auto volumeHelper = cylinderVolumeHelper_dd4hep(logger);
162  // create local logger for conversion
163  ACTS_VERBOSE("Processing detector element: " << subDetector.name());
164 
165  dd4hep::DetType subDetType{subDetector.typeFlag()};
166  ACTS_VERBOSE("SubDetector type is: ["
167  << subDetType << "], compound: "
168  << (subDetector.type() == "compound" ? "yes" : "no"));
169  if (subDetector.type() == "compound") {
170  ACTS_VERBOSE("Subdetector : '" << subDetector.name()
171  << "' has type compound ");
172  ACTS_VERBOSE(
173  "handling as a compound volume (a hierarchy of a "
174  "barrel-endcap structure) and resolving the "
175  "subvolumes...");
176  // Now create the Layerbuilders and Volumebuilder
177  // the layers
179  std::vector<dd4hep::DetElement> negativeLayers;
181  std::vector<dd4hep::DetElement> centralLayers;
183  std::vector<dd4hep::DetElement> positiveLayers;
184 
185  // the configuration object of the volume builder
187 
188  // go through sub volumes
189  std::vector<dd4hep::DetElement> compounds;
190  collectCompounds_dd4hep(subDetector, compounds);
191 
192  // get z position to distinguish positive & negative endcap
193  double zPos = 0.;
194  // flags to catch if sub volumes have been set already
195  bool nEndCap = false;
196  bool pEndCap = false;
197  bool barrel = false;
198  for (auto& volumeDetElement : compounds) {
199  ACTS_VERBOSE("Volume : '"
200  << subDetector.name()
201  << "' is a compound volume -> resolve the sub volumes");
202 
203  // get the dimensions of the volume
204  TGeoShape* geoShape =
205  volumeDetElement.placement().ptr()->GetVolume()->GetShape();
206  // check if it has a shape (the other case should not happen)
207  if (geoShape != nullptr) {
208  zPos = volumeDetElement.placement()
209  .ptr()
210  ->GetMatrix()
211  ->GetTranslation()[2] *
213  } else {
214  throw std::logic_error(std::string("Volume of DetElement: ") +
215  volumeDetElement.name() +
216  std::string(" has no shape!"));
217  }
218 
219  dd4hep::DetType type{volumeDetElement.typeFlag()};
220 
221  if (type.is(dd4hep::DetType::ENDCAP)) {
222  ACTS_VERBOSE(std::string("Subvolume : '") + volumeDetElement.name() +
223  std::string("' is marked ENDCAP"));
224  if (zPos < 0.) {
225  if (nEndCap) {
226  throw std::logic_error(
227  "Negative Endcap was already given for this "
228  "hierarchy! Please create a new "
229  "DD4hep_SubDetectorAssembly for the next "
230  "hierarchy.");
231  }
232  nEndCap = true;
233  ACTS_VERBOSE("-> is negative endcap");
234  ACTS_VERBOSE("-> collecting layers");
235  collectLayers_dd4hep(volumeDetElement, negativeLayers, logger);
236  // Fill the volume material for barrel case
237  if (getParamOr<bool>("boundary_material", volumeDetElement, false)) {
238  ACTS_VERBOSE(
239  "-> boundary_material flag detected, creating proto "
240  "material.");
241  auto& params = getParams(volumeDetElement);
242  if (hasParam("boundary_material_negative", volumeDetElement)) {
243  ACTS_VERBOSE("--> negative");
245  params, "boundary_material_negative",
246  {{"binPhi", Acts::closed}, {"binR", Acts::open}}, logger);
247  }
248  if (hasParam("boundary_material_positive", volumeDetElement)) {
249  ACTS_VERBOSE("--> positive");
251  params, "boundary_material_positive",
252  {{"binPhi", Acts::closed}, {"binR", Acts::open}}, logger);
253  }
254  }
255  } else {
256  if (pEndCap) {
257  throw std::logic_error(
258  "Positive Endcap was already given for this "
259  "hierarchy! Please create a new "
260  "DD4hep_SubDetectorAssembly for the next "
261  "hierarchy.");
262  }
263  pEndCap = true;
264  ACTS_VERBOSE("-> is positive endcap");
265  ACTS_VERBOSE("-> collecting layers");
266  collectLayers_dd4hep(volumeDetElement, positiveLayers, logger);
267  // Fill the volume material for barrel case
268  if (getParamOr<bool>("boundary_material", volumeDetElement, false)) {
269  ACTS_VERBOSE(
270  "-> boundary_material flag detected, creating proto "
271  "material.");
272  auto& params = getParams(volumeDetElement);
273  if (params.contains("boundary_material_negative")) {
274  ACTS_VERBOSE("--> negative");
276  params, "boundary_material_negative",
277  {{"binPhi", Acts::closed}, {"binR", Acts::open}}, logger);
278  }
279  if (params.contains("boundary_material_positive")) {
280  ACTS_VERBOSE("--> positive");
282  params, "boundary_material_positive",
283  {{"binPhi", Acts::closed}, {"binR", Acts::open}}, logger);
284  }
285  }
286  }
287  } else if (type.is(dd4hep::DetType::BARREL)) {
288  if (barrel) {
289  throw std::logic_error(
290  "Barrel was already given for this "
291  "hierarchy! Please create a new "
292  "DD4hep_SubDetectorAssembly for the next "
293  "hierarchy.");
294  }
295  barrel = true;
296  ACTS_VERBOSE("Subvolume : " << volumeDetElement.name()
297  << " is marked as BARREL");
298  ACTS_VERBOSE("-> collecting layers");
299  collectLayers_dd4hep(volumeDetElement, centralLayers, logger);
300  // Fill the volume material for barrel case
301  if (getParamOr<bool>("boundary_material", volumeDetElement, false)) {
302  ACTS_VERBOSE(
303  "-> boundary_material flag detected, creating proto "
304  "material.");
305  auto& params = getParams(volumeDetElement);
306  if (params.contains("boundary_material_negative")) {
307  ACTS_VERBOSE("--> negative");
309  params, "boundary_material_negative",
310  {{"binPhi", Acts::closed}, {"binR", Acts::open}}, logger);
311  }
312  if (params.contains("boundary_material_positive")) {
313  ACTS_VERBOSE("--> positive");
315  params, "boundary_material_positive",
316  {{"binPhi", Acts::closed}, {"binR", Acts::open}}, logger);
317  }
318  }
319  } else {
320  throw std::logic_error(
321  std::string("Current DetElement: ") + volumeDetElement.name() +
322  std::string(" has inconsistent settings. It's a compound,"
323  " but its DetectorType is neither BARREL nor ENDCAP"
324  " Please check your detector construction."));
325  }
326 
327  // Fill the volume material for the inner / outer cover
328  if (getParamOr<bool>("boundary_material", volumeDetElement, false)) {
329  ACTS_VERBOSE(
330  "-> boundary_material flag detected, creating proto "
331  "material.");
332  auto& params = getParams(volumeDetElement);
333  if (params.contains("boundary_material_inner")) {
334  ACTS_VERBOSE("--> inner");
336  params, "boundary_material_inner",
337  {{"binPhi", Acts::closed}, {"binZ", Acts::open}}, logger);
338  }
339  if (params.contains("boundary_material_outer")) {
340  ACTS_VERBOSE("--> outer");
342  params, "boundary_material_outer",
343  {{"binPhi", Acts::closed}, {"binZ", Acts::open}}, logger);
344  }
345  }
346  }
347 
348  if ((pEndCap && !nEndCap) || (!pEndCap && nEndCap)) {
349  throw std::logic_error(
350  "Only one Endcap is given for the current "
351  "hierarchy! Endcaps should always occur in "
352  "pairs. Please check your detector "
353  "construction.");
354  }
355 
356  // configure SurfaceArrayCreator
357  auto surfaceArrayCreator =
358  std::make_shared<const Acts::SurfaceArrayCreator>(
359  logger.clone("D2A_SAC"));
360  // configure LayerCreator
362  lcConfig.surfaceArrayCreator = surfaceArrayCreator;
363  auto layerCreator = std::make_shared<const Acts::LayerCreator>(
364  lcConfig, logger.clone("D2A_LAC"));
365  // configure DD4hepLayerBuilder
367  lbConfig.configurationName = subDetector.name();
368  lbConfig.layerCreator = layerCreator;
369  lbConfig.negativeLayers = negativeLayers;
370  lbConfig.centralLayers = centralLayers;
371  lbConfig.positiveLayers = positiveLayers;
372  lbConfig.bTypePhi = bTypePhi;
373  lbConfig.bTypeR = bTypeR;
374  lbConfig.bTypeZ = bTypeZ;
375  lbConfig.defaultThickness = defaultLayerThickness;
376  auto dd4hepLayerBuilder = std::make_shared<const Acts::DD4hepLayerBuilder>(
377  lbConfig, logger.clone(std::string("D2A_L:") + subDetector.name()));
378 
379  // Create the sub volume
380  // Dimensions are created automatically by adding a tolerance to the
381  // layer setup
382  cvbConfig.layerEnvelopeR = std::make_pair(layerEnvelopeR, layerEnvelopeR);
383  cvbConfig.layerEnvelopeZ = layerEnvelopeZ;
384  cvbConfig.trackingVolumeHelper = volumeHelper;
385  cvbConfig.volumeSignature = 0;
386  cvbConfig.volumeName = subDetector.name();
387  cvbConfig.layerBuilder = dd4hepLayerBuilder;
388  auto cylinderVolumeBuilder =
389  std::make_shared<const Acts::CylinderVolumeBuilder>(
390  cvbConfig,
391  logger.clone(std::string("D2A_V:") + subDetector.name()));
392  return cylinderVolumeBuilder;
393  } else if (subDetType.is(dd4hep::DetType::BEAMPIPE) ||
394  getParamOr<bool>("passive_layer", subDetector, false)) {
395  ACTS_VERBOSE("Subdetector : " << subDetector.name()
396  << " - building a passive cylinder.");
397 
398  if (subDetType.is(dd4hep::DetType::BEAMPIPE)) {
399  ACTS_VERBOSE("This is the beam pipe - will be built to r -> 0.");
400  }
401 
402  // get the dimensions of the volume
403  TGeoShape* geoShape =
404  subDetector.placement().ptr()->GetVolume()->GetShape();
405  TGeoTubeSeg* tube = dynamic_cast<TGeoTubeSeg*>(geoShape);
406  if (tube == nullptr) {
407  throw std::logic_error(
408  "Cylinder has wrong shape - needs to be TGeoTubeSeg!");
409  }
410  // get the dimension of TGeo and convert lengths
411  double rMin = tube->GetRmin() * UnitConstants::cm - layerEnvelopeR;
412  double rMax = tube->GetRmax() * UnitConstants::cm + layerEnvelopeR;
413  double halfZ = tube->GetDz() * UnitConstants::cm + layerEnvelopeZ;
414  ACTS_VERBOSE(
415  "Extracting cylindrical volume bounds ( rmin / rmax / "
416  "halfZ )= ( "
417  << rMin << " / " << rMax << " / " << halfZ << " )");
418 
419  std::shared_ptr<Acts::ISurfaceMaterial> plMaterial = nullptr;
420  if (getParamOr<bool>("layer_material", subDetector, false)) {
421  // get the possible material of the surrounding volume
422  ACTS_VERBOSE("--> adding layer material at 'representing'");
423  plMaterial = Acts::createProtoMaterial(
424  getParams(subDetector), "layer_material_representing",
425  {{"binPhi", Acts::closed}, {"binZ", Acts::open}}, logger);
426  }
427 
428  // configure the passive layer builder
430  plbConfig.layerIdentification = subDetector.name();
431  plbConfig.centralLayerRadii = std::vector<double>(1, 0.5 * (rMax + rMin));
432  plbConfig.centralLayerHalflengthZ = std::vector<double>(1, halfZ);
433  plbConfig.centralLayerThickness = std::vector<double>(1, fabs(rMax - rMin));
434  plbConfig.centralLayerMaterial = {plMaterial};
435  auto pcLayerBuilder = std::make_shared<const Acts::PassiveLayerBuilder>(
436  plbConfig, logger.clone(std::string("D2A_PL:") + subDetector.name()));
437 
438  // the configuration object of the volume builder
440  cvbConfig.trackingVolumeHelper = volumeHelper;
441  cvbConfig.volumeSignature = 0;
442  cvbConfig.volumeName = subDetector.name();
443  cvbConfig.layerBuilder = pcLayerBuilder;
444  cvbConfig.layerEnvelopeR = {layerEnvelopeR, layerEnvelopeR};
445  cvbConfig.layerEnvelopeZ = layerEnvelopeZ;
446  cvbConfig.buildToRadiusZero = subDetType.is(dd4hep::DetType::BEAMPIPE);
447 
448  // Fill the volume material for the inner / outer cover
449  if (getParamOr<bool>("boundary_material", subDetector, false)) {
450  ACTS_VERBOSE(
451  "-> boundary_material flag detected, creating proto "
452  "material.");
453  auto& params = getParams(subDetector);
454  if (hasParam("boundary_material_inner", subDetector)) {
455  ACTS_VERBOSE("--> inner");
457  params, "boundary_material_inner",
458  {{"binPhi", Acts::closed}, {"binZ", Acts::open}}, logger);
459  }
460  if (hasParam("boundary_material_outer", subDetector)) {
461  ACTS_VERBOSE("--> outer");
463  params, "boundary_material_outer",
464  {{"binPhi", Acts::closed}, {"binZ", Acts::open}}, logger);
465  }
466  }
467 
468  // beam pipe / passive cylinder volume builder
469  auto pcVolumeBuilder = std::make_shared<const Acts::CylinderVolumeBuilder>(
470  cvbConfig, logger.clone(std::string("D2A_V:") + subDetector.name()));
471  return pcVolumeBuilder;
472  } else if (subDetType.is(dd4hep::DetType::BARREL)) {
473  ACTS_VERBOSE("Subdetector: "
474  << subDetector.name()
475  << " is a (sensitive) Barrel volume - building barrel.");
477  std::vector<dd4hep::DetElement> centralLayers, centralVolumes;
478  ACTS_VERBOSE("-> collecting layers");
479  collectLayers_dd4hep(subDetector, centralLayers, logger);
480 
481  // configure SurfaceArrayCreator
482  auto surfaceArrayCreator =
483  std::make_shared<const Acts::SurfaceArrayCreator>(
484  logger.clone("D2A_SAC"));
485  // configure LayerCreator
487  lcConfig.surfaceArrayCreator = surfaceArrayCreator;
488  auto layerCreator = std::make_shared<const Acts::LayerCreator>(
489  lcConfig, logger.clone("D2A_LAC"));
490  // configure DD4hepLayerBuilder
492  lbConfig.configurationName = subDetector.name();
493  lbConfig.layerCreator = layerCreator;
494  lbConfig.centralLayers = centralLayers;
495  lbConfig.bTypePhi = bTypePhi;
496  lbConfig.bTypeZ = bTypeZ;
497  lbConfig.defaultThickness = defaultLayerThickness;
498  auto dd4hepLayerBuilder = std::make_shared<const Acts::DD4hepLayerBuilder>(
499  lbConfig, logger.clone(std::string("D2A_LB_") + subDetector.name()));
500 
501  // Configure DD4hepVolumeBuilder
503  vbConfig.configurationName = subDetector.name();
504  vbConfig.centralVolumes = centralVolumes;
505  auto dd4hepVolumeBuilder =
506  std::make_shared<const Acts::DD4hepVolumeBuilder>(
507  vbConfig,
508  logger.clone(std::string("D2A_VB_") + subDetector.name()));
509 
510  // the configuration object of the volume builder
512  // get the dimensions of the volume
513  TGeoShape* geoShape =
514  subDetector.placement().ptr()->GetVolume()->GetShape();
515  // this should not happen
516  if (geoShape == nullptr) {
517  throw std::logic_error(std::string("Volume of DetElement: ") +
518  subDetector.name() +
519  std::string(" has no a shape!"));
520  }
521 
522  cvbConfig.layerEnvelopeR = std::make_pair(layerEnvelopeR, layerEnvelopeR);
523  cvbConfig.layerEnvelopeZ = layerEnvelopeZ;
524  cvbConfig.trackingVolumeHelper = volumeHelper;
525  cvbConfig.volumeSignature = 0;
526  cvbConfig.volumeName = subDetector.name();
527  cvbConfig.layerBuilder = dd4hepLayerBuilder;
528  cvbConfig.ctVolumeBuilder = dd4hepVolumeBuilder;
529  auto cylinderVolumeBuilder =
530  std::make_shared<const Acts::CylinderVolumeBuilder>(
531  cvbConfig,
532  logger.clone(std::string("D2A_V:") + subDetector.name()));
533  return cylinderVolumeBuilder;
534  } else {
535  ACTS_INFO(
536  "Subdetector with name : '"
537  << subDetector.name()
538  << "' has inconsistent information for translation and is not of type "
539  "'compound'. If you want to have this DetElement be translated "
540  "into the tracking geometry you need add the right DetectorType "
541  "or VariantParameters (at this stage the subvolume needs to be "
542  "declared as BEAMPIPE or BARREl, or have a VariantParameter "
543  "passive_layer=true) or if it is a compound DetElement (containing "
544  "a barrel-endcap hierarchy), the type needs to be set to "
545  "'compound'.");
546  return nullptr;
547  }
548 }
549 
550 std::shared_ptr<const Acts::CylinderVolumeHelper> cylinderVolumeHelper_dd4hep(
551  const Logger& logger) {
552  // create cylindervolumehelper which can be used by all instances
553  // hand over LayerArrayCreator
555  auto layerArrayCreator = std::make_shared<const Acts::LayerArrayCreator>(
556  lacConfig, logger.clone("D2A_LAC"));
557  // tracking volume array creator
559  auto trackingVolumeArrayCreator =
560  std::make_shared<const Acts::TrackingVolumeArrayCreator>(
561  tvacConfig, logger.clone("D2A_TVAC"));
562  // configure the cylinder volume helper
564  cvhConfig.layerArrayCreator = layerArrayCreator;
565  cvhConfig.trackingVolumeArrayCreator = trackingVolumeArrayCreator;
566  auto cylinderVolumeHelper =
567  std::make_shared<const Acts::CylinderVolumeHelper>(
568  cvhConfig, logger.clone("D2A_CVH"));
569 
570  return cylinderVolumeHelper;
571 }
572 
573 void collectCompounds_dd4hep(dd4hep::DetElement& detElement,
574  std::vector<dd4hep::DetElement>& compounds) {
575  const dd4hep::DetElement::Children& children = detElement.children();
576  for (auto& child : children) {
577  dd4hep::DetElement childDetElement = child.second;
578  dd4hep::DetType type{childDetElement.typeFlag()};
579  if (type.is(dd4hep::DetType::BARREL) || type.is(dd4hep::DetType::ENDCAP)) {
580  compounds.push_back(childDetElement);
581  }
582  collectCompounds_dd4hep(childDetElement, compounds);
583  }
584 }
585 
586 void collectSubDetectors_dd4hep(dd4hep::DetElement& detElement,
587  std::vector<dd4hep::DetElement>& subdetectors,
588  const Logger& logger) {
589  const dd4hep::DetElement::Children& children = detElement.children();
590  for (auto& child : children) {
591  dd4hep::DetElement childDetElement = child.second;
592  dd4hep::DetType type{childDetElement.typeFlag()};
593  if (childDetElement.type() == "compound") {
594  subdetectors.push_back(childDetElement);
595  continue;
596  }
597 
598  if (type.is(dd4hep::DetType::TRACKER)) {
599  subdetectors.push_back(childDetElement);
600  }
601  collectSubDetectors_dd4hep(childDetElement, subdetectors, logger);
602  }
603 }
604 
605 void collectLayers_dd4hep(dd4hep::DetElement& detElement,
606  std::vector<dd4hep::DetElement>& layers,
607  const Logger& logger) {
608  const dd4hep::DetElement::Children& children = detElement.children();
609  for (auto& child : children) {
610  std::string _expr{"$^"}; // nothing
611 
612  dd4hep::rec::VariantParameters* params =
613  detElement.extension<dd4hep::rec::VariantParameters>(false);
614 
615  if (params != nullptr) {
616  _expr = params->value_or<std::string>("layer_pattern", _expr);
617  ACTS_VERBOSE("--> Layer pattern for elt " << detElement.name() << ": "
618  << _expr);
619  }
620  std::regex expr{_expr};
621 
622  dd4hep::DetElement childDetElement = child.second;
623 
624  if (std::regex_search(childDetElement.name(), expr)) {
625  ACTS_VERBOSE("--> Layer candidate match: " << _expr << " -> "
626  << childDetElement.name());
627  layers.push_back(childDetElement);
628  continue;
629  }
630 
631  collectLayers_dd4hep(childDetElement, layers, logger);
632  }
633 }
634 
635 } // End of namespace Acts