Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DD4hepLayerBuilder.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file DD4hepLayerBuilder.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017-2019 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 
16 #include "Acts/Geometry/Extent.hpp"
17 #include "Acts/Geometry/Layer.hpp"
31 
32 #include <algorithm>
33 #include <array>
34 #include <cmath>
35 #include <cstddef>
36 #include <iterator>
37 #include <map>
38 #include <ostream>
39 #include <stdexcept>
40 #include <utility>
41 
42 #include <boost/algorithm/string.hpp>
43 
44 #include "DD4hep/Alignments.h"
45 #include "DD4hep/DetElement.h"
46 #include "DD4hep/Volumes.h"
47 #include "DDRec/DetectorData.h"
48 #include "RtypesCore.h"
49 #include "TGeoManager.h"
50 #include "TGeoMatrix.h"
51 
54  std::unique_ptr<const Logger> logger)
55  : m_cfg(), m_logger(std::move(logger)) {
56  setConfiguration(config);
57 }
58 
60 
63  m_cfg = config;
64 }
65 
67  const GeometryContext& gctx,
68  const std::vector<dd4hep::DetElement>& dendcapLayers,
69  const std::string& side) const {
70  LayerVector layers;
71  if (dendcapLayers.empty()) {
72  ACTS_VERBOSE(" No layers handed over for " << side << " volume!");
73  } else {
74  ACTS_VERBOSE(" Received layers for " << side
75  << " volume -> creating "
76  "disc layers");
77  // go through layers
78  for (auto& detElement : dendcapLayers) {
79  ACTS_VERBOSE("=> Translating layer from: " << detElement.name());
80  // prepare the layer surfaces
81  std::vector<std::shared_ptr<const Surface>> layerSurfaces;
82  // access the extension of the layer
83  // at this stage all layer detElements have extension (checked in
84  // ConvertDD4hepDetector)
85  auto& params = getParams(detElement);
86  // collect the sensitive detector elements possibly contained by the layer
87  resolveSensitive(detElement, layerSurfaces);
88  // access the global transformation matrix of the layer
89  auto transform =
90  convertTransform(&(detElement.nominal().worldTransformation()));
91  // get the shape of the layer
92  TGeoShape* geoShape =
93  detElement.placement().ptr()->GetVolume()->GetShape();
94  // create the proto layer
95  ProtoLayer pl(gctx, layerSurfaces);
96  if (logger().doPrint(Logging::VERBOSE)) {
97  std::stringstream ss;
98  pl.toStream(ss);
99  ACTS_VERBOSE("Extent from surfaces: " << ss.str());
100 
101  std::vector<double> rvalues;
102  std::transform(layerSurfaces.begin(), layerSurfaces.end(),
103  std::back_inserter(rvalues), [&](const auto& surface) {
104  return VectorHelpers::perp(surface->center(gctx));
105  });
106  std::sort(rvalues.begin(), rvalues.end());
107  std::vector<std::string> locs;
108  std::transform(rvalues.begin(),
109  std::unique(rvalues.begin(), rvalues.end()),
110  std::back_inserter(locs),
111  [](const auto& v) { return std::to_string(v); });
112  ACTS_VERBOSE(
113  "-> unique r locations: " << boost::algorithm::join(locs, ", "));
114  }
115 
116  if (params.contains("envelope_r_min") &&
117  params.contains("envelope_r_max") &&
118  params.contains("envelope_z_min") &&
119  params.contains("envelope_z_max")) {
120  // set the values of the proto layer in case enevelopes are handed
121  // over
122  pl.envelope[Acts::binR] = {params.get<double>("envelope_r_min"),
123  params.get<double>("envelope_r_max")};
124  pl.envelope[Acts::binZ] = {params.get<double>("envelope_z_min"),
125  params.get<double>("envelope_z_max")};
126  } else if (geoShape != nullptr) {
127  TGeoTubeSeg* tube = dynamic_cast<TGeoTubeSeg*>(geoShape);
128  if (tube == nullptr) {
129  ACTS_ERROR(" Disc layer has wrong shape - needs to be TGeoTubeSeg!");
130  }
131  // extract the boundaries
132  double rMin = tube->GetRmin() * UnitConstants::cm;
133  double rMax = tube->GetRmax() * UnitConstants::cm;
134  double zMin =
135  (transform.translation() -
136  transform.rotation().col(2) * tube->GetDz() * UnitConstants::cm)
137  .z();
138  double zMax =
139  (transform.translation() +
140  transform.rotation().col(2) * tube->GetDz() * UnitConstants::cm)
141  .z();
142  if (zMin > zMax) {
143  std::swap(zMin, zMax);
144  }
145  // check if layer has surfaces
146  if (layerSurfaces.empty()) {
147  ACTS_VERBOSE(" Disc layer has no sensitive surfaces.");
148  // in case no surfaces are handed over the layer thickness will be
149  // set to a default value to allow attaching material layers
150  double z = (zMin + zMax) * 0.5;
151  // create layer without surfaces
152  // manually create a proto layer
153  double eiz = (z != 0.) ? z - m_cfg.defaultThickness : 0.;
154  double eoz = (z != 0.) ? z + m_cfg.defaultThickness : 0.;
155  pl.extent.range(Acts::binZ).set(eiz, eoz);
156  pl.extent.range(Acts::binR).set(rMin, rMax);
157  pl.envelope[Acts::binR] = {0., 0.};
158  pl.envelope[Acts::binZ] = {0., 0.};
159  } else {
160  ACTS_VERBOSE(" Disc layer has " << layerSurfaces.size()
161  << " sensitive surfaces.");
162  // set the values of the proto layer in case dimensions are given by
163  // geometry
164  pl.envelope[Acts::binZ] = {std::abs(zMin - pl.min(Acts::binZ)),
165  std::abs(zMax - pl.max(Acts::binZ))};
166  pl.envelope[Acts::binR] = {std::abs(rMin - pl.min(Acts::binR)),
167  std::abs(rMax - pl.max(Acts::binR))};
168  pl.extent.range(Acts::binR).set(rMin, rMax);
169  }
170  } else {
171  throw std::logic_error(
172  std::string("Layer DetElement: ") + detElement.name() +
173  std::string(" has neither a shape nor tolerances for envelopes "
174  "added to its extension. Please check your detector "
175  "constructor!"));
176  }
177 
178  std::shared_ptr<Layer> endcapLayer = nullptr;
179 
180  // Check if DD4hep pre-defines the surface binning
181  bool hasSurfaceBinning =
182  getParamOr<bool>("surface_binning", detElement, true);
183  size_t nPhi = 1;
184  size_t nR = 1;
185  if (hasSurfaceBinning) {
186  if (params.contains("surface_binning_n_phi")) {
187  nPhi = static_cast<size_t>(params.get<int>("surface_binning_n_phi"));
188  }
189  if (params.contains("surface_binning_n_r")) {
190  nR = static_cast<size_t>(params.get<int>("surface_binning_n_r"));
191  }
192  hasSurfaceBinning = nR * nPhi > 1;
193  }
194 
195  // In case the layer is sensitive
196  if (detElement.volume().isSensitive()) {
197  // Create the sensitive surface
198  auto sensitiveSurf = createSensitiveSurface(detElement, true);
199  // Create the surfaceArray
200  std::unique_ptr<Acts::SurfaceArray> sArray =
201  std::make_unique<SurfaceArray>(sensitiveSurf);
202 
203  // create the share disc bounds
204  auto dBounds = std::make_shared<const RadialBounds>(pl.min(Acts::binR),
205  pl.max(Acts::binR));
206  double thickness = std::fabs(pl.max(Acts::binZ) - pl.min(Acts::binZ));
207  // Create the layer containing the sensitive surface
208  endcapLayer = DiscLayer::create(transform, dBounds, std::move(sArray),
209  thickness, nullptr, Acts::active);
210 
211  } else if (hasSurfaceBinning) {
212  // This method uses the binning from DD4hep/xml
213  endcapLayer = m_cfg.layerCreator->discLayer(
214  gctx, layerSurfaces, nR, nPhi, pl, transform, nullptr);
215  } else {
216  // This method determines the binning automatically
217  endcapLayer = m_cfg.layerCreator->discLayer(
218  gctx, layerSurfaces, m_cfg.bTypeR, m_cfg.bTypePhi, pl, transform,
219  nullptr);
220  }
221  // Add the ProtoMaterial if present
222  addDiscLayerProtoMaterial(detElement, *endcapLayer, logger());
223  // push back created layer
224  layers.push_back(endcapLayer);
225  }
226  }
227  return layers;
228 }
229 
231  const GeometryContext& gctx) const {
232  return endcapLayers(gctx, m_cfg.negativeLayers, "negative");
233 }
234 
236  const GeometryContext& gctx) const {
237  LayerVector layers;
238  if (m_cfg.centralLayers.empty()) {
239  ACTS_VERBOSE(" No layers handed over for central volume!");
240  } else {
241  ACTS_VERBOSE(
242  " Received layers for central volume -> creating "
243  "cylindrical layers");
244  // go through layers
245  for (auto& detElement : m_cfg.centralLayers) {
246  ACTS_VERBOSE("=> Translating layer from: " << detElement.name());
247  // prepare the layer surfaces
248  std::vector<std::shared_ptr<const Surface>> layerSurfaces;
249  // access the extension of the layer
250  // at this stage all layer detElements have extension (checked in
251  // ConvertDD4hepDetector)
252  auto& params = getParams(detElement);
253  // collect the sensitive detector elements possibly contained by the layer
254  resolveSensitive(detElement, layerSurfaces);
255  // access the global transformation matrix of the layer
256  auto transform =
257  convertTransform(&(detElement.nominal().worldTransformation()));
258  // get the shape of the layer
259  TGeoShape* geoShape =
260  detElement.placement().ptr()->GetVolume()->GetShape();
261  // create the proto layer
262  ProtoLayer pl(gctx, layerSurfaces);
263  if (logger().doPrint(Logging::VERBOSE)) {
264  std::stringstream ss;
265  pl.toStream(ss);
266  ACTS_VERBOSE("Extent from surfaces: " << ss.str());
267  std::vector<double> zvalues;
268  std::transform(layerSurfaces.begin(), layerSurfaces.end(),
269  std::back_inserter(zvalues), [&](const auto& surface) {
270  return surface->center(gctx)[eZ];
271  });
272  std::sort(zvalues.begin(), zvalues.end());
273  std::vector<std::string> locs;
274  std::transform(zvalues.begin(),
275  std::unique(zvalues.begin(), zvalues.end()),
276  std::back_inserter(locs),
277  [](const auto& v) { return std::to_string(v); });
278  ACTS_VERBOSE(
279  "-> unique z locations: " << boost::algorithm::join(locs, ", "));
280  }
281 
282  if (params.contains("envelope_r_min") &&
283  params.contains("envelope_r_max") &&
284  params.contains("envelope_z_min") &&
285  params.contains("envelope_z_max")) {
286  // set the values of the proto layer in case enevelopes are handed over
287  pl.envelope[Acts::binR] = {params.get<double>("envelope_r_min"),
288  params.get<double>("envelope_r_max")};
289  pl.envelope[Acts::binZ] = {params.get<double>("envelope_z_min"),
290  params.get<double>("envelope_z_max")};
291  } else if (geoShape != nullptr) {
292  TGeoTubeSeg* tube = dynamic_cast<TGeoTubeSeg*>(geoShape);
293  if (tube == nullptr) {
294  ACTS_ERROR(
295  " Cylinder layer has wrong shape - needs to be TGeoTubeSeg!");
296  }
297 
298  // extract the boundaries
299  double rMin = tube->GetRmin() * UnitConstants::cm;
300  double rMax = tube->GetRmax() * UnitConstants::cm;
301  double dz = tube->GetDz() * UnitConstants::cm;
302  // check if layer has surfaces
303  if (layerSurfaces.empty()) {
304  // in case no surfaces are handed over the layer thickness will be set
305  // to a default value to allow attaching material layers
306  double r = (rMin + rMax) * 0.5;
307  // create layer without surfaces
308  // manually create a proto layer
309  double eir = (r != 0.) ? r - m_cfg.defaultThickness : 0.;
310  double eor = (r != 0.) ? r + m_cfg.defaultThickness : 0.;
311  pl.extent.range(Acts::binR).set(eir, eor);
312  pl.extent.range(Acts::binZ).set(-dz, dz);
313  pl.envelope[Acts::binR] = {0., 0.};
314  pl.envelope[Acts::binZ] = {0., 0.};
315  } else {
316  // set the values of the proto layer in case dimensions are given by
317  // geometry
318  pl.envelope[Acts::binZ] = {std::abs(-dz - pl.min(Acts::binZ)),
319  std::abs(dz - pl.max(Acts::binZ))};
320  pl.envelope[Acts::binR] = {std::abs(rMin - pl.min(Acts::binR)),
321  std::abs(rMax - pl.max(Acts::binR))};
322  }
323  } else {
324  throw std::logic_error(
325  std::string("Layer DetElement: ") + detElement.name() +
326  std::string(" has neither a shape nor tolerances for envelopes "
327  "added to itÂ¥s extension. Please check your detector "
328  "constructor!"));
329  }
330 
331  double halfZ = (pl.min(Acts::binZ) - pl.max(Acts::binZ)) * 0.5;
332 
333  std::shared_ptr<Layer> centralLayer = nullptr;
334  // In case the layer is sensitive
335  if (detElement.volume().isSensitive()) {
336  // Create the sensitive surface
337  auto sensitiveSurf = createSensitiveSurface(detElement);
338  // Create the surfaceArray
339  std::unique_ptr<Acts::SurfaceArray> sArray =
340  std::make_unique<SurfaceArray>(sensitiveSurf);
341 
342  // create the layer
343  double layerR = (pl.min(Acts::binR) + pl.max(Acts::binR)) * 0.5;
344  double thickness = std::fabs(pl.max(Acts::binR) - pl.min(Acts::binR));
345  std::shared_ptr<const CylinderBounds> cBounds(
346  new CylinderBounds(layerR, halfZ));
347  // Create the layer containing the sensitive surface
348  centralLayer =
349  CylinderLayer::create(transform, cBounds, std::move(sArray),
350  thickness, nullptr, Acts::active);
351 
352  } else {
353  centralLayer = m_cfg.layerCreator->cylinderLayer(
354  gctx, layerSurfaces, m_cfg.bTypePhi, m_cfg.bTypeZ, pl, transform,
355  nullptr);
356  }
357  // Add the ProtoMaterial if present
358  addCylinderLayerProtoMaterial(detElement, *centralLayer, logger());
359  // push back created layer
360  layers.push_back(centralLayer);
361  }
362  }
363  return layers;
364 }
365 
367  const GeometryContext& gctx) const {
368  return endcapLayers(gctx, m_cfg.positiveLayers, "positive");
369 }
370 
372  const dd4hep::DetElement& detElement,
373  std::vector<std::shared_ptr<const Acts::Surface>>& surfaces) const {
374  const dd4hep::DetElement::Children& children = detElement.children();
375  if (!children.empty()) {
376  for (auto& child : children) {
377  dd4hep::DetElement childDetElement = child.second;
378  if (childDetElement.volume().isSensitive()) {
379  // create the surface
380  surfaces.push_back(createSensitiveSurface(childDetElement, false));
381  }
382  resolveSensitive(childDetElement, surfaces);
383  }
384  }
385 }
386 
387 std::shared_ptr<const Acts::Surface>
389  const dd4hep::DetElement& detElement, bool isDisc) const {
390  std::string detAxis =
391  getParamOr<std::string>("axis_definitions", detElement, "XYZ");
392  // Create the corresponding detector element !- memory leak --!
393  Acts::DD4hepDetectorElement* dd4hepDetElement =
394  new Acts::DD4hepDetectorElement(detElement, detAxis, UnitConstants::cm,
395  isDisc, nullptr);
396 
397  // return the surface
398  return dd4hepDetElement->surface().getSharedPtr();
399 }
400 
402  const TGeoMatrix* tGeoTrans) const {
403  // get the placement and orientation in respect to its mother
404  const Double_t* rotation = tGeoTrans->GetRotationMatrix();
405  const Double_t* translation = tGeoTrans->GetTranslation();
407  Acts::Vector3(rotation[0], rotation[3], rotation[6]),
408  Acts::Vector3(rotation[1], rotation[4], rotation[7]),
409  Acts::Vector3(rotation[2], rotation[5], rotation[8]),
410  Acts::Vector3(translation[0] * UnitConstants::cm,
411  translation[1] * UnitConstants::cm,
412  translation[2] * UnitConstants::cm));
413 }