ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TGeoLayerBuilder.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file TGeoLayerBuilder.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 #include <stdio.h>
13 #include "TGeoManager.h"
14 #include "TGeoMatrix.h"
15 
18  std::unique_ptr<const Logger> logger)
19  : m_cfg(), m_logger(std::move(logger)) {
20  setConfiguration(config);
21 }
22 
24 
27  m_cfg = config;
28 }
29 
31  std::unique_ptr<const Logger> newLogger) {
32  m_logger = std::move(newLogger);
33 }
34 
36  const GeometryContext& gctx) const {
37  // @todo Remove this hack once the m_elementStore mess is sorted out
38  auto mutableThis = const_cast<TGeoLayerBuilder*>(this);
39  LayerVector nVector;
40  mutableThis->buildLayers(gctx, nVector, -1);
41  return nVector;
42 }
43 
45  const GeometryContext& gctx) const {
46  // @todo Remove this hack once the m_elementStore mess is sorted out
47  auto mutableThis = const_cast<TGeoLayerBuilder*>(this);
48  LayerVector cVector;
49  mutableThis->buildLayers(gctx, cVector, 0);
50  return cVector;
51 }
52 
54  const GeometryContext& gctx) const {
55  // @todo Remove this hack once the m_elementStore mess is sorted out
56  auto mutableThis = const_cast<TGeoLayerBuilder*>(this);
57  LayerVector pVector;
58  mutableThis->buildLayers(gctx, pVector, 1);
59  return pVector;
60 }
61 
63  LayerVector& layers, int type) {
64  // Bail out if you have no gGeoManager
65  if (gGeoManager == nullptr) {
66  ACTS_WARNING("No gGeoManager found - bailing out.");
67  return;
68  }
69 
70  // Prepare which ones to build
71  std::vector<LayerConfig> layerConfigs = m_cfg.layerConfigurations[type + 1];
72  std::string layerType = m_layerTypes[type + 1];
73 
74  // Appropriate screen output
75  std::string addonOutput = m_cfg.layerSplitToleranceR[type + 1] > 0.
76  ? std::string(", splitting in r")
77  : std::string("");
78  addonOutput += m_cfg.layerSplitToleranceZ[type + 1] > 0.
79  ? std::string(", splitting in z")
80  : std::string("");
81  addonOutput += std::string(".");
82 
83  // Screen output of the configuration
84  ACTS_DEBUG(layerType << " layers : found " << layerConfigs.size()
85  << " configuration(s)" + addonOutput);
86  for (auto layerCfg : layerConfigs) {
87  // Prepare the layer surfaces
88  using LayerSurfaceVector = std::vector<std::shared_ptr<const Surface>>;
89  LayerSurfaceVector layerSurfaces;
90 
91  ACTS_DEBUG("- layer configuration found for layer "
92  << layerCfg.layerName << " with sensor " << layerCfg.sensorName);
93  ACTS_DEBUG("- layers radially bound to rmin/rmax = "
94  << layerCfg.parseRangeR.first << "/"
95  << layerCfg.parseRangeR.second);
96  // Step down from the top volume each time to collect the logical tree
97  TGeoVolume* tvolume = gGeoManager->GetTopVolume();
98  if (tvolume != nullptr) {
99  // Recursively step down
100  resolveSensitive(gctx, layerSurfaces, tvolume, nullptr, TGeoIdentity(),
101  layerCfg, type);
102  // screen output
103  ACTS_DEBUG(
104  "- number of senstive sensors found : " << layerSurfaces.size());
105 
106  // Helper function to fill the layer
107  auto fillLayer = [&](const LayerSurfaceVector lSurfaces,
108  const LayerConfig& lCfg) -> void {
109  // Create the layer - either way as cylinder or disk
110  if (type == 0) {
111  ProtoLayer pl(gctx, lSurfaces);
112  pl.envR = {lCfg.envelope.first, lCfg.envelope.second};
113  pl.envZ = {lCfg.envelope.second, lCfg.envelope.second};
114  layers.push_back(m_cfg.layerCreator->cylinderLayer(
115  gctx, lSurfaces, lCfg.binsLoc0, lCfg.binsLoc1, pl));
116  } else {
117  ProtoLayer pl(gctx, lSurfaces);
118  pl.envR = {lCfg.envelope.first, lCfg.envelope.second};
119  pl.envZ = {lCfg.envelope.second, lCfg.envelope.second};
120  layers.push_back(m_cfg.layerCreator->discLayer(
121  gctx, lSurfaces, lCfg.binsLoc0, lCfg.binsLoc1, pl));
122  }
123  };
124 
125  // There is no split to be attempted
126  if (layerCfg.splitParametersR.empty() and
127  layerCfg.splitParametersZ.empty()) {
128  // No splitting to be done, fill and return
129  fillLayer(layerSurfaces, layerCfg);
130  return;
131  }
132 
133  std::vector<LayerSurfaceVector> splitLayerSurfaces = {layerSurfaces};
134 
135  // Helper method : perform the actual split
136  auto splitSurfaces =
137  [&](std::string splitValue, BinningValue bValue,
138  const std::vector<LayerSurfaceVector>& preSplitSurfaces,
139  double splitTolerance,
140  std::pair<double, double> splitRange = {0., 0.},
141  std::vector<double> splitParameters = {})
142  -> std::vector<LayerSurfaceVector> {
143  ACTS_DEBUG("- split attempt in " << splitValue);
144  ACTS_DEBUG("- split layers seperated by more than " << splitTolerance);
145  // Re-evaluate
146  bool reevaluate = splitParameters.empty();
147  if (reevaluate) {
148  ACTS_DEBUG("- split parameters to be re-evaluated");
149  }
150 
151  // The vector of surfaces after splitting
152  std::vector<LayerSurfaceVector> postSplitSurfaces;
153  // Go through and split them accordingly
154  for (const auto& surfaceSet : preSplitSurfaces) {
155  ACTS_DEBUG("- split surface set with " << surfaceSet.size()
156  << " surfaces.");
157  // The Split parameters are empty, parse again
158  if (reevaluate) {
159  // Loop over sub set for new splitting range and parameters
160  for (const auto& surface : surfaceSet) {
161  // Get the surface parameter
162  double surfacePar = surface->binningPositionValue(gctx, bValue);
163  registerSplit(splitParameters, surfacePar, splitTolerance,
164  splitRange);
165  }
166  }
167  // Output the split range
168  ACTS_DEBUG("- split range is = " << splitRange.first << ", "
169  << splitRange.second);
170  ACTS_DEBUG("- number of proposed splits is "
171  << splitParameters.size());
172  // Allocate expected sub vector
173  std::vector<LayerSurfaceVector> setSplitSurfaces{
174  splitParameters.size(), LayerSurfaceVector{}};
175  // Filling loop (2nd loop if split in case of re-evaluation)
176  for (const auto& surface : surfaceSet) {
177  // Get the surface parameter
178  double surfacePar = surface->binningPositionValue(gctx, bValue);
179  unsigned isplit = 0;
180  for (const auto& splitPar : splitParameters) {
181  if (std::abs(splitPar - surfacePar) < splitTolerance) {
182  setSplitSurfaces[isplit].push_back(surface);
183  }
184  ++isplit;
185  }
186  }
187  // Insert the split set into the post split set
188  postSplitSurfaces.insert(postSplitSurfaces.end(),
189  setSplitSurfaces.begin(),
190  setSplitSurfaces.end());
191  // reset the split parameters
192  if (reevaluate) {
193  splitParameters.clear();
194  }
195  }
196  unsigned int iss = 0;
197  ACTS_VERBOSE(" - splitting yielded " << postSplitSurfaces.size()
198  << " surface sets:");
199  for (const auto& sset : postSplitSurfaces) {
200  ACTS_VERBOSE(" - set " << iss++ << " has " << sset.size()
201  << " surfaces.");
202  }
203 
204  // Return them to the callers
205  return postSplitSurfaces;
206  };
207 
208  // Split in R first if split tolerance is set
209  if (m_cfg.layerSplitToleranceR[type + 1] > 0.) {
210  // Split the surfaces in R
211  splitLayerSurfaces = splitSurfaces(
212  "r", binR, splitLayerSurfaces, m_cfg.layerSplitToleranceR[type + 1],
213  layerCfg.splitRangeR, layerCfg.splitParametersR);
214  // This invalidates the Z parameters and range
215  layerCfg.splitParametersZ.clear();
216  layerCfg.splitRangeZ = {std::numeric_limits<double>::max(),
218  }
219 
220  // Split in Z then if configured to do so
221  if (m_cfg.layerSplitToleranceZ[type + 1] > 0.) {
222  // Split the surfaces in Z
223  splitLayerSurfaces = splitSurfaces(
224  "z", binZ, splitLayerSurfaces, m_cfg.layerSplitToleranceZ[type + 1],
225  layerCfg.splitRangeZ, layerCfg.splitParametersZ);
226  }
227 
228  // Now go through and fill, @todo adapt layer configurations
229  unsigned int il = 0;
230  for (const auto& slSurfaces : splitLayerSurfaces) {
231  ACTS_VERBOSE(" - layer " << il++ << " has " << slSurfaces.size()
232  << " surfaces.");
233  fillLayer(slSurfaces, layerCfg);
234  }
235  }
236  }
237 }
238 
240  const GeometryContext& gctx,
241  std::vector<std::shared_ptr<const Acts::Surface>>& layerSurfaces,
242  TGeoVolume* tgVolume, TGeoNode* tgNode, const TGeoMatrix& tgTransform,
243  LayerConfig& layerConfig, int type, bool correctBranch,
244  const std::string& offset) {
245  if (tgVolume != nullptr) {
246  std::string volumeName = tgVolume->GetName();
248  ACTS_VERBOSE(offset << "[o] Volume : " << volumeName
249  << " - checking for volume name "
250  << layerConfig.layerName);
251 
252  // Once in the current branch stepping down means staying inside the branch
253  bool correctVolume = correctBranch;
254  if (!correctVolume &&
255  (volumeName.find(layerConfig.layerName) != std::string::npos ||
256  match(layerConfig.layerName.c_str(), volumeName.c_str()))) {
257  correctVolume = true;
258  ACTS_VERBOSE(offset << " triggered current branch!");
259  }
260  // Loop over the daughters and collect them
261  auto daugthers = tgVolume->GetNodes();
262  // Screen output
263  ACTS_VERBOSE(offset << "has " << tgVolume->GetNdaughters()
264  << " daughters.");
265  // A daughter iterator
266  TIter iObj(daugthers);
267  // While loop over the objects for the recursive parsing
268  while (TObject* obj = iObj()) {
269  // dynamic_cast to a node
270  TGeoNode* node = dynamic_cast<TGeoNode*>(obj);
271  if (node != nullptr) {
272  resolveSensitive(gctx, layerSurfaces, nullptr, node, tgTransform,
273  layerConfig, type, correctVolume, offset + " ");
274  }
275  }
276  } else {
277  ACTS_VERBOSE("No volume present.");
278  }
279 
281  if (tgNode != nullptr) {
282  // Get the matrix of the current node for positioning
283  const TGeoMatrix* tgMatrix = tgNode->GetMatrix();
284 
285  // Build the matrix
286  TGeoHMatrix parseTransform =
287  TGeoCombiTrans(tgTransform) * TGeoCombiTrans(*tgMatrix);
288 
289  // The translation of the node for parsing
290  const Double_t* translation = parseTransform.GetTranslation();
291 
292  double x = m_cfg.unit * translation[0];
293  double y = m_cfg.unit * translation[1];
294  double z = m_cfg.unit * translation[2];
295  double r = std::sqrt(x * x + y * y);
296 
297  // The name of the nodefor cross checking
298  std::string tNodeName = tgNode->GetName();
299  ACTS_VERBOSE(offset << "[>] Node : " << tNodeName
300  << " - checking for sensor name "
301  << layerConfig.sensorName);
302  // Find out the branch hit, ingle layer depth supported by sensor==layer
303  bool branchHit =
304  correctBranch || (layerConfig.sensorName == layerConfig.layerName);
305  if (branchHit &&
306  (tNodeName.find(layerConfig.sensorName) != std::string::npos ||
307  match(layerConfig.sensorName.c_str(), tNodeName.c_str()))) {
308  ACTS_VERBOSE(offset << "Sensor name '" << layerConfig.sensorName
309  << "' found in branch '" << layerConfig.layerName
310  << "'.");
311 
312  // Create the detector element
313  // - check on the type for the side
314  // - check for the parsing volume
315  bool insideParseRange = r >= layerConfig.parseRangeR.first and
316  r <= layerConfig.parseRangeR.second;
317 
318  if (insideParseRange and ((type == 0) || type * z > 0.)) {
319  // Senstive volume found, collect it
320  ACTS_VERBOSE(offset << "[>>] accepted.");
321  // Create the element
322  auto identifier =
323  m_cfg.identifierProvider != nullptr
324  ? m_cfg.identifierProvider->identify(gctx, *tgNode)
325  : Identifier();
326  auto tgElement = std::make_shared<const Acts::TGeoDetectorElement>(
327  identifier, tgNode, &tgTransform, layerConfig.localAxes,
328  m_cfg.unit);
329  // Record the element @todo solve with provided cache
330  m_elementStore.push_back(tgElement);
331  // Register the shared pointer to the surface for layer building
332  layerSurfaces.push_back(tgElement->surface().getSharedPtr());
333 
334  // Record split range for eventual splitting
335  double surfaceR = tgElement->surface().binningPositionValue(gctx, binR);
336  double surfaceZ = tgElement->surface().binningPositionValue(gctx, binZ);
337 
338  // Split in R if configured to do so
339  if (m_cfg.layerSplitToleranceR[type + 1] > 0.) {
340  registerSplit(layerConfig.splitParametersR, surfaceR,
341  m_cfg.layerSplitToleranceR[type + 1],
342  layerConfig.splitRangeR);
343  }
344  // Split in Z if configured to do so
345  if (m_cfg.layerSplitToleranceZ[type + 1] > 0.) {
346  registerSplit(layerConfig.splitParametersZ, surfaceZ,
347  m_cfg.layerSplitToleranceZ[type + 1],
348  layerConfig.splitRangeZ);
349  }
350  } else if (type * z < 0) {
351  ACTS_VERBOSE("[xx] cancelled by side check.");
352  } else if (not insideParseRange) {
353  ACTS_VERBOSE("[xx] cancelled by parse range on side " << type);
354  ACTS_VERBOSE(" r = " << r << " in ("
355  << layerConfig.parseRangeR.first << ", "
356  << layerConfig.parseRangeR.second << "] ?");
357  }
358  } else {
359  // This is not yet the senstive one
360  ACTS_VERBOSE(offset << "[<<] not accepted, stepping down.");
361  // Build the matrix
362  TGeoHMatrix nTransform =
363  TGeoCombiTrans(tgTransform) * TGeoCombiTrans(*tgMatrix);
364  std::string suffix = "_transform";
365  nTransform.SetName((tNodeName + suffix).c_str());
366  // If it's not accepted, get the associated volume
367  TGeoVolume* nodeVolume = tgNode->GetVolume();
368  // Now step down one further
369  resolveSensitive(gctx, layerSurfaces, nodeVolume, nullptr, nTransform,
370  layerConfig, type, correctBranch, offset + " ");
371  }
372  } else {
373  ACTS_VERBOSE("No node present.");
374  }
375 }