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