Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MockupSectorBuilder.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file MockupSectorBuilder.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2022-2023 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 
34 
35 #include <algorithm>
36 #include <array>
37 #include <cmath>
38 #include <cstddef>
39 #include <limits>
40 #include <stdexcept>
41 #include <string>
42 #include <tuple>
43 #include <utility>
44 #include <vector>
45 
48  mCfg = config;
50  g4World = geo_gdml.Construct();
51 }
52 
53 std::shared_ptr<Acts::Experimental::DetectorVolume>
56  if (g4World == nullptr) {
57  throw std::invalid_argument("MockupSector: No g4World initialized");
58  return nullptr;
59  }
60 
62 
63  // Geant4Detector Config creator with the g4world from the gdml file
64  auto g4WorldConfig = ActsExamples::Geant4::Geant4Detector::Config();
65  g4WorldConfig.name = "Chamber";
66  g4WorldConfig.g4World = g4World;
67 
68  // Get the sensitive and passive surfaces and pass to the g4World Config
69  auto g4Sensitive =
70  std::make_shared<Acts::Geant4PhysicalVolumeSelectors::NameSelector>(
71  chamberConfig.SensitiveNames);
72  auto g4Passive =
73  std::make_shared<Acts::Geant4PhysicalVolumeSelectors::NameSelector>(
74  chamberConfig.PassiveNames);
75 
76  auto g4SurfaceOptions = Acts::Geant4DetectorSurfaceFactory::Options();
77  g4SurfaceOptions.sensitiveSurfaceSelector = g4Sensitive;
78  g4SurfaceOptions.passiveSurfaceSelector = g4Passive;
79  g4WorldConfig.g4SurfaceOptions = g4SurfaceOptions;
80 
81  auto g4detector = ActsExamples::Geant4::Geant4Detector();
82 
83  auto [detector, surfaces, detectorElements] =
84  g4detector.constructDetector(g4WorldConfig, Acts::getDummyLogger());
85 
86  // The vector that holds the converted sensitive surfaces of the chamber
87  std::vector<std::shared_ptr<Acts::Surface>> strawSurfaces = {};
88 
89  std::array<std::pair<float, float>, 3> min_max;
90  std::fill(min_max.begin(), min_max.end(),
91  std::make_pair<float, float>(std::numeric_limits<float>::max(),
92  -std::numeric_limits<float>::max()));
93 
94  // Convert the physical volumes of the detector elements to straw surfaces
95  for (auto& detectorElement : detectorElements) {
96  auto context = Acts::GeometryContext();
98 
99  g4conv.forcedType = Acts::Surface::SurfaceType::Straw;
100  auto g4ConvSurf = g4conv.Geant4PhysicalVolumeConverter::surface(
101  detectorElement->g4PhysicalVolume(),
102  detectorElement->transform(context));
103 
104  strawSurfaces.push_back(g4ConvSurf);
105 
106  min_max[0].first =
107  std::min(min_max[0].first, (float)g4ConvSurf->center(context).x());
108  min_max[0].second =
109  std::max(min_max[0].second, (float)g4ConvSurf->center(context).x());
110 
111  min_max[1].first =
112  std::min(min_max[1].first, (float)g4ConvSurf->center(context).y());
113  min_max[1].second =
114  std::max(min_max[1].second, (float)g4ConvSurf->center(context).y());
115 
116  min_max[2].first =
117  std::min(min_max[2].first, (float)g4ConvSurf->center(context).z());
118  min_max[2].second =
119  std::max(min_max[2].second, (float)g4ConvSurf->center(context).z());
120  }
121 
122  // Create the bounds of the detector volumes
123  float radius = strawSurfaces.front()->bounds().values()[0];
124 
125  Acts::Vector3 minValues = {min_max[0].first, min_max[1].first,
126  min_max[2].first};
127  Acts::Vector3 maxValues = {min_max[0].second, min_max[1].second,
128  min_max[2].second};
129 
131  strawSurfaces.front()->bounds().values()[1] + mCfg.toleranceOverlap;
133  0.5 * ((maxValues.y() + radius) - (minValues.y() - radius)) +
134  mCfg.toleranceOverlap;
136  0.5 * ((maxValues.z() + radius) - (minValues.z() - radius)) +
137  mCfg.toleranceOverlap;
138 
139  auto detectorVolumeBounds =
140  std::make_shared<Acts::CuboidVolumeBounds>(hx, hy, hz);
141 
142  Acts::Vector3 chamber_position = {(maxValues.x() + minValues.x()) / 2,
143  (maxValues.y() + minValues.y()) / 2,
144  (maxValues.z() + minValues.z()) / 2};
145 
146  // create the detector volume for the chamber
149  chamberConfig.name,
150  Acts::Transform3(Acts::Translation3(chamber_position)),
151  std::move(detectorVolumeBounds), strawSurfaces,
152  std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>>{},
155 
156  return detectorVolume;
157 }
158 
159 std::shared_ptr<Acts::Experimental::DetectorVolume>
161  std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>>
162  detVolumes) {
163  if (mCfg.NumberOfSectors > maxNumberOfSectors) {
164  throw std::invalid_argument("MockupSector:Number of max sectors exceeded");
165  return nullptr;
166  }
167 
169 
170  // sort the detector volumes by their radial distance (from
171  // innermost---->outermost)
172  std::sort(detVolumes.begin(), detVolumes.end(),
173  [](const auto& detVol1, const auto& detVol2) {
174  return detVol1->center().y() < detVol2->center().y();
175  });
176 
177  auto xA = detVolumes.back()->center().x() +
178  detVolumes.back()->volumeBounds().values()[0];
179  auto yA = detVolumes.back()->center().y() -
180  detVolumes.back()->volumeBounds().values()[1];
181  auto zA = detVolumes.back()->center().z();
182 
183  auto xB = detVolumes.back()->center().x() -
184  detVolumes.back()->volumeBounds().values()[0];
185  auto yB = detVolumes.back()->center().y() -
186  detVolumes.back()->volumeBounds().values()[1];
187  auto zB = detVolumes.back()->center().z();
188 
189  Acts::Vector3 pointA = {xA, yA, zA};
190  Acts::Vector3 pointB = {xB, yB, zB};
191 
192  // calculate the phi angles of the vectors
193  auto phiA = Acts::VectorHelpers::phi(pointA);
194  auto phiB = Acts::VectorHelpers::phi(pointB);
195  auto sectorAngle = M_PI;
196 
197  auto halfPhi = M_PI / mCfg.NumberOfSectors;
198 
199  if (mCfg.NumberOfSectors == 1) {
200  halfPhi = (phiB - phiA) / 2;
201  sectorAngle = halfPhi;
202  }
203 
204  const int detVolumesSize = detVolumes.size();
205 
206  std::vector<float> rmins(detVolumesSize);
207  std::vector<float> rmaxs(detVolumesSize);
208  std::vector<float> halfZ(detVolumesSize);
209  std::vector<std::shared_ptr<Acts::CylinderVolumeBounds>>
210  cylinderVolumesBounds(detVolumesSize);
211 
212  for (int i = 0; i < detVolumesSize; i++) {
213  const auto& detVol = detVolumes[i];
214  rmins[i] = detVol->center().y() - detVol->volumeBounds().values()[1] -
215  mCfg.toleranceOverlap;
216  rmaxs[i] = std::sqrt(std::pow(detVol->volumeBounds().values()[0], 2) +
217  std::pow(detVol->center().y() +
218  detVol->volumeBounds().values()[1],
219  2)) +
220  mCfg.toleranceOverlap;
221  halfZ[i] = detVol->volumeBounds().values()[2];
222 
223  cylinderVolumesBounds[i] = std::make_shared<Acts::CylinderVolumeBounds>(
224  rmins[i], rmaxs[i], halfZ[i], sectorAngle);
225  }
226 
227  const Acts::Vector3 pos = {0., 0., 0.};
228 
229  // the transform of the cylinder volume
230  Acts::AngleAxis3 rotZ(M_PI / 2, Acts::Vector3(0., 0., 1));
232  transform *= rotZ;
233 
234  // create a vector for the shifted surfaces of each chamber
235  std::vector<std::shared_ptr<Acts::Surface>> shiftedSurfaces = {};
236 
237  // creare an array of vectors that holds all the chambers of each sector
238  std::vector<std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>>>
239  chambersOfSectors(detVolumesSize);
240 
241  std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>>
242  detectorCylinderVolumesOfSector = {};
243 
244  for (int i = 0; i < mCfg.NumberOfSectors; i++) {
245  Acts::AngleAxis3 rotation(2 * i * halfPhi, Acts::Vector3(0., 0., 1.));
246 
247  for (int itr = 0; itr < detVolumesSize; itr++) {
248  const auto& detVol = detVolumes[itr];
249 
250  auto shift_vol =
251  rotation * Acts::Transform3(Acts::Translation3(detVol->center()));
252 
253  for (auto& detSurf : detVol->surfaces()) {
254  auto shift_surf = Acts::Transform3::Identity() * rotation;
255 
256  // create the shifted surfaces by creating copied surface objects
257  auto strawSurfaceObject = Acts::Surface::makeShared<Acts::StrawSurface>(
258  detSurf->transform(Acts::GeometryContext()),
259  detSurf->bounds().values()[0], detSurf->bounds().values()[1]);
260 
261  auto copiedTransformStrawSurface =
262  Acts::Surface::makeShared<Acts::StrawSurface>(
263  Acts::GeometryContext(), *strawSurfaceObject, shift_surf);
264 
265  shiftedSurfaces.push_back(copiedTransformStrawSurface);
266  }
267 
268  // create the bounds of the volumes of each chamber
269  auto bounds = std::make_unique<Acts::CuboidVolumeBounds>(
270  detVol->volumeBounds().values()[0],
271  detVol->volumeBounds().values()[1],
272  detVol->volumeBounds().values()[2]);
273  // create the shifted chamber
274  auto detectorVolumeSec =
277  "detectorVolumeChamber_" + std::to_string(itr), shift_vol,
278  std::move(bounds), shiftedSurfaces,
279  std::vector<
280  std::shared_ptr<Acts::Experimental::DetectorVolume>>{},
283 
284  chambersOfSectors[itr].push_back(detectorVolumeSec);
285 
286  shiftedSurfaces.clear();
287 
288  } // end of detector volumes
289 
290  } // end of number of sectors
291 
292  for (std::size_t i = 0; i < cylinderVolumesBounds.size(); ++i) {
293  detectorCylinderVolumesOfSector.push_back(
296  "cylinder_volume_" + std::to_string(i), transform,
297  std::move(cylinderVolumesBounds[i]),
298  std::vector<std::shared_ptr<Acts::Surface>>{}, chambersOfSectors[i],
301 
302  } // end of cylinder volumes
303 
304  auto cylinderVolumesBoundsOfMother =
305  std::make_shared<Acts::CylinderVolumeBounds>(
306  rmins.front(), rmaxs.back(),
307  *std::max_element(halfZ.begin(), halfZ.end()), sectorAngle);
308 
309  // creation of the mother volume
312  "detectorVolumeSector", transform,
313  std::move(cylinderVolumesBoundsOfMother),
314  std::vector<std::shared_ptr<Acts::Surface>>{},
315  detectorCylinderVolumesOfSector, Acts::Experimental::tryAllSubVolumes(),
317 
318  return detectorVolume;
319 }
320 
322  const std::shared_ptr<Acts::Experimental::DetectorVolume>&
324  const std::string& nameObjFile) {
326 
327  Acts::ObjVisualization3D objSector;
328 
330  objSector, *detectorVolumeSector, Acts::GeometryContext(),
331  Acts::Transform3::Identity(), sConfig);
332 
333  objSector.write(nameObjFile);
334 }