ATLAS Offline Software
RobustTrackingGeometryBuilderImpl.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 namespace InDet {
5 template <RobustTrackingGeometryBuilderImpl::ToolType type,
6  typename LayerBuilders, typename PipeBuilder>
7 std::unique_ptr<Trk::TrackingGeometry>
8 RobustTrackingGeometryBuilderImpl::trackingGeometryImpl(
9  const LayerBuilders& layerHandles, const PipeBuilder& pipeHandle,
10  [[maybe_unused]] const EventContext* ctx,
11  [[maybe_unused]] SG::WriteCondHandle<Trk::TrackingGeometry>* whandle)
12  const {
13 
14  // only one assumption:
15  // layer builders are ordered in increasing r
16 
17  ////////////////////////////////////////////////////////////////////////////////////////////////////////
18  // The Overall Geometry
19 
20  // retrieve all the layers and sort them
21  unsigned int numLayBuilders = layerHandles.size();
22 
23  // central sector extend
24  double centralExtendZ = 0.;
25  // endcap extends
26  double endcapMaxExtend = 0.;
27  double endcapMinExtend = 10e10;
28  // and the overallExtend(s)
29  double overallExtendZ = 0.;
30  double overallRmin = 10e10;
31  double overallRmax = 0.;
32 
33  // cylinder layers at growing radii
34  std::vector<std::vector<Trk::Layer*> > providedCylinderLayers;
35  providedCylinderLayers.reserve(numLayBuilders);
36  std::vector<double> cylinderInnerRadii(numLayBuilders, 10e10);
37  std::vector<double> cylinderOuterRadii(numLayBuilders, 0.);
38  std::vector<double> cylinderExtendsInZ(numLayBuilders, 0.);
39 
40  // negative disc layers and positive disc layers
41  std::vector<std::vector<Trk::Layer*> > providedDiscLayersNeg;
42  std::vector<std::vector<Trk::Layer*> > providedDiscLayersPos;
43  providedDiscLayersNeg.reserve(numLayBuilders);
44  providedDiscLayersPos.reserve(numLayBuilders);
45  std::vector<double> discInnerRadii(numLayBuilders, 10e10);
46  std::vector<double> discOuterRadii(numLayBuilders, 0.);
47  std::vector<double> discMinZ(numLayBuilders, 10e10);
48  std::vector<double> discMaxZ(numLayBuilders, 0.);
49 
50  // (I) PARSE THE LAYERS FOR OVERALL DIMENSIONS
51  // -------------------------------------------------------------
52  ATH_MSG_DEBUG("[ STEP 1 ] : Parse the provided layers for the dimensions.");
53  // fill the layers into the vectors
54  for (unsigned int ilb = 0; ilb < layerHandles.size(); ++ilb) {
55 
56  Trk::BinningType binningType =
57  (m_layerBinningType.size() == layerHandles.size())
58  ? (Trk::BinningType)m_layerBinningType[ilb]
59  : Trk::arbitrary;
60 
61  // retrieve the cylinder and disc layers
62  ATH_MSG_DEBUG("[ LayerBuilder : '" << layerHandles[ilb]->identification()
63  << "' ] being processed. ");
64  // (a) cylinder
65  std::unique_ptr<const std::vector<Trk::CylinderLayer*> > cylinderLayers =
66  nullptr;
67  if constexpr (type == Cond) {
68  cylinderLayers = layerHandles[ilb]->cylindricalLayers(*ctx, *whandle);
69  } else {
70  cylinderLayers = layerHandles[ilb]->cylindricalLayers();
71  }
72  // (a)
73  std::vector<Trk::Layer*> cylinderVolumeLayers;
74  if (cylinderLayers && !cylinderLayers->empty()) {
75  // screen output
76  ATH_MSG_DEBUG(" Processing CylinderLayers : ");
77  // the ones to be filled into the double-vector
78  for (const auto& cylIter : *cylinderLayers) {
79  // get the CylinderBounds
80  const Trk::CylinderBounds& cylBounds =
81  (cylIter)->surfaceRepresentation().bounds();
82  double currentR = cylBounds.r();
83  // rmin/rmax with thicknes in mind
84  double currentRmin =
85  binningType != Trk::biequidistant
86  ? currentR - 0.5 * (cylIter)->thickness() - m_layerEnvelopeCover
87  : currentR + 0.5 * (cylIter)->thickness() -
88  m_layerEnvelopeCover;
89  double currentRmax =
90  currentR + 0.5 * (cylIter)->thickness() + m_layerEnvelopeCover;
91  // safe
92  double extendZ =
93  cylIter->surfaceRepresentation().center().z() < 0.
94  ? std::abs(cylIter->surfaceRepresentation().center().z() -
95  cylBounds.halflengthZ()) -
96  m_layerEnvelopeCover
97  : cylIter->surfaceRepresentation().center().z() +
98  cylBounds.halflengthZ() + m_layerEnvelopeCover;
99  // note the dimension
100  takeSmaller(cylinderInnerRadii[ilb], currentRmin);
101  takeBigger(cylinderOuterRadii[ilb], currentRmax);
102  takeBigger(cylinderExtendsInZ[ilb], extendZ);
103  // push it into the vector
104  cylinderVolumeLayers.push_back(cylIter);
105  // overall dimensions
106  takeSmaller(overallRmin, currentRmin);
107  takeBigger(overallRmax, currentRmax);
108  takeBigger(centralExtendZ, extendZ);
109  // in case no disc layers are provided
110  takeBigger(overallExtendZ, centralExtendZ);
111  }
112  // special treatment for bi-equidistant binning - a navigation layer will
113  // be added before and after the layers
114  if (binningType == Trk::biequidistant) {
115  double rStep = (cylinderOuterRadii[ilb] - cylinderInnerRadii[ilb]) /
116  (cylinderLayers->size() - 1);
117  ATH_MSG_VERBOSE(" -> bi-equidistant : rStep estimated as "
118  << rStep);
119  cylinderInnerRadii[ilb] -= rStep;
120  cylinderOuterRadii[ilb] += rStep;
121  takeBigger(overallRmax, cylinderOuterRadii[ilb]);
122  }
123  ATH_MSG_VERBOSE(" -> yield (rMin/rMax/halflengthZ) = "
124  << cylinderInnerRadii[ilb] << " / "
125  << cylinderOuterRadii[ilb] << " / "
126  << cylinderExtendsInZ[ilb]);
127 
128  } else
129  ATH_MSG_DEBUG(" No cylindrical layers processed.");
130 
131  providedCylinderLayers.push_back(cylinderVolumeLayers);
132  // if after parsing of cylinder layers the maximal extend of cylinders is
133  // bigger than the minmal of discs reset the disc min extend (tiple will be
134  // swallowed)!
135  endcapMinExtend =
136  (centralExtendZ > endcapMinExtend) ? 10e10 : endcapMinExtend;
137 
138  // (b) discs
139  std::unique_ptr<const std::vector<Trk::DiscLayer*> > discLayers = nullptr;
140  if constexpr (type == Cond) {
141  discLayers = layerHandles[ilb]->discLayers(*ctx, *whandle);
142  } else {
143  discLayers = layerHandles[ilb]->discLayers();
144  }
145 
146  std::vector<Trk::Layer*> discVolumeLayersNeg;
147  std::vector<Trk::Layer*> discVolumeLayersPos;
148  if (discLayers && !discLayers->empty()) {
149  // screen output
150  ATH_MSG_DEBUG(" Processing DiscLayers : ");
151  for (const auto& discIter : *discLayers) {
152  // get the DiscBounds
153  const Trk::DiscBounds* discBounds =
154  dynamic_cast<const Trk::DiscBounds*>(
155  &(discIter->surfaceRepresentation().bounds()));
156  // get the current Z min/max
157  double discZ = discIter->surfaceRepresentation().center().z();
158  double currentZmin = binningType != Trk::biequidistant
159  ? (discZ - 0.5 * discIter->thickness())
160  : (discZ + 0.5 * discIter->thickness());
161  double currentZmax = discZ + 0.5 * discIter->thickness();
162  // force it to be symmetrized
163  if (currentZmax > 0.) {
164  takeSmaller(discMinZ[ilb], currentZmin);
165  takeBigger(discMaxZ[ilb], currentZmax);
166  // push it into the vector
167  discVolumeLayersPos.push_back(discIter);
168  } else {
169  // in symmetrized setup only interested in total numbers
170  double negMinZ = std::abs(currentZmax);
171  double negMaxZ = std::abs(currentZmin);
172  takeSmaller(discMinZ[ilb], negMinZ);
173  takeBigger(discMaxZ[ilb], negMaxZ);
174  // push it into the vector
175  discVolumeLayersNeg.push_back(discIter);
176  }
177 
178  // radial dimensions
179  if (discBounds) {
180  double currentRmin = discBounds->rMin();
181  double currentRmax = discBounds->rMax();
182  // note the dimension
183  takeSmaller(discInnerRadii[ilb], currentRmin);
184  takeBigger(discOuterRadii[ilb], currentRmax);
185  // overall dimensions
186  takeSmaller(overallRmin, currentRmin);
187  takeBigger(overallRmax, currentRmax);
188  }
189  // min/max extend of the discs
190  takeSmaller(endcapMinExtend, discMinZ[ilb]);
191  takeBigger(endcapMaxExtend, discMaxZ[ilb]);
192  takeBigger(overallExtendZ, endcapMaxExtend);
193  }
194  // special treatment for bi-equidistant binning - a navigation layer will
195  // be added before and after the layers
196  if (binningType == Trk::biequidistant) {
197  double zStep =
198  (discMaxZ[ilb] - discMinZ[ilb]) / (discLayers->size() / 2 - 1);
199  discMinZ[ilb] -= zStep;
200  discMaxZ[ilb] += zStep;
201  takeBigger(overallExtendZ, discMaxZ[ilb]);
202  }
203 
204  ATH_MSG_VERBOSE(" -> yield (rMin/rMax/zMin/zMax) = "
205  << discInnerRadii[ilb] << " / " << discOuterRadii[ilb]
206  << " / " << discMinZ[ilb] << " / " << discMaxZ[ilb]);
207 
208  } else
209  ATH_MSG_DEBUG(" No disk-like layers processed.");
210 
211  // fill the layers into the double-vector
212  providedDiscLayersNeg.push_back(discVolumeLayersNeg);
213  providedDiscLayersPos.push_back(discVolumeLayersPos);
214 
215  if (msgLvl(MSG::VERBOSE)) {
216  // summary after this step
217  ATH_MSG_VERBOSE(
218  "[ Summary STEP 1 ---------------------------------------- ] ");
219  ATH_MSG_VERBOSE(
220  " overall minimum r : " << overallRmin);
221  ATH_MSG_VERBOSE(
222  " overall maximum r : " << overallRmax);
223  ATH_MSG_VERBOSE(
224  " overall z extend : " << overallExtendZ);
225  ATH_MSG_VERBOSE(
226  " central sector z extend : " << centralExtendZ);
227  ATH_MSG_VERBOSE(
228  " maximum endcap z extend : " << endcapMaxExtend);
229  ATH_MSG_VERBOSE(
230  " minimum endcap z extend : " << endcapMinExtend);
231  }
232  }
233 
234  // (II) update the positions
235  // ------------------------------------------------------------
236  ATH_MSG_DEBUG(
237  "[ STEP 2 ] : Closing the gaps from the parsed original dimensions.");
238  // i.e. close the gap
239  double oldCeZ = centralExtendZ;
240  centralExtendZ = 0.5 * (endcapMinExtend + oldCeZ);
241  endcapMinExtend = centralExtendZ;
242 
243  ATH_MSG_DEBUG(" central sector extend in z recalculated to be "
244  << centralExtendZ << " (was " << oldCeZ << ")");
245 
246  // (III) create the sub volumes
247  // -------------------------------------------------------------
248  ATH_MSG_DEBUG("[ STEP 3 ] : Create the sub volumes.");
249 
250  std::vector<Trk::TrackingVolume*> centralSectorVolumes;
251  std::vector<Trk::TrackingVolume*> negativeSectorVolumes;
252  std::vector<Trk::TrackingVolume*> positiveSectorVolumes;
253 
254  // --------------------------------------------------------------------------------------------------
255  // first the beampipe volume
256  Trk::TrackingVolume* beamPipeVolume = nullptr;
257  // the Volume Bounds
258  Trk::CylinderVolumeBounds* beamPipeBounds =
259  new Trk::CylinderVolumeBounds(overallRmin, overallExtendZ);
260  // BinnedArray needed
261  Trk::BinnedArray<Trk::Layer>* beamPipeLayerArray = nullptr;
262 
263  std::unique_ptr<const std::vector<Trk::CylinderLayer*> > beamPipeVecPtr =
264  nullptr;
265  if constexpr (type == Cond) {
266  beamPipeVecPtr = pipeHandle->cylindricalLayers(*ctx, *whandle);
267  } else {
268  beamPipeVecPtr = pipeHandle->cylindricalLayers();
269  }
270 
271  if (!beamPipeVecPtr->empty()) {
272  beamPipeLayerArray = m_layerArrayCreator->cylinderLayerArray(
273  *beamPipeVecPtr, 0., beamPipeBounds->outerRadius(), Trk::arbitrary);
274  }
275  // create the TrackingVolume
276  beamPipeVolume =
277  new Trk::TrackingVolume(nullptr, beamPipeBounds, *m_materialProperties,
278  beamPipeLayerArray, nullptr, "InDet::BeamPipe");
279  // set the color code
280  beamPipeVolume->registerColorCode(46);
281 
282  // beampipe + detectors / prepared
283  std::vector<Trk::TrackingVolume*> idVolumes;
284  idVolumes.push_back(beamPipeVolume);
285 
286  // --------------------------------------------------------------------------------------------------
287  double lastCentralOuterR = beamPipeBounds->outerRadius();
288  double lastNegEndcapOuterR = lastCentralOuterR;
289  double lastPosEndcapOuterR = lastCentralOuterR;
290 
291  // loop over double-vectors, access the dimensions from the parsing
292  auto pclIter = providedCylinderLayers.begin();
293  auto pclEnd = providedCylinderLayers.end();
294  auto pndlIter = providedDiscLayersNeg.begin();
295  auto pndlEnd = providedDiscLayersNeg.end();
296  auto ppdlIter = providedDiscLayersPos.begin();
297  auto ppdlEnd = providedDiscLayersPos.end();
298 
299  // the number of layer builders
300  unsigned int numLayerBuilders = layerHandles.size();
301 
302  // loop over the prepared volumes
303  for (unsigned int ilb = 0;
304  pclIter != pclEnd && pndlIter != pndlEnd && ppdlIter != ppdlEnd;
305  ++pclIter, ++pndlIter, ++ppdlIter, ++ilb) {
306  // color code configuration (from jobOptions/declareProperty interface)
307  int colorCode = (m_colorCodesConfig.size() == numLayerBuilders)
308  ? m_colorCodesConfig[ilb]
309  : 21;
310 
311  Trk::BinningType binningType =
312  (m_layerBinningType.size() == numLayerBuilders)
313  ? (Trk::BinningType)m_layerBinningType[ilb]
314  : Trk::arbitrary;
315 
316  // volume name base
317  std::string baseName = layerHandles[ilb]->identification();
318  ATH_MSG_DEBUG("[ Volume Creation : '" << baseName << "'] carried out.");
319  ATH_MSG_DEBUG(" + color code : " << colorCode);
320 
321  // maxmmal z extend for volume set & endcap inner z
322  double currentSetExtendZ = (!(*pndlIter).empty() || !(*ppdlIter).empty())
323  ? discMaxZ[ilb]
324  : cylinderExtendsInZ[ilb];
325  double currentEndcapInnerZ = (!(*pndlIter).empty() || !(*ppdlIter).empty())
326  ? discMinZ[ilb]
327  : currentSetExtendZ;
328 
329  // radii for the sectors
330  double currentCentralOuterR = 0.;
331  double currentEndcapOuterR = 0.;
332 
333  if (m_isITk) {
334  double NextInnerRadii =
335  ((ilb != cylinderOuterRadii.size() - 1) &&
336  cylinderInnerRadii[ilb + 1] < discInnerRadii[ilb + 1])
337  ? cylinderInnerRadii[ilb + 1]
338  : discInnerRadii[ilb + 1];
339  currentCentralOuterR =
340  (ilb != cylinderOuterRadii.size() - 1)
341  ? 0.5 * (NextInnerRadii + cylinderOuterRadii[ilb])
342  : overallRmax;
343  currentEndcapOuterR = (ilb != discOuterRadii.size() - 1)
344  ? 0.5 * (NextInnerRadii + discOuterRadii[ilb])
345  : overallRmax;
346  } else {
347  // we build from inside to outside, don't take middle position, but tend
348  // towards outer extend
349  currentCentralOuterR =
350  (ilb != cylinderOuterRadii.size() - 1)
351  ? (m_outwardsFraction * cylinderInnerRadii[ilb + 1] +
352  (1. - m_outwardsFraction) * cylinderOuterRadii[ilb])
353  : overallRmax;
354  currentEndcapOuterR =
355  (ilb != discOuterRadii.size() - 1)
356  ? (m_outwardsFraction * discInnerRadii[ilb + 1] +
357  (1. - m_outwardsFraction) * discOuterRadii[ilb])
358  : overallRmax;
359  }
360 
361  ATH_MSG_VERBOSE(" + checking the sector boundaries : ");
362  ATH_MSG_VERBOSE(" central sector ext. z (boundary) = "
363  << currentSetExtendZ << " (" << centralExtendZ << ")");
364  ATH_MSG_VERBOSE(" + current volume radii rMax (c/d) = "
365  << currentCentralOuterR << " / " << currentEndcapOuterR);
366  // estimate the case
367  // cases are :
368  enum PackCase { contained, radial, central, split };
369  // 0 - both cylinders and disc are contained in the central sector
370  // 1 - radial packing, volumes can't be put in in central / ec sectors
371  // 2 - only central sector exists
372  // 3 - standard ecn / central / ecp sectors split
373  bool endcapsExist = !(*pndlIter).empty() && !(*ppdlIter).empty();
374  // case flag set
375  PackCase caseFlag = (currentSetExtendZ < centralExtendZ && endcapsExist)
376  ? contained
377  : split;
378  if (currentSetExtendZ > centralExtendZ &&
379  currentEndcapInnerZ < centralExtendZ && endcapsExist)
380  caseFlag = radial;
381  if (!endcapsExist)
382  caseFlag = central;
383 
384  // case 0 and 1 can be handled together :
385  if (caseFlag == contained || caseFlag == radial) {
386  // create the volume sizes for the compact volume
387  double currentCentralExtendZ =
388  0.5 * (cylinderExtendsInZ[ilb] + discMinZ[ilb]);
389  double currentExtendZ = contained ? centralExtendZ : overallExtendZ;
390  // in the radial wrapping case : take the smaller radius, assumes that
391  // packing is possible
392  double currentOuterR = currentCentralOuterR < currentEndcapOuterR
393  ? currentCentralOuterR
394  : currentEndcapOuterR;
395  // create the tiple container
396  Trk::TrackingVolume* tripleContainer = packVolumeTriple(
397  (*pndlIter), (*pclIter), (*ppdlIter), lastCentralOuterR,
398  currentOuterR, currentExtendZ, currentCentralExtendZ, baseName,
399  colorCode, binningType);
400 
401  // cache the last central / ec outer radius
402  lastCentralOuterR = currentOuterR;
403  if (contained) {
404  ATH_MSG_VERBOSE(
405  " + case I : provided cylinder and disc layers are "
406  "entirely contained in central sector.");
407  // and push the centralSectorVolumes
408  centralSectorVolumes.push_back(tripleContainer);
409  } else {
410  ATH_MSG_VERBOSE(
411  " + case II : split into negative - central - positive "
412  "sectors doesn't work, radial wrapping");
413  // cache the laster endcap radii (need to be equal since this is
414  // radially wrapped)
415  lastNegEndcapOuterR = currentOuterR;
416  lastPosEndcapOuterR = currentOuterR;
417  // the triple goes into the radial packing volumes
418  idVolumes.push_back(tripleContainer);
419  }
420  // case 2 and 3
421  } else {
422  // output for case 3 and 4
423  if (!endcapsExist)
424  ATH_MSG_VERBOSE(" + case III : only central sector.");
425  else
426  ATH_MSG_VERBOSE(
427  " + case IV : split into negative - central - positive "
428  "sectors.");
429  // build the name
430  std::string volumeBase = m_namespace + "Detectors::" + baseName;
431  // cylinder layers exist -------------------------------
432  if (!(*pclIter).empty()) {
433 
434  ATH_MSG_VERBOSE(" -> central sector is being build.");
435  // create the cylinder barrel
436  Trk::TrackingVolume* barrel =
437  m_trackingVolumeCreator->createTrackingVolume(
438  (*pclIter), *m_materialProperties, lastCentralOuterR,
439  currentCentralOuterR, -centralExtendZ, centralExtendZ,
440  volumeBase + "::Barrel", binningType);
441  // register the color code
442  barrel->registerColorCode(colorCode);
443  // cache the last ones
444  lastCentralOuterR = currentCentralOuterR;
445  // and push the centralSectorVolumes
446  centralSectorVolumes.push_back(barrel);
447  }
448 
449  // negative disc layers exist ------------------------------
450  if (!(*pndlIter).empty()) {
451 
452  ATH_MSG_VERBOSE(" -> negative endcap is being build.");
453  // create the cylinder barrel
454  Trk::TrackingVolume* negEndcap =
455  m_trackingVolumeCreator->createTrackingVolume(
456  (*pndlIter), *m_materialProperties, lastNegEndcapOuterR,
457  currentEndcapOuterR, -overallExtendZ, -endcapMinExtend,
458  volumeBase + "::NegativeEndcap", binningType);
459  // register the color code
460  negEndcap->registerColorCode(colorCode);
461  // cache the last ones
462  lastNegEndcapOuterR = currentEndcapOuterR;
463  // and push the negativeSectorVolumes
464  negativeSectorVolumes.push_back(negEndcap);
465  }
466  // positive disc layers exist --------------------------------
467  if (!(*ppdlIter).empty()) {
468 
469  ATH_MSG_VERBOSE(" -> positive endcap is being build.");
470  // create the cylinder barrel
471  Trk::TrackingVolume* posEndcap =
472  m_trackingVolumeCreator->createTrackingVolume(
473  (*ppdlIter), *m_materialProperties, lastPosEndcapOuterR,
474  currentEndcapOuterR, endcapMinExtend, overallExtendZ,
475  volumeBase + "::PositiveEndcap", binningType);
476  // register the color code
477  posEndcap->registerColorCode(colorCode);
478  // cache the last ones
479  lastPosEndcapOuterR = currentEndcapOuterR;
480  // and push the positiveSectorVolumes
481  positiveSectorVolumes.push_back(posEndcap);
482  }
483  }
484  }
485 
486  // (IV) create the container
487  // ---------------------------------------------------------
488  ATH_MSG_DEBUG("[ STEP 4 ] : Create the container volume");
489 
490  bool enclose = (!m_enclosingEnvelopeSvc.empty());
491 
492  Trk::TrackingVolume* detectorContainer =
493  packVolumeTriple(negativeSectorVolumes, centralSectorVolumes,
494  positiveSectorVolumes, "Container");
495 
496  // get the dimensions from the envelope service
497  const RZPairVector& envelopeDefs =
498  m_enclosingEnvelopeSvc->getInDetRZBoundary();
499  ATH_MSG_VERBOSE(
500  " -> retrieved Inner Detector envelope definitions at size "
501  << envelopeDefs.size());
502  double enclosingVolumeRadius = envelopeDefs[1].first;
503  double enclosingVolumeHalfZ = fabs(envelopeDefs[1].second);
504 
505  // central enclosure volume
506  Trk::TrackingVolume* centralEnclosure =
507  enclose ? m_trackingVolumeCreator->createGapTrackingVolume(
508  *m_materialProperties, overallRmax, enclosingVolumeRadius,
509  -overallExtendZ, overallExtendZ, 1, true,
510  m_namespace + "Gaps::CentralEnclosure")
511  : nullptr;
512 
513  // push the detector container into the ID volumes
514  idVolumes.push_back(detectorContainer);
515  if (centralEnclosure)
516  idVolumes.push_back(centralEnclosure);
517 
518  std::string volumeName =
519  enclose ? "InDet::Detectors::BpPixSctTrt" : m_exitVolume;
520 
521  ATH_MSG_VERBOSE(" -> inserting beam pipe into detectors.");
522 
523  Trk::TrackingVolume* detectorWithBp =
524  m_trackingVolumeCreator->createContainerTrackingVolume(
525  idVolumes, *m_materialProperties, volumeName, m_buildBoundaryLayers,
526  m_replaceJointBoundaries);
527 
528  // if packing is needed
529  // ------------------------------------------------------------------
530  Trk::TrackingVolume* highestIdVolume = nullptr;
531  if (enclose) {
532 
533  // negative positions
534  std::vector<double> negDiscPositionZ(m_enclosingDiscPositionZ);
535  for (double& posIter : negDiscPositionZ)
536  posIter *= -1;
537 
538  Trk::TrackingVolume* negativeEnclosure =
539  !negDiscPositionZ.empty()
540  ? m_trackingVolumeCreator->createGapTrackingVolume(
541  *m_materialProperties, 0., enclosingVolumeRadius,
542  -enclosingVolumeHalfZ, -overallExtendZ, negDiscPositionZ,
543  false, m_namespace + "Gaps::NegativeEnclosure")
544  : m_trackingVolumeCreator->createGapTrackingVolume(
545  *m_materialProperties, 0., enclosingVolumeRadius,
546  -enclosingVolumeHalfZ, -overallExtendZ, 1, false,
547  m_namespace + "Gaps::NegativeEnclosure");
548 
549  Trk::TrackingVolume* positiveEnclosure =
550  !m_enclosingDiscPositionZ.empty()
551  ? m_trackingVolumeCreator->createGapTrackingVolume(
552  *m_materialProperties, 0., enclosingVolumeRadius,
553  overallExtendZ, enclosingVolumeHalfZ,
554  m_enclosingDiscPositionZ, false,
555  m_namespace + "Gaps::PositiveEnclosure")
556  : m_trackingVolumeCreator->createGapTrackingVolume(
557  *m_materialProperties, 0., enclosingVolumeRadius,
558  overallExtendZ, enclosingVolumeHalfZ, 1, false,
559  m_namespace + "Gaps::PositiveEnclosure");
560 
561  std::vector<Trk::TrackingVolume*> enclosedVolumes;
562  enclosedVolumes.push_back(negativeEnclosure);
563  enclosedVolumes.push_back(detectorWithBp);
564  enclosedVolumes.push_back(positiveEnclosure);
565 
566  Trk::TrackingVolume* enclosedDetector =
567  m_trackingVolumeCreator->createContainerTrackingVolume(
568  enclosedVolumes, *m_materialProperties, m_exitVolume,
569  m_buildBoundaryLayers, m_replaceJointBoundaries);
570 
571  highestIdVolume = enclosedDetector;
572  } else
573  highestIdVolume = detectorWithBp;
574 
575  // (V) create the TrackingGeometry
576  // ------------------------------------------------------
577  auto trackingGeometry =
578  std::make_unique<Trk::TrackingGeometry>(highestIdVolume);
579 
580  if (m_indexStaticLayers) {
581  ATH_MSG_VERBOSE("Re-index the static layers ...");
582  // ST temporary hack till layer numbering resolved
583  // trackingGeometry->indexStaticLayers(geometrySignature());
584  trackingGeometry->indexStaticLayers(Trk::Global);
585  }
586 
587  return trackingGeometry;
588 }
589 
590 } // namespace InDet