Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TGeoDetector.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file TGeoDetector.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 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 
30 
31 #include <algorithm>
32 #include <array>
33 #include <cstdlib>
34 #include <fstream>
35 #include <functional>
36 #include <initializer_list>
37 #include <limits>
38 #include <list>
39 #include <optional>
40 
41 #include <boost/program_options.hpp>
42 #include <nlohmann/json.hpp>
43 
44 #include "TGeoManager.h"
45 
46 namespace ActsExamples {
47 using namespace Options;
48 
49 namespace {
50 
56 std::vector<Acts::TGeoLayerBuilder::Config> makeLayerBuilderConfigs(
58  std::vector<Acts::TGeoLayerBuilder::Config> detLayerConfigs;
59 
60  // iterate over all configured detector volumes
61  for (const auto& volume : config.volumes) {
62  Acts::TGeoLayerBuilder::Config layerBuilderConfig;
63  layerBuilderConfig.configurationName = volume.name;
64  layerBuilderConfig.unit = config.unitScalor;
65  layerBuilderConfig.elementFactory = config.elementFactory;
66 
67  // configure surface autobinning
68  std::vector<std::pair<double, double>> binTolerances(
69  static_cast<size_t>(Acts::binValues), {0., 0.});
70  binTolerances[Acts::binR] = {volume.binToleranceR.lower.value_or(0.),
71  volume.binToleranceR.upper.value_or(0.)};
72  binTolerances[Acts::binZ] = {volume.binToleranceZ.lower.value_or(0.),
73  volume.binToleranceZ.upper.value_or(0.)};
74  binTolerances[Acts::binPhi] = {volume.binTolerancePhi.lower.value_or(0.),
75  volume.binTolerancePhi.upper.value_or(0.)};
76 
77  layerBuilderConfig.autoSurfaceBinning = true;
78  layerBuilderConfig.surfaceBinMatcher =
79  Acts::SurfaceBinningMatcher(binTolerances);
80 
81  // loop over the negative/central/positive layer configurations
82  for (auto ncp : {
86  }) {
87  if (!volume.layers.at(ncp)) {
88  continue;
89  }
90 
92  lConfig.volumeName = volume.subVolumeName.at(ncp);
93  lConfig.sensorNames = volume.sensitiveNames.at(ncp);
94  lConfig.localAxes = volume.sensitiveAxes.at(ncp);
95  lConfig.envelope = {config.layerEnvelopeR, config.layerEnvelopeR};
96 
97  auto rR = volume.rRange.at(ncp);
98  auto rMin = rR.lower.value_or(0.);
99  auto rMax = rR.upper.value_or(std::numeric_limits<double>::max());
100  auto zR = volume.zRange.at(ncp);
101  auto zMin = zR.lower.value_or(-std::numeric_limits<double>::max());
102  auto zMax = zR.upper.value_or(std::numeric_limits<double>::max());
103  lConfig.parseRanges = {
104  {Acts::binR, {rMin, rMax}},
105  {Acts::binZ, {zMin, zMax}},
106  };
107 
108  // Fill the layer splitting parameters in r/z
109  auto str = volume.splitTolR.at(ncp);
110  auto stz = volume.splitTolZ.at(ncp);
111  if (0 < str) {
112  lConfig.splitConfigs.emplace_back(Acts::binR, str);
113  }
114  if (0 < stz) {
115  lConfig.splitConfigs.emplace_back(Acts::binZ, stz);
116  }
117  lConfig.binning0 = volume.binning0.at(ncp);
118  lConfig.binning1 = volume.binning1.at(ncp);
119 
120  layerBuilderConfig.layerConfigurations[ncp].push_back(lConfig);
121  }
122 
123  // Perform splitting of cylinders and discs
124  if (volume.cylinderDiscSplit) {
126  cdsConfig.cylinderPhiSegments = volume.cylinderNPhiSegments;
127  cdsConfig.cylinderLongitudinalSegments = volume.cylinderNZSegments;
128  cdsConfig.discPhiSegments = volume.discNPhiSegments;
129  cdsConfig.discRadialSegments = volume.discNRSegments;
130  layerBuilderConfig.detectorElementSplitter =
131  std::make_shared<const Acts::TGeoCylinderDiscSplitter>(
132  cdsConfig,
133  logger.clone("TGeoCylinderDiscSplitter", config.layerLogLevel));
134  } else if (volume.itkModuleSplit) {
136  itkConfig.barrelMap = volume.barrelMap;
137  itkConfig.discMap = volume.discMap;
138  itkConfig.splitPatterns = volume.splitPatterns;
139  layerBuilderConfig.detectorElementSplitter =
140  std::make_shared<ActsExamples::TGeoITkModuleSplitter>(
141  itkConfig,
142  logger.clone("TGeoITkModuleSplitter", config.layerLogLevel));
143  }
144 
145  detLayerConfigs.push_back(layerBuilderConfig);
146  }
147 
148  return detLayerConfigs;
149 }
150 
152 // from a TGeo object.
160 std::shared_ptr<const Acts::TrackingGeometry> buildTGeoDetector(
161  const TGeoDetector::Config& config, const Acts::GeometryContext& context,
162  std::vector<std::shared_ptr<const Acts::TGeoDetectorElement>>&
163  detElementStore,
164  std::shared_ptr<const Acts::IMaterialDecorator> mdecorator,
165  const Acts::Logger& logger) {
166  // configure surface array creator
168  auto surfaceArrayCreator = std::make_shared<const Acts::SurfaceArrayCreator>(
169  sacConfig, logger.clone("SurfaceArrayCreator", config.surfaceLogLevel));
170  // configure the proto layer helper
172  auto protoLayerHelper = std::make_shared<const Acts::ProtoLayerHelper>(
173  plhConfig, logger.clone("ProtoLayerHelper", config.layerLogLevel));
174  // configure the layer creator that uses the surface array creator
176  lcConfig.surfaceArrayCreator = surfaceArrayCreator;
177  auto layerCreator = std::make_shared<const Acts::LayerCreator>(
178  lcConfig, logger.clone("LayerCreator", config.layerLogLevel));
179  // configure the layer array creator
181  auto layerArrayCreator = std::make_shared<const Acts::LayerArrayCreator>(
182  lacConfig, logger.clone("LayerArrayCreator", config.layerLogLevel));
183  // tracking volume array creator
185  auto tVolumeArrayCreator =
186  std::make_shared<const Acts::TrackingVolumeArrayCreator>(
187  tvacConfig,
188  logger.clone("TrackingVolumeArrayCreator", config.volumeLogLevel));
189  // configure the cylinder volume helper
191  cvhConfig.layerArrayCreator = layerArrayCreator;
192  cvhConfig.trackingVolumeArrayCreator = tVolumeArrayCreator;
193  auto cylinderVolumeHelper =
194  std::make_shared<const Acts::CylinderVolumeHelper>(
195  cvhConfig,
196  logger.clone("CylinderVolumeHelper", config.volumeLogLevel));
197 
198  //-------------------------------------------------------------------------------------
199  // list the volume builders
200  std::list<std::shared_ptr<const Acts::ITrackingVolumeBuilder>> volumeBuilders;
201 
202  // Create a beam pipe if configured to do so
203  if (config.buildBeamPipe) {
206  bplConfig.layerIdentification = "BeamPipe";
207  bplConfig.centralLayerRadii = {config.beamPipeRadius};
208  bplConfig.centralLayerHalflengthZ = {config.beamPipeHalflengthZ};
209  bplConfig.centralLayerThickness = {config.beamPipeLayerThickness};
210  auto beamPipeBuilder = std::make_shared<const Acts::PassiveLayerBuilder>(
211  bplConfig, logger.clone("BeamPipeLayerBuilder", config.layerLogLevel));
212  // create the volume for the beam pipe
214  bpvConfig.trackingVolumeHelper = cylinderVolumeHelper;
215  bpvConfig.volumeName = "BeamPipe";
216  bpvConfig.layerBuilder = beamPipeBuilder;
217  bpvConfig.layerEnvelopeR = {config.beamPipeEnvelopeR,
218  config.beamPipeEnvelopeR};
219  bpvConfig.buildToRadiusZero = true;
220  auto beamPipeVolumeBuilder =
221  std::make_shared<const Acts::CylinderVolumeBuilder>(
222  bpvConfig,
223  logger.clone("BeamPipeVolumeBuilder", config.volumeLogLevel));
224  // add to the list of builders
225  volumeBuilders.push_back(beamPipeVolumeBuilder);
226  }
227 
228  // Import the file from
229  TGeoManager::Import(config.fileName.c_str());
230 
231  auto layerBuilderConfigs = makeLayerBuilderConfigs(config, logger);
232 
233  // Remember the layer builders to collect the detector elements
234  std::vector<std::shared_ptr<const Acts::TGeoLayerBuilder>> tgLayerBuilders;
235 
236  for (auto& lbc : layerBuilderConfigs) {
237  std::shared_ptr<const Acts::LayerCreator> layerCreatorLB = nullptr;
238 
239  if (lbc.autoSurfaceBinning) {
240  // Configure surface array creator (optionally) per layer builder
241  // (in order to configure them to work appropriately)
243  sacConfigLB.surfaceMatcher = lbc.surfaceBinMatcher;
244  auto surfaceArrayCreatorLB =
245  std::make_shared<const Acts::SurfaceArrayCreator>(
246  sacConfigLB,
247  logger.clone(lbc.configurationName + "SurfaceArrayCreator",
248  config.surfaceLogLevel));
249  // configure the layer creator that uses the surface array creator
250  Acts::LayerCreator::Config lcConfigLB;
251  lcConfigLB.surfaceArrayCreator = surfaceArrayCreatorLB;
252  layerCreatorLB = std::make_shared<const Acts::LayerCreator>(
253  lcConfigLB, logger.clone(lbc.configurationName + "LayerCreator",
254  config.layerLogLevel));
255  }
256 
257  // Configure the proto layer helper
258  Acts::ProtoLayerHelper::Config plhConfigLB;
259  auto protoLayerHelperLB = std::make_shared<const Acts::ProtoLayerHelper>(
260  plhConfigLB, logger.clone(lbc.configurationName + "ProtoLayerHelper",
261  config.layerLogLevel));
262 
263  //-------------------------------------------------------------------------------------
264  lbc.layerCreator =
265  (layerCreatorLB != nullptr) ? layerCreatorLB : layerCreator;
266  lbc.protoLayerHelper =
267  (protoLayerHelperLB != nullptr) ? protoLayerHelperLB : protoLayerHelper;
268 
269  auto layerBuilder = std::make_shared<const Acts::TGeoLayerBuilder>(
270  lbc, logger.clone(lbc.configurationName + "LayerBuilder",
271  config.layerLogLevel));
272  // remember the layer builder
273  tgLayerBuilders.push_back(layerBuilder);
274 
275  // build the pixel volume
277  volumeConfig.trackingVolumeHelper = cylinderVolumeHelper;
278  volumeConfig.volumeName = lbc.configurationName;
279  volumeConfig.buildToRadiusZero = volumeBuilders.empty();
280  volumeConfig.layerEnvelopeR = {config.layerEnvelopeR,
281  config.layerEnvelopeR};
282  auto ringLayoutConfiguration =
283  [&](const std::vector<Acts::TGeoLayerBuilder::LayerConfig>& lConfigs)
284  -> void {
285  for (const auto& lcfg : lConfigs) {
286  for (const auto& scfg : lcfg.splitConfigs) {
287  if (scfg.first == Acts::binR and scfg.second > 0.) {
288  volumeConfig.ringTolerance =
289  std::max(volumeConfig.ringTolerance, scfg.second);
290  volumeConfig.checkRingLayout = true;
291  }
292  }
293  }
294  };
295  ringLayoutConfiguration(lbc.layerConfigurations[0]);
296  ringLayoutConfiguration(lbc.layerConfigurations[2]);
297  volumeConfig.layerBuilder = layerBuilder;
298  volumeConfig.volumeSignature = 0;
299  auto volumeBuilder = std::make_shared<const Acts::CylinderVolumeBuilder>(
300  volumeConfig, logger.clone(lbc.configurationName + "VolumeBuilder",
301  config.volumeLogLevel));
302  // add to the list of builders
303  volumeBuilders.push_back(volumeBuilder);
304  }
305 
306  //-------------------------------------------------------------------------------------
307  // create the tracking geometry
309  // Add the builders
310  tgConfig.materialDecorator = std::move(mdecorator);
311  tgConfig.geometryIdentifierHook = config.geometryIdentifierHook;
312 
313  for (auto& vb : volumeBuilders) {
314  tgConfig.trackingVolumeBuilders.push_back(
315  [=](const auto& gcontext, const auto& inner, const auto&) {
316  return vb->trackingVolume(gcontext, inner);
317  });
318  }
319  // Add the helper
320  tgConfig.trackingVolumeHelper = cylinderVolumeHelper;
321  auto cylinderGeometryBuilder =
322  std::make_shared<const Acts::TrackingGeometryBuilder>(
323  tgConfig,
324  logger.clone("TrackerGeometryBuilder", config.volumeLogLevel));
325  // get the geometry
326  auto trackingGeometry = cylinderGeometryBuilder->trackingGeometry(context);
327  // collect the detector element store
328  for (auto& lBuilder : tgLayerBuilders) {
329  auto detElements = lBuilder->detectorElements();
330  detElementStore.insert(detElementStore.begin(), detElements.begin(),
331  detElements.end());
332  }
333 
335  return trackingGeometry;
336 }
337 
338 } // namespace
339 
342  Config& config) {
343  if (path.empty()) {
344  return;
345  }
346  nlohmann::json djson;
347  std::ifstream infile(path, std::ifstream::in | std::ifstream::binary);
348  infile >> djson;
349 
350  config.unitScalor = djson["geo-tgeo-unit-scalor"];
351 
352  config.buildBeamPipe = djson["geo-tgeo-build-beampipe"];
353  if (config.buildBeamPipe) {
354  const auto beamPipeParameters =
355  djson["geo-tgeo-beampipe-parameters"].get<std::array<double, 3>>();
356  config.beamPipeRadius = beamPipeParameters[0];
357  config.beamPipeHalflengthZ = beamPipeParameters[1];
358  config.beamPipeLayerThickness = beamPipeParameters[2];
359  }
360 
361  // Fill nested volume configs
362  for (const auto& volume : djson["Volumes"]) {
363  auto& vol = config.volumes.emplace_back();
364  vol = volume;
365  }
366 }
367 
369  const Config& cfg,
370  std::shared_ptr<const Acts::IMaterialDecorator> mdecorator)
371  -> std::pair<TrackingGeometryPtr, ContextDecorators> {
372  Acts::GeometryContext tGeoContext;
373  auto logger = Acts::getDefaultLogger("TGeoDetector", Acts::Logging::INFO);
374  TrackingGeometryPtr tgeoTrackingGeometry = buildTGeoDetector(
375  cfg, tGeoContext, detectorStore, std::move(mdecorator), *logger);
376 
377  ContextDecorators tgeoContextDecorators = {};
378  // Return the pair of geometry and empty decorators
379  return std::make_pair<TrackingGeometryPtr, ContextDecorators>(
380  std::move(tgeoTrackingGeometry), std::move(tgeoContextDecorators));
381 }
382 
384  readTGeoLayerBuilderConfigsFile(jsonFile, *this);
385 }
386 
387 } // namespace ActsExamples