ATLAS Offline Software
ActsCaloTrackingVolumeBuilder.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 #include "ActsInterop/Logger.h"
7 
8 #include "StoreGate/ReadHandle.h"
10 #include "CaloDetDescr/CaloDetDescrElement.h"
12 
13 #include "Acts/Geometry/TrackingVolume.hpp"
14 #include "Acts/Geometry/VolumeBounds.hpp"
15 #include "Acts/Geometry/GlueVolumesDescriptor.hpp"
16 
17 // ACTS
18 #include "Acts/Geometry/GenericCuboidVolumeBounds.hpp"
19 #include "Acts/Geometry/CutoutCylinderVolumeBounds.hpp"
20 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
21 //#include "Acts/Utilities/IVisualization.hpp"
22 #include "Acts/Utilities/Helpers.hpp"
23 #include "Acts/Geometry/TrackingVolumeArrayCreator.hpp"
24 #include "Acts/Utilities/BinnedArrayXD.hpp"
25 #include "Acts/Geometry/CylinderVolumeHelper.hpp"
26 
27 #include <fstream>
28 
29 using Box = Acts::Volume::BoundingBox; // shortcut
30 
31 using CVBBV = Acts::CylinderVolumeBounds::BoundValues;
32 using CCVBBV = Acts::CutoutCylinderVolumeBounds::BoundValues;
33 
35  const std::string& name,
36  const IInterface* parent)
37 : base_class(type, name, parent)
38 {
39 
40 }
41 
44 {
45  m_caloMgr = detStore()->tryConstRetrieve<CaloDetDescrManager>(caloMgrStaticKey);
46  if(!m_caloMgr) {
47  std::unique_ptr<CaloDetDescrManager> caloMgrPtr = buildCaloDetDescrNoAlign(serviceLocator()
49  ATH_CHECK(detStore()->record(std::move(caloMgrPtr), caloMgrStaticKey));
50  ATH_CHECK(detStore()->retrieve(m_caloMgr, caloMgrStaticKey));
51  }
52  return StatusCode::SUCCESS;
53 }
54 
55 std::shared_ptr<Acts::TrackingVolume>
57  const Acts::GeometryContext& gctx,
58  std::shared_ptr<const Acts::TrackingVolume> insideVolume,
59  std::shared_ptr<const Acts::VolumeBounds> /*outsideBounds*/) const
60 {
61 
62 
63  // generate the calo cell volume description
64  std::vector<std::unique_ptr<Acts::Volume>> cells;
65  cells = cellFactory();
66 
67  ATH_MSG_VERBOSE("Collected " << cells.size() << " calo cells");
68 
69 
70  // we need to turn the cells into boundary boxes
71  std::vector<std::unique_ptr<Box>> boxStore;
72  std::vector<Box*> prims;
73  for (const auto& cell : cells) {
74  boxStore.push_back(
75  std::make_unique<Box>(cell->boundingBox({0.1, 0.1, 0.1})));
76  prims.push_back(boxStore.back().get());
77  }
78 
79  ATH_MSG_VERBOSE("Generated Bounding Boxes");
80 
81 
82  ATH_MSG_VERBOSE("Figure out dimensions of wrapping volume");
83 
84  std::shared_ptr<Acts::CutoutCylinderVolumeBounds> caloVolBounds
85  = makeCaloVolumeBounds(boxStore, insideVolume);
86 
87  // build a BVH octree for the bounding boxes
88  // but only AFTER we've built the calo volume bounds
89  // Box* top;
90  // top = Acts::make_octree(boxStore, prims, 1, 0.1);
91 
92  // Create Tracking Volume that coutains the Calo
93  // This needs to own the Abstract Volumes (cells), but we
94  // need to up-cast them to Volume, since that's what TrackingVolume can own
95  std::vector<std::unique_ptr<const Acts::Volume>> cellVols;
96  cellVols.reserve(cells.size());
97  for(auto& cell : cells) {
98  std::unique_ptr<const Acts::Volume> up;
99  // release, up-cast, then immediately pack again
100  up = std::unique_ptr<const Acts::Volume>(dynamic_cast<const Acts::Volume*>(cell.release()));
101  cellVols.push_back(std::move(up));
102  }
103 
104  // This was removed in https://github.com/acts-project/acts/pull/3029
105  // To be reimplemented using new geometry model instead of explicit TrackingVolume content
106  throw std::runtime_error{"Calo building for ACTS currently disabled"};
107  std::shared_ptr<Acts::TrackingVolume> calo;
108  // = Acts::TrackingVolume::create(Acts::Transform3::Identity(),
109  // caloVolBounds,
110  // std::move(boxStore),
111  // std::move(cellVols),
112  // top,
113  // nullptr, // no material for now
114  // "Calo");
115 
116  // We need to interglue all the volumes together
117  std::shared_ptr<Acts::TrackingVolume> mutInsideVolume
118  = std::const_pointer_cast<Acts::TrackingVolume>(insideVolume);
119  auto idBounds = dynamic_cast<const Acts::CylinderVolumeBounds*>(&insideVolume->volumeBounds());
120  if (idBounds == nullptr) { // protection against nullptr
121  ATH_MSG_ERROR("Unable to dynamic cast volume bounds to Acts::CylinderVolumeBounds");
122  throw std::runtime_error("Error casting to CylinderVolumeBounds");
123  }
124 
125  // we want gap volumes at pos and neg xy face, and at outer cyl cover
126  // which will include the solenoid area
127 
128  auto trackingVolumeArrayCreator
129  = std::make_shared<const Acts::TrackingVolumeArrayCreator>(
130  Acts::TrackingVolumeArrayCreator::Config{},
131  makeActsAthenaLogger(this, std::string("TrkVolArrCrtr"), std::string("ActsTGSvc")));
132  Acts::CylinderVolumeHelper::Config cvhCfg;
133  cvhCfg.trackingVolumeArrayCreator = trackingVolumeArrayCreator;
134  Acts::CylinderVolumeHelper cvh(cvhCfg, makeActsAthenaLogger(this, std::string("ACaloTrkVB"), std::string("CylVolHlp")));
135 
136  std::vector<double> lPos = {};
137  std::vector<std::shared_ptr<Acts::TrackingVolume>> noVolumes;
138 
139  ATH_MSG_VERBOSE("Creating gap volume to extend ID");
140  // positive xy gap
141  auto idGapPosXY = cvh.createGapTrackingVolume(gctx,
142  noVolumes,
143  nullptr,
144  idBounds->get(CVBBV::eMinR),
145  idBounds->get(CVBBV::eMaxR),
146  idBounds->get(CVBBV::eHalfLengthZ),
147  caloVolBounds->get(CCVBBV::eHalfLengthZcutout),
148  lPos,
149  false,
150  "ID::PositiveGap"
151  );
152  // negative xy gap
153  auto idGapNegXY = cvh.createGapTrackingVolume(gctx,
154  noVolumes,
155  nullptr,
156  idBounds->get(CVBBV::eMinR),
157  idBounds->get(CVBBV::eMaxR),
158  -caloVolBounds->get(CCVBBV::eHalfLengthZcutout),
159  -idBounds->get(CVBBV::eHalfLengthZ),
160  lPos,
161  false,
162  "ID::NegativeGap"
163  );
164  // outer cover gap
165  auto idGapCylOuter = cvh.createGapTrackingVolume(gctx,
166  noVolumes,
167  nullptr,
168  idBounds->get(CVBBV::eMaxR),
169  caloVolBounds->get(CCVBBV::eMedR),
170  -caloVolBounds->get(CCVBBV::eHalfLengthZcutout),
171  +caloVolBounds->get(CCVBBV::eHalfLengthZcutout),
172  lPos,
173  false,
174  "ID::CylOutGap"
175  );
176 
177  ATH_MSG_VERBOSE("Create container volume to contain ID and gap volumes");
178  auto idContainerZ = cvh.createContainerTrackingVolume(gctx, {idGapNegXY, mutInsideVolume, idGapPosXY});
179  auto idContainer = cvh.createContainerTrackingVolume(gctx, {idContainerZ, idGapCylOuter});
180 
181 
182  ATH_MSG_VERBOSE("Begin volume glueing");
183 
184  const Acts::GlueVolumesDescriptor& gvd
185  = idContainer->glueVolumesDescriptor();
186  // let's see what the GVD says is on the inner cover of the ID
187  const auto& tVolArrPos = gvd.glueVolumes(Acts::positiveFaceXY);
188  const auto& tVolArrNeg = gvd.glueVolumes(Acts::negativeFaceXY);
189 
190  std::cout << "POSITIVE: " << std::endl;
191  for(const auto& subvol : tVolArrPos->arrayObjects()) {
192  std::cout << subvol->volumeName() << std::endl;
193  std::cout << *subvol << std::endl;
194  }
195 
196  std::cout << "NEGATIVE: " << std::endl;
197  for(const auto& subvol : tVolArrNeg->arrayObjects()) {
198  std::cout << subvol->volumeName() << std::endl;
199  std::cout << *subvol << std::endl;
200  }
201 
202  using BoundarySurface = Acts::BoundarySurfaceT<Acts::TrackingVolume>;
203 
204 
205  // Glue outer radial cover of ID to inner cover of Calo cutout
206  auto idOutVolArray = gvd.glueVolumes(Acts::tubeOuterCover);
207  // Attach that volume array to the calo inner cover
208  ATH_MSG_VERBOSE("Glueing " << calo->volumeName() << " inner cover to " << idOutVolArray->arrayObjects().size() << " volumes");
209  std::const_pointer_cast<BoundarySurface>(calo->boundarySurfaces().at(Acts::tubeInnerCover))
210  ->attachVolumeArray(idOutVolArray, Acts::Direction::Backward);
211  // Loop through the array and attach their boundary surfaces to the calo
212  for(const auto& idVol : idOutVolArray->arrayObjects()){
213  ATH_MSG_VERBOSE("Glueing outer cover of " << idVol->volumeName()
214  << " to inner cover of " << calo->volumeName());
215  std::const_pointer_cast<BoundarySurface>(idVol->boundarySurfaces().at(Acts::tubeOuterCover))
216  ->attachVolume(calo.get(), Acts::Direction::Forward);
217  }
218 
219  // Glue positive XY face of ID to inner positive XY face of Calo.
220  // ID has multiple, Calo has only one
221  auto idPosXYVolArray = gvd.glueVolumes(Acts::positiveFaceXY);
222  ATH_MSG_VERBOSE("Glueing " << calo->volumeName() << " positive inner cutout disc to "
223  << idPosXYVolArray->arrayObjects().size() << " volumes");
224  std::const_pointer_cast<BoundarySurface>(calo->boundarySurfaces().at(Acts::index5))
225  ->attachVolumeArray(idPosXYVolArray, Acts::Direction::Backward);
226  // Other way round, attach ID volumes to calo
227  for(const auto& idVol : idPosXYVolArray->arrayObjects()){
228  ATH_MSG_VERBOSE("Glueing positive XY face of " << idVol->volumeName()
229  << " to positive inner coutout disc of " << calo->volumeName());
230  std::const_pointer_cast<BoundarySurface>(idVol->boundarySurfaces().at(Acts::positiveFaceXY))
231  ->attachVolume(calo.get(), Acts::Direction::Forward);
232  }
233 
234  // Glue negative XY face of ID to inner negative XY face of Calo.
235  // ID has multiple, Calo has only one
236  auto idNegXYVolArray = gvd.glueVolumes(Acts::negativeFaceXY);
237  ATH_MSG_VERBOSE("Glueing " << calo->volumeName() << " negative inner cutout disc to "
238  << idNegXYVolArray->arrayObjects().size() << " volumes");
239  std::const_pointer_cast<BoundarySurface>(calo->boundarySurfaces().at(Acts::index4))
240  ->attachVolumeArray(idNegXYVolArray, Acts::Direction::Forward);
241  // Other way round, attach ID volumes to calo
242  for(const auto& idVol : idNegXYVolArray->arrayObjects()){
243  ATH_MSG_VERBOSE("Glueing negative XY face of " << idVol->volumeName()
244  << " to negative inner coutout disc of " << calo->volumeName());
245  std::const_pointer_cast<BoundarySurface>(idVol->boundarySurfaces().at(Acts::negativeFaceXY))
246  ->attachVolume(calo.get(), Acts::Direction::Backward);
247  }
248 
249  // For navigational purposes we need to create three pseudo container cylinders.
250  // One for the middle, which includes the central part of the Calo and the ID, and
251  // two that fit cleanly at the +- XY face that then only include the Calo
252 
253  // Construct track vol array for use in positive and negative pseudocontainer.
254  // This will only contain the calo
255 
256  double caloRMin = caloVolBounds->get(CCVBBV::eMinR);
257  double caloRMed = caloVolBounds->get(CCVBBV::eMedR);
258  double caloRMax = caloVolBounds->get(CCVBBV::eMaxR);
259  double caloDZ1 = caloVolBounds->get(CCVBBV::eHalfLengthZ);
260  double caloDZ2 = caloVolBounds->get(CCVBBV::eHalfLengthZcutout);
261 
262  Acts::Vector3 caloChokeRPos
263  = {caloRMin + (caloRMax - caloRMin)/2., 0, 0};
264 
265  std::vector<Acts::TrackingVolumeOrderPosition> tVolOrdPosNeg;
266  tVolOrdPosNeg.push_back(std::make_pair(calo, caloChokeRPos));
267  std::vector<float> posNegBoundaries
268  = {float(caloRMin), float(caloRMax)};
269  auto binUtilityPosNeg = std::make_unique<const Acts::BinUtility>(posNegBoundaries,
271 
272  auto tVolArrPosNeg
273  = std::make_shared<const Acts::BinnedArrayXD<Acts::TrackingVolumePtr>>(
274  tVolOrdPosNeg, std::move(binUtilityPosNeg));
275 
276  double chokeZOffset = caloDZ2 + (caloDZ1 - caloDZ2)/2.;
277  Acts::Transform3 posTrf(Acts::Translation3(Acts::Vector3::UnitZ() * chokeZOffset));
278  Acts::Transform3 negTrf(Acts::Translation3(Acts::Vector3::UnitZ()* -1 *chokeZOffset));
279 
280  auto posNegCylBounds = std::make_shared<Acts::CylinderVolumeBounds>(
281  caloRMin, caloRMax, (caloDZ1 - caloDZ2) / 2.);
282 
283  // they share the same bounds and tvol array
284  auto posContainer = std::make_shared<Acts::TrackingVolume>(
285  posTrf,
286  posNegCylBounds,
287  nullptr, nullptr,
288  tVolArrPosNeg,
289  Acts::MutableTrackingVolumeVector{});
290  ATH_MSG_VERBOSE("Built positive container " << *posContainer);
291  ATH_MSG_VERBOSE(" - containing: " << calo->volumeName());
292  auto negContainer = std::make_shared<Acts::TrackingVolume>(
293  negTrf,
294  posNegCylBounds,
295  nullptr, nullptr,
296  tVolArrPosNeg,
297  Acts::MutableTrackingVolumeVector{});
298  ATH_MSG_VERBOSE("Built negative container " << *negContainer);
299  ATH_MSG_VERBOSE(" - containing: " << calo->volumeName());
300 
301  // now build the central pseudocontainer
302  std::vector<Acts::TrackingVolumeOrderPosition> tVolOrderedCtr;
303  tVolOrderedCtr.push_back(std::make_pair(idContainer, Acts::Vector3(caloRMed / 2., 0, 0)));
304  tVolOrderedCtr.push_back(std::make_pair(calo,
305  Acts::Vector3(caloRMed +
306  (caloRMax- caloRMed) / 2., 0, 0)));
307 
308  std::vector<float> ctrBoundaries = {0, float(caloRMed), float(caloRMax)};
309  auto binUtilityCtr
310  = std::make_unique<const Acts::BinUtility>(
311  ctrBoundaries,
313 
314  auto tVolArrCtr
315  = std::make_shared<const Acts::BinnedArrayXD<Acts::TrackingVolumePtr>>(
316  tVolOrderedCtr, std::move(binUtilityCtr));
317 
318 
319  auto ctrContainer = std::make_shared<Acts::TrackingVolume>(Acts::Transform3::Identity(),
320  std::make_shared<Acts::CylinderVolumeBounds>(
321  caloRMin, caloRMax, caloDZ2),
322  nullptr, nullptr,
323  tVolArrCtr,
324  Acts::MutableTrackingVolumeVector{}
325  );
326 
327  ATH_MSG_VERBOSE("Built central container " << *ctrContainer);
328  ATH_MSG_VERBOSE("- containing: " << idContainer->volumeName() << ", " << calo->volumeName());
329 
330  // and now combine those together into another one
331  Acts::TrackingVolumeArrayCreator tvac{Acts::TrackingVolumeArrayCreator::Config{}};
332 
333  auto mainContainer = std::make_shared<Acts::TrackingVolume>(Acts::Transform3::Identity(),
334  std::make_shared<Acts::CylinderVolumeBounds>(
335  caloRMin, caloRMax, caloDZ1),
336  nullptr, nullptr,
337  tvac.trackingVolumeArray(gctx, {negContainer, ctrContainer, posContainer},
338  Acts::binZ),
339  Acts::MutableTrackingVolumeVector{}
340  );
341 
342 
343  ATH_MSG_VERBOSE("Built main container: " << *mainContainer);
344 
345  return mainContainer;
346 }
347 
348 std::shared_ptr<Acts::CutoutCylinderVolumeBounds>
349 ActsCaloTrackingVolumeBuilder::makeCaloVolumeBounds(const std::vector<std::unique_ptr<Box>>& boxStore,
350  std::shared_ptr<const Acts::TrackingVolume> insideVolume) const
351 {
352  using namespace Acts::VectorHelpers;
353 
354  // determine the dimensions of the
355  double rmin_at_center = std::numeric_limits<double>::max();
356  double rmin_at_choke = std::numeric_limits<double>::max();
357  double rmax = std::numeric_limits<double>::lowest();
359  double zmax = std::numeric_limits<double>::lowest();
360  double cutout_zmin_abs = std::numeric_limits<double>::max();
361 
362  // We need to figure out what the size of the inner cutout cylinder is
363  // so we can make sure everything worked fine!
364  // We check what the min radius at small z, and then we turn it around and
365  // check z bounds at lower radii.
366  for (const auto& box : boxStore) {
367  Acts::Vector3 vmin = box->min().cast<double>();
368  Acts::Vector3 vmax = box->max().cast<double>();
369 
370  double vrmin = perp(vmin);
371  double vrmax = perp(vmax);
372 
373  rmin_at_choke = std::min(rmin_at_choke, std::min(vrmin, vrmax));
374 
375  rmax = std::max(rmax, std::max(vrmin, vrmax));
376  zmin = std::min(zmin, std::min(vmin.z(), vmax.z()));
377  zmax = std::max(zmax, std::max(vmin.z(), vmax.z()));
378 
379  if (std::abs(vmin.z()) < 100) {
380  rmin_at_center = std::min(vrmin, rmin_at_center);
381  }
382  if (std::abs(vmax.z()) < 100) {
383  rmin_at_center = std::min(vrmax, rmin_at_center);
384  }
385  }
386 
387  for (const auto& box : boxStore) {
388  Acts::Vector3 vmin = box->min().cast<double>();
389  Acts::Vector3 vmax = box->max().cast<double>();
390  double vrmin = perp(vmin);
391  double vrmax = perp(vmax);
392 
393  if (vrmin < rmin_at_center * 0.9) {
394  cutout_zmin_abs = std::min(cutout_zmin_abs, std::abs(vmin.z()));
395  }
396  if (vrmax < rmin_at_center * 0.9) {
397  cutout_zmin_abs = std::min(cutout_zmin_abs, std::abs(vmax.z()));
398  }
399  }
400 
401  double dz1 = (zmax - zmin) / 2.;
402  double dz2 = cutout_zmin_abs;
403 
404  // envelopes
405  double envZ = 5;
406  double envR = 5;
407  dz1 += envZ;
408  dz2 -= envZ;
409  rmax += envR;
410  if(rmin_at_choke > envR) rmin_at_choke -= envR;
411  rmin_at_center -= envR;
412 
413 
414  ATH_MSG_VERBOSE("rmin_at_center: " << rmin_at_center
415  << " rmin at choke: " << rmin_at_choke
416  << " rmax: " << rmax << " zmin: " << zmin << " zmax: " << zmax
417  << " coutout_zmin_abs: " << cutout_zmin_abs);
418 
419  // Ok now let's analyse what we're wrapping the calo around: the ID
420  // The ID will have to be built already.
421 
422  // We need to figure out the dimensions of the ID.
423  // Assuming the wrapping volume is a cylinder.
424  auto idCylBds
425  = dynamic_cast<const Acts::CylinderVolumeBounds*>(&insideVolume->volumeBounds());
426  if (idCylBds == nullptr) { // protection against nullptr
427  ATH_MSG_ERROR("Unable to dynamic cast volume bounds to Acts::CylinderVolumeBounds");
428  throw std::runtime_error("Error casting to CylinderVolumeBounds");
429  }
430 
431  double idRMax = idCylBds->get(CVBBV::eMaxR);
432  double idRMin = idCylBds->get(CVBBV::eMinR);
433  double idHlZ = idCylBds->get(CVBBV::eHalfLengthZ);
434 
435  ATH_MSG_VERBOSE("ID volume bounds:\n" << *idCylBds);
436 
437  ATH_MSG_VERBOSE("Inside volume transform: \n" << insideVolume->transform().matrix());
438 
439  if (!insideVolume->transform().isApprox(Acts::Transform3::Identity())) {
440  ATH_MSG_VERBOSE("Inside volume transform is not unity.");
441 
442  // transformation matrix is NOT unity. Let's check:
443  // - Rotation is approximate unity
444  // - Translation is only along z axis
445  const auto& trf = insideVolume->transform();
446 
447  Acts::RotationMatrix3 rot = trf.rotation();
448  bool unityRot = rot.isApprox(Acts::RotationMatrix3::Identity());
449 
450  ATH_MSG_VERBOSE("\n" << rot);
451 
452  // dot product with Z axis is about 1 => ok
453  const Acts::Vector3 trl = trf.translation();
454  bool transZOnly = std::abs(1 - std::abs(Acts::Vector3::UnitZ().dot(trl.normalized()))) < 1e-6;
455 
456  ATH_MSG_VERBOSE("TRL "<< trl.transpose());
457  ATH_MSG_VERBOSE("TRL "<< trl.normalized().dot(Acts::Vector3::UnitZ()));
458 
459  if(!unityRot || !transZOnly) {
460  ATH_MSG_ERROR("The ID appears to be shifted from the origin. I cannot handle this.");
461  ATH_MSG_ERROR("(I'm not building the Calo!)");
462  throw std::runtime_error("Error building calo");
463  }
464  else {
465  ATH_MSG_VERBOSE("Checked: non unitarity is ONLY due to shift along z axis: that's ok");
466  double prevIdHlZ = idHlZ;
467  idHlZ += std::abs(trl.z());
468  ATH_MSG_VERBOSE("Modifying effective half length of ID cylinder: " << prevIdHlZ << " => " << idHlZ);
469  }
470  }
471 
472  // make sure we can fit the ID inside the calo cutout
473  if (idRMax > rmin_at_center || idHlZ > dz2 || (idRMin > rmin_at_choke && idRMin != 0.)) {
474  ATH_MSG_ERROR("Cannot fit ID inside the Calo");
475  ATH_MSG_ERROR("This can be because the ID overlaps into the calo volume");
476  ATH_MSG_ERROR("Or because the Calo choke radius is SMALLER than the ID inner radius");
477  ATH_MSG_ERROR("Currently, I can only make the choke radius smaller, I can not make it larger");
478  ATH_MSG_ERROR("nor can I manipulate the ID volume bounds at this point.");
479  ATH_MSG_ERROR("ID rMax: " << idRMax << " Calo rMin@center: " << rmin_at_center);
480  ATH_MSG_ERROR("ID hlZ: " << idHlZ << " Calo inner Z hl: " << dz2);
481  ATH_MSG_ERROR("ID rMin: " << idRMin << " Calo rMin@choke: " << rmin_at_choke);
482  ATH_MSG_ERROR("(I'm not building the Calo!)");
483  throw std::runtime_error("Error building calo");
484  }
485 
486  // Let's harmonize the sizes, so we have a exact wrap of the ID
487  // Choke is now exactly as wide as space inside the ID.
488  // We can fit the beam pipe in there later.
489  rmin_at_choke = idRMin;
490 
491  std::shared_ptr<Acts::CutoutCylinderVolumeBounds> volBds = nullptr;
492  volBds = std::make_shared<Acts::CutoutCylinderVolumeBounds>(
493  rmin_at_choke, rmin_at_center, rmax, dz1, dz2);
494 
495  ATH_MSG_VERBOSE(*volBds);
496 
497  return volBds;
498 }
499 
500 
501 namespace {
502  double
503  eta_to_theta(double eta)
504  {
505  return 2 * std::atan(std::exp(-eta));
506  }
507 }
508 
509 Acts::Volume
511  double dz,
512  double eta,
513  double deta,
514  double phi,
515  double dphi) const
516 {
517  double eta_max = eta + deta * 0.5;
518  double eta_min = eta - deta * 0.5;
519  double theta_max = eta_to_theta(eta_max);
520  double theta = eta_to_theta(eta);
521  double theta_min = eta_to_theta(eta_min);
522  double phi_max = phi + dphi * 0.5;
523  double phi_min = phi - dphi * 0.5;
524  double z_min = z - dz;
525  double z_max = z + dz;
526 
527  double r_min, r_max;
528 
529  // inner face
530  r_min = std::tan(theta_min) * z_min;
531  r_max = std::tan(theta_max) * z_min;
532 
533  Acts::Vector3 p1(r_min * std::cos(phi_min), r_min * std::sin(phi_min), z_min);
534  Acts::Vector3 p2(r_min * std::cos(phi_max), r_min * std::sin(phi_max), z_min);
535  Acts::Vector3 p3(r_max * std::cos(phi_max), r_max * std::sin(phi_max), z_min);
536  Acts::Vector3 p4(r_max * std::cos(phi_min), r_max * std::sin(phi_min), z_min);
537 
538  // outer face
539  r_min = std::tan(theta_min) * z_max;
540  r_max = std::tan(theta_max) * z_max;
541 
542  Acts::Vector3 p5(r_min * std::cos(phi_min), r_min * std::sin(phi_min), z_max);
543  Acts::Vector3 p6(r_min * std::cos(phi_max), r_min * std::sin(phi_max), z_max);
544  Acts::Vector3 p7(r_max * std::cos(phi_max), r_max * std::sin(phi_max), z_max);
545  Acts::Vector3 p8(r_max * std::cos(phi_min), r_max * std::sin(phi_min), z_max);
546 
547  double r_mid = std::tan(theta) * z_min;
548  Acts::Vector3 center;
549  center.x() = r_mid * std::cos(phi);
550  center.y() = r_mid * std::sin(phi);
551  center.z() = z;
552 
553  Acts::Transform3 glob2vol = Acts::Transform3::Identity();
554  glob2vol *= Acts::AngleAxis3(-phi, Acts::Vector3::UnitZ());
555  glob2vol *= Acts::AngleAxis3(
556  -theta, Acts::Vector3::UnitZ().cross(center).normalized());
557  glob2vol
558  *= Acts::Translation3(-(p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8) / 8.);
559 
560  p1 = glob2vol * p1;
561  p2 = glob2vol * p2;
562  p3 = glob2vol * p3;
563  p4 = glob2vol * p4;
564  p5 = glob2vol * p5;
565  p6 = glob2vol * p6;
566  p7 = glob2vol * p7;
567  p8 = glob2vol * p8;
568 
569  auto globalToLocal = glob2vol.inverse();
570 
571  auto cubo = std::make_shared<Acts::GenericCuboidVolumeBounds>(
572  std::array<Acts::Vector3, 8>({{p1, p2, p3, p4, p5, p6, p7, p8}}));
573  Acts::Volume vol(globalToLocal, std::move(cubo));
574 
575  return vol;
576 }
577 
578 
579 Acts::Volume
581  double dr,
582  double eta,
583  double deta,
584  double phi,
585  double dphi) const
586 {
587  // std::cout << "build barrel" << std::endl;
588  double eta_max = eta + deta * 0.5;
589  double eta_min = eta - deta * 0.5;
590  double theta = eta_to_theta(eta);
591  double theta_max = eta_to_theta(eta_max);
592  double theta_min = eta_to_theta(eta_min);
593  double phi_max = phi + dphi * 0.5;
594  double phi_min = phi - dphi * 0.5;
595 
596  double r_min = r - dr;
597  double r_max = r + dr;
598 
599  double z_min, z_max;
600 
601  // inner face
602  z_min = r_min / std::tan(theta_min);
603  z_max = r_min / std::tan(theta_max);
604 
605  Acts::Vector3 p1(r_min * std::cos(phi_min), r_min * std::sin(phi_min), z_min);
606  Acts::Vector3 p2(r_min * std::cos(phi_min), r_min * std::sin(phi_min), z_max);
607  Acts::Vector3 p3(r_min * std::cos(phi_max), r_min * std::sin(phi_max), z_max);
608  Acts::Vector3 p4(r_min * std::cos(phi_max), r_min * std::sin(phi_max), z_min);
609 
610  // outer face
611  z_min = r_max / std::tan(theta_min);
612  z_max = r_max / std::tan(theta_max);
613 
614  Acts::Vector3 p5(r_max * std::cos(phi_min), r_max * std::sin(phi_min), z_min);
615  Acts::Vector3 p6(r_max * std::cos(phi_min), r_max * std::sin(phi_min), z_max);
616  Acts::Vector3 p7(r_max * std::cos(phi_max), r_max * std::sin(phi_max), z_max);
617  Acts::Vector3 p8(r_max * std::cos(phi_max), r_max * std::sin(phi_max), z_min);
618 
619  Acts::Vector3 center;
620  center.x() = r * std::cos(phi);
621  center.y() = r * std::sin(phi);
622  center.z() = r / std::tan(theta);
623 
624  Acts::Transform3 glob2vol = Acts::Transform3::Identity();
625  glob2vol *= Acts::AngleAxis3(-phi, Acts::Vector3::UnitZ());
626  glob2vol *= Acts::AngleAxis3(
627  -theta, Acts::Vector3::UnitZ().cross(center).normalized());
628  glob2vol
629  *= Acts::Translation3(-(p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8) / 8.);
630 
631  p1 = glob2vol * p1;
632  p2 = glob2vol * p2;
633  p3 = glob2vol * p3;
634  p4 = glob2vol * p4;
635  p5 = glob2vol * p5;
636  p6 = glob2vol * p6;
637  p7 = glob2vol * p7;
638  p8 = glob2vol * p8;
639 
640  auto globalToLocal = glob2vol.inverse();
641 
642  auto cubo = std::make_shared<Acts::GenericCuboidVolumeBounds>(
643  std::array<Acts::Vector3, 8>({{p1, p2, p3, p4, p5, p6, p7, p8}}));
644 
645  Acts::Volume vol(globalToLocal, std::move(cubo));
646 
647  return vol;
648 }
649 
650 Acts::Volume
651 ActsCaloTrackingVolumeBuilder::build_box(double x, double dx, double y, double dy, double z, double dz) const
652 {
653  // std::cout << "build box" << std::endl;
654 
655  double x_min, x_max, y_min, y_max, z_min, z_max;
656  x_min = x - dx;
657  x_max = x + dx;
658  y_min = y - dy;
659  y_max = y + dy;
660  z_min = z - dz;
661  z_max = z + dz;
662 
663  // inner face
664  Acts::Vector3 p1(x_min, y_min, z_min);
665  Acts::Vector3 p2(x_min, y_max, z_min);
666  Acts::Vector3 p3(x_max, y_max, z_min);
667  Acts::Vector3 p4(x_max, y_min, z_min);
668 
669  // outer face
670  Acts::Vector3 p5(x_min, y_min, z_max);
671  Acts::Vector3 p6(x_min, y_max, z_max);
672  Acts::Vector3 p7(x_max, y_max, z_max);
673  Acts::Vector3 p8(x_max, y_min, z_max);
674 
675  Acts::Transform3 glob2vol = Acts::Transform3::Identity();
676  glob2vol
677  *= Acts::Translation3(-(p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8) / 8.);
678 
679  p1 = glob2vol * p1;
680  p2 = glob2vol * p2;
681  p3 = glob2vol * p3;
682  p4 = glob2vol * p4;
683  p5 = glob2vol * p5;
684  p6 = glob2vol * p6;
685  p7 = glob2vol * p7;
686  p8 = glob2vol * p8;
687 
688  auto globalToLocal = glob2vol.inverse();
689 
690  auto cubo = std::make_shared<Acts::GenericCuboidVolumeBounds>(
691  std::array<Acts::Vector3, 8>({{p1, p2, p3, p4, p5, p6, p7, p8}}));
692  Acts::Volume vol(globalToLocal, std::move(cubo));
693 
694  return vol;
695 }
696 
697 std::vector<std::unique_ptr<Acts::Volume>>
699 {
700  //Acts::ply_helper<double> ply_lar;
701  //Acts::ply_helper<double> ply_tile;
702  //Acts::ply_helper<double> ply_fcal;
703 
704  //float x, y, z, r, phi_raw, eta_raw, dphi, deta, dr, dx, dy, dz;
705  float z, dz, eta_raw, deta, phi_raw, dphi, r, dr, x, y, dx, dy;
706  size_t calosample;
707  float scale;
708 
709  // storage of cells we will produce
710  std::vector<std::unique_ptr<Acts::Volume>> cells;
711  cells.reserve(m_caloMgr->element_size()); // about 180k
712 
713  for(auto it = m_caloMgr->element_begin();it < m_caloMgr->element_end();++it) {
714  const CaloDetDescrElement* cde = *it;
715 
716  z = cde->z();
717  dz = cde->dz();
718  eta_raw = cde->eta_raw();
719  deta = cde->deta();
720  phi_raw = cde->phi_raw();
721  dphi = cde->dphi();
722  r = cde->r();
723  dr = cde->dr();
724  x = cde->x();
725  y = cde->y();
726  dx = cde->dx();
727  dy = cde->dy();
728 
729  calosample = cde->getSampling();
730 
731  scale = 1.;
732  if (calosample >= 12 && calosample <= 20) {
733  scale = 0.5;
734  }
735 
736  //Acts::ply_helper<double>* ply;
737  //if (calosample <= 11) {
738  //ply = &ply_lar;
739  //} else if (calosample <= 20) {
740  //ply = &ply_tile;
741  //} else {
742  //ply = &ply_fcal;
743  //}
744 
745 
746  switch (calosample) {
747  case 4:
748  case 5:
749  case 6:
750  case 7:
751  case 8:
752  case 9:
753  case 10:
754  case 11:
755  case 17:
756  dz *= scale;
757  cells.push_back(std::make_unique<Acts::Volume>(
758  build_endcap(z, dz, eta_raw, deta, phi_raw, dphi)));
759  break;
760  case 0:
761  case 1:
762  case 2:
763  case 3:
764  case 12:
765  case 13:
766  case 14:
767  case 15:
768  case 16:
769  case 18:
770  case 19:
771  case 20:
772  dr *= scale;
773  cells.push_back(std::make_unique<Acts::Volume>(
774  build_barrel(r, dr, eta_raw, deta, phi_raw, dphi)));
775  break;
776  case 21:
777  case 22:
778  case 23:
779  scale = 1.;
780  dx *= scale;
781  dy *= scale;
782  // dz *= scale;
783  cells.push_back(std::make_unique<Acts::Volume>(
784  build_box(x, dx, y, dy, z, dz)));
785  break;
786  default:
787  std::stringstream ss;
788  ss << "Unkown calo sample " << calosample;
789  std::runtime_error(ss.str());
790  }
791 
792  //cells.back()->boundingBox({0.1, 0.1, 0.1}).draw(*ply);
793  //auto cvb = dynamic_cast<const
794  //Acts::GenericCuboidVolumeBounds*>(&cells.back()->volumeBounds());
795  //cvb->draw(*ply, cells.back()->transform());
796  }
797 
798  //std::ofstream os("lar.ply");
799  //os << ply_lar << std::flush;
800  //os.close();
801 
802  //os = std::ofstream("tile.ply");
803  //os << ply_tile << std::flush;
804  //os.close();
805 
806  //os = std::ofstream("fcal.ply");
807  //os << ply_fcal << std::flush;
808  //os.close();
809 
810  return cells;
811 }
CaloDetDescrElement::deta
float deta() const
cell deta
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:356
python.PyKernel.retrieve
def retrieve(aClass, aKey=None)
Definition: PyKernel.py:110
beamspotman.r
def r
Definition: beamspotman.py:676
RunTileCalibRec.cells
cells
Definition: RunTileCalibRec.py:271
ActsCaloTrackingVolumeBuilder::trackingVolume
std::shared_ptr< Acts::TrackingVolume > trackingVolume(const Acts::GeometryContext &gctx, std::shared_ptr< const Acts::TrackingVolume > insideVolume=nullptr, std::shared_ptr< const Acts::VolumeBounds > outsideBounds=nullptr) const override
Definition: ActsCaloTrackingVolumeBuilder.cxx:56
ActsCaloTrackingVolumeBuilder.h
ReadCellNoiseFromCool.cell
cell
Definition: ReadCellNoiseFromCool.py:53
max
#define max(a, b)
Definition: cfImp.cxx:41
PowhegControl_ttHplus_NLO.ss
ss
Definition: PowhegControl_ttHplus_NLO.py:83
phi
Scalar phi() const
phi method
Definition: AmgMatrixBasePlugin.h:64
CaloDetDescrElement::y
float y() const
cell y
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:365
perp
Scalar perp() const
perp method - perpenticular length
Definition: AmgMatrixBasePlugin.h:35
ActsCaloTrackingVolumeBuilder::makeCaloVolumeBounds
std::shared_ptr< Acts::CutoutCylinderVolumeBounds > makeCaloVolumeBounds(const std::vector< std::unique_ptr< Acts::Volume::BoundingBox >> &boxStore, std::shared_ptr< const Acts::TrackingVolume > insideVolume) const
Definition: ActsCaloTrackingVolumeBuilder.cxx:349
Trk::binZ
@ binZ
Definition: BinningType.h:49
eta
Scalar eta() const
pseudorapidity method
Definition: AmgMatrixBasePlugin.h:79
PixelAthClusterMonAlgCfg.zmin
zmin
Definition: PixelAthClusterMonAlgCfg.py:176
CaloDetDescrElement
This class groups all DetDescr information related to a CaloCell. Provides a generic interface for al...
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:66
theta
Scalar theta() const
theta method
Definition: AmgMatrixBasePlugin.h:71
CaloDetDescrElement::dr
float dr() const
cell dr
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:360
Trk::index5
@ index5
Definition: BoundarySurfaceFace.h:52
skel.it
it
Definition: skel.GENtoEVGEN.py:423
Trk::positiveFaceXY
@ positiveFaceXY
Definition: BoundarySurfaceFace.h:33
PlotCalibFromCool.vmin
vmin
Definition: PlotCalibFromCool.py:696
python.TurnDataReader.dr
dr
Definition: TurnDataReader.py:112
ActsCaloTrackingVolumeBuilder::build_box
Acts::Volume build_box(double x, double dx, double y, double dy, double z, double dz) const
Definition: ActsCaloTrackingVolumeBuilder.cxx:651
drawFromPickle.cos
cos
Definition: drawFromPickle.py:36
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
drawFromPickle.exp
exp
Definition: drawFromPickle.py:36
yodamerge_tmp.scale
scale
Definition: yodamerge_tmp.py:138
x
#define x
Athena::getMessageSvc
IMessageSvc * getMessageSvc(bool quiet=false)
Definition: getMessageSvc.cxx:20
CaloDetDescrManager.h
Definition of CaloDetDescrManager.
drawFromPickle.atan
atan
Definition: drawFromPickle.py:36
CaloDetDescrElement::eta_raw
float eta_raw() const
cell eta_raw
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:350
ParticleJetTools::p3
Amg::Vector3D p3(const xAOD::TruthVertex *p)
Definition: ParticleJetLabelCommon.cxx:55
CaloDetDescrElement::dz
float dz() const
cell dz
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:379
ActsCaloTrackingVolumeBuilder::build_barrel
Acts::Volume build_barrel(double r, double dr, double eta, double deta, double phi, double dphi) const
Definition: ActsCaloTrackingVolumeBuilder.cxx:580
makeActsAthenaLogger
std::unique_ptr< const Acts::Logger > makeActsAthenaLogger(IMessageSvc *svc, const std::string &name, int level, std::optional< std::string > parent_name)
Definition: Tracking/Acts/ActsInterop/src/Logger.cxx:64
ActsCaloTrackingVolumeBuilder::cellFactory
std::vector< std::unique_ptr< Acts::Volume > > cellFactory() const
Definition: ActsCaloTrackingVolumeBuilder.cxx:698
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
z
#define z
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
CalibCoolCompareRT.up
up
Definition: CalibCoolCompareRT.py:109
PixelAthClusterMonAlgCfg.zmax
zmax
Definition: PixelAthClusterMonAlgCfg.py:176
test_pyathena.parent
parent
Definition: test_pyathena.py:15
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
ActsCaloTrackingVolumeBuilder::ActsCaloTrackingVolumeBuilder
ActsCaloTrackingVolumeBuilder(const std::string &type, const std::string &name, const IInterface *parent)
Definition: ActsCaloTrackingVolumeBuilder.cxx:34
Trk::negativeFaceXY
@ negativeFaceXY
Definition: BoundarySurfaceFace.h:32
drawFromPickle.tan
tan
Definition: drawFromPickle.py:36
CCVBBV
Acts::CutoutCylinderVolumeBounds::BoundValues CCVBBV
Definition: ActsCaloTrackingVolumeBuilder.cxx:32
Box
Acts::Volume::BoundingBox Box
Definition: ActsCaloTrackingVolumeBuilder.cxx:29
dot.dot
def dot(G, fn, nodesToHighlight=[])
Definition: dot.py:5
min
#define min(a, b)
Definition: cfImp.cxx:40
ActsCaloTrackingVolumeBuilder::build_endcap
Acts::Volume build_endcap(double z, double dz, double eta, double deta, double phi, double dphi) const
Definition: ActsCaloTrackingVolumeBuilder.cxx:510
python.PyKernel.detStore
detStore
Definition: PyKernel.py:41
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
CaloDetDescrBuilder.h
CaloDetDescrManager_Base::element_begin
calo_element_const_iterator element_begin() const
first element
Definition: CaloDetDescrManager.cxx:111
CaloDetDescrElement::x
float x() const
cell x
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:363
CVBBV
Acts::CylinderVolumeBounds::BoundValues CVBBV
Definition: ActsCaloTrackingVolumeBuilder.cxx:31
Trk::open
@ open
Definition: BinningType.h:40
makeTRTBarrelCans.dy
tuple dy
Definition: makeTRTBarrelCans.py:21
CaloDetDescrElement::dphi
float dphi() const
cell dphi
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:358
Trk::binR
@ binR
Definition: BinningType.h:50
ActsCaloTrackingVolumeBuilder::m_caloMgr
const CaloDetDescrManager * m_caloMgr
Definition: ActsCaloTrackingVolumeBuilder.h:64
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
Trk::index4
@ index4
Definition: BoundarySurfaceFace.h:51
y
#define y
CaloDetDescrManager
This class provides the client interface for accessing the detector description information common to...
Definition: CaloDetDescrManager.h:473
CaloDetDescrElement::dx
float dx() const
cell dx
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:375
CaloDetDescrElement::getSampling
CaloCell_ID::CaloSample getSampling() const
cell sampling
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:395
CaloDetDescrManager_Base::element_size
calo_element_vec_size element_size() const
total number of elements
Definition: CaloDetDescrManager.cxx:105
CaloDetDescrElement::z
float z() const
cell z
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:367
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
makeTRTBarrelCans.dx
tuple dx
Definition: makeTRTBarrelCans.py:20
ActsCaloTrackingVolumeBuilder::initialize
StatusCode initialize() override
Definition: ActsCaloTrackingVolumeBuilder.cxx:43
Trk::tubeOuterCover
@ tubeOuterCover
Definition: BoundarySurfaceFace.h:40
Trk::tubeInnerCover
@ tubeInnerCover
Definition: BoundarySurfaceFace.h:39
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
CaloLCW_tf.trf
trf
Definition: CaloLCW_tf.py:20
ReadHandle.h
Handle class for reading from StoreGate.
CaloDetDescrElement::r
float r() const
cell r
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:348
Logger.h
CaloDetDescrElement::dy
float dy() const
cell dy
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:377
NSWL1::globalToLocal
Polygon globalToLocal(const Polygon &pol, float z, const Trk::PlaneSurface &surf)
Definition: GeoUtils.cxx:103
readCCLHist.float
float
Definition: readCCLHist.py:83
buildCaloDetDescrNoAlign
std::unique_ptr< CaloDetDescrManager > buildCaloDetDescrNoAlign(ISvcLocator *svcLocator, IMessageSvc *msgSvc)
Definition: CaloDetDescrBuilder.cxx:791
PlotCalibFromCool.vmax
vmax
Definition: PlotCalibFromCool.py:697
CaloDetDescrElement::phi_raw
float phi_raw() const
cell phi_raw
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:352