ATLAS Offline Software
Loading...
Searching...
No Matches
ActsTrk::ItkBlueprintNodeBuilder Class Reference

Helper class to build the ItkBlueprint node It adds the system as a node to the Blueprint. More...

#include <ItkBlueprintNodeBuilder.h>

Inheritance diagram for ActsTrk::ItkBlueprintNodeBuilder:
Collaboration diagram for ActsTrk::ItkBlueprintNodeBuilder:

Public Member Functions

StatusCode initialize () override
std::shared_ptr< Acts::Experimental::BlueprintNode > buildBlueprintNode (const Acts::GeometryContext &gctx, std::shared_ptr< Acts::Experimental::BlueprintNode > &&child) override
 Build the Itk Blueprint Node.

Private Member Functions

void buildItkStripBlueprintNode (const Acts::GeometryContext &gctx, Acts::Experimental::BlueprintNode &node)
 Build the Itk Strip Blueprint Node.
void buildItkPixelBlueprintNode (const Acts::GeometryContext &gctx, Acts::Experimental::BlueprintNode &node)
 Build the Itk Pixel Blueprint Node.
void buildBeamPipeBlueprintNode (const Acts::GeometryContext &gctx, Acts::Experimental::BlueprintNode &node)
 Build the Beam Pipe Blueprint Node.

Private Attributes

const InDetDD::SiDetectorManagerm_itkPixelMgr {nullptr}
const InDetDD::SiDetectorManagerm_itkStripMgr {nullptr}
const BeamPipeDetectorManagerm_beamPipeMgr {nullptr}
std::shared_ptr< ActsElementVectorm_elementStore {nullptr}
Gaudi::Property< bool > m_doEndcapLayerMerging {this, "doEndcapLayerMerging", true}
Gaudi::Property< bool > m_buildBeamPipe {this, "buildBeamPipe", true}

Detailed Description

Helper class to build the ItkBlueprint node It adds the system as a node to the Blueprint.

Definition at line 24 of file ItkBlueprintNodeBuilder.h.

Member Function Documentation

◆ buildBeamPipeBlueprintNode()

void ActsTrk::ItkBlueprintNodeBuilder::buildBeamPipeBlueprintNode ( const Acts::GeometryContext & gctx,
Acts::Experimental::BlueprintNode & node )
private

Build the Beam Pipe Blueprint Node.

Parameters
gctxGeometry context
nodeThe node to add the beam pipe node to

Definition at line 753 of file ItkBlueprintNodeBuilder.cxx.

754 {
755
756
757 // Get beam pipe parameters from existing code
758 PVConstLink beamPipeTopVolume = m_beamPipeMgr->getTreeTop(0);
759 if (m_beamPipeMgr->getNumTreeTops() == 1) {
760 beamPipeTopVolume =
761 m_beamPipeMgr->getTreeTop(0)->getChildVol(0)->getChildVol(0);
762 }
763
764 const Amg::Transform3D beamPipeTransform{Amg::getTranslate3D(beamPipeTopVolume->getX().translation())};
765
766 // Extract radius similar to makeBeamPipeConfig
767 double beamPipeRadius = 20; // Default value
768
769 const GeoLogVol* beamPipeLogVolume = beamPipeTopVolume->getLogVol();
770 // This should always be set, but let's be safe
771 if (beamPipeLogVolume == nullptr) {
772 ATH_MSG_ERROR("Beam pipe volume has no log volume");
773 throw std::runtime_error("Beam pipe volume has no log volume");
774 }
775
776 // Get the geoShape and translate
777 const GeoTube* beamPipeTube =
778 dynamic_cast<const GeoTube*>(beamPipeLogVolume->getShape());
779 if (beamPipeTube == nullptr) {
780 ATH_MSG_ERROR("BeamPipeLogVolume was not of type GeoTube");
781 throw std::runtime_error{"BeamPipeLogVolume was not of type GeoTube"};
782 }
783
784 // Look for SectionC03 to get the actual radius
785 for (unsigned int i = 0; i < beamPipeTopVolume->getNChildVols(); i++) {
786 auto childName = beamPipeTopVolume->getNameOfChildVol(i);
787 if (childName != "SectionC03") {
788 continue; // Skip if not SectionC03
789 }
790 PVConstLink childTopVolume = beamPipeTopVolume->getChildVol(i);
791 const GeoLogVol* childLogVolume = childTopVolume->getLogVol();
792 const GeoTube* childTube =
793 dynamic_cast<const GeoTube*>(childLogVolume->getShape());
794 if (childTube) {
795 beamPipeRadius = 0.5 * (childTube->getRMax() + childTube->getRMin());
796 break;
797 }
798
799 }
800
801
803 "BeamPipe constructed from Database: translation (yes) - radius "
804 << (beamPipeTube ? "(yes)" : "(no)") << " - r = " << beamPipeRadius);
805
806 ATH_MSG_VERBOSE("BeamPipe shift estimated as : "
807 << beamPipeTransform.translation().transpose());
808
809 // Add to blueprint following pattern from blueprint_itk.py
810 node.withGeometryIdentifier([&](auto& geoId) {
811 geoId.setAllVolumeIdsTo(s_beamPipeVolumeId);
812
813 geoId.addMaterial("BeamPipe_Material", [&](auto& mat) {
814 mat.configureFace(OuterCylinder, {AxisRPhi, Bound, 20},
815 {AxisZ, Bound, 20});
816
817 // Add static volume for beam pipe
818 mat.addStaticVolume(beamPipeTransform,
819 std::make_shared<Acts::CylinderVolumeBounds>(
820 0, beamPipeRadius * 1_mm, 3 * 1_m),
821 "BeamPipe");
822 });
823 });
824}
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
const BeamPipeDetectorManager * m_beamPipeMgr
Amg::Transform3D getTranslate3D(const double X, const double Y, const double Z)
: Returns a shift transformation along an arbitrary axis
Eigen::Affine3d Transform3D

◆ buildBlueprintNode()

std::shared_ptr< Acts::Experimental::BlueprintNode > ActsTrk::ItkBlueprintNodeBuilder::buildBlueprintNode ( const Acts::GeometryContext & gctx,
std::shared_ptr< Acts::Experimental::BlueprintNode > && child )
override

Build the Itk Blueprint Node.

Parameters
gctxGeometry context
childThe child node which is added to the itk node.

Definition at line 217 of file ItkBlueprintNodeBuilder.cxx.

218 {
219
220 if(childNode) {
221 ATH_MSG_ERROR("Child node for the Calo should be null - no child expected");
222 throw std::runtime_error("Child node is not null");
223 }
224
225 auto itkNode = std::make_shared<Acts::Experimental::CylinderContainerBlueprintNode>("ItkNode", AxisR);
226
227 // Add the itk pixel to the node
228 buildItkPixelBlueprintNode(gctx, *itkNode);
229
230 // Add the itk strip to the node
231 buildItkStripBlueprintNode(gctx, *itkNode);
232
233 //Add the beam pipe to the node
234 if(m_buildBeamPipe) {
235
236 buildBeamPipeBlueprintNode(gctx, *itkNode);
237
238 }
239
240 return itkNode;
241}
void buildItkPixelBlueprintNode(const Acts::GeometryContext &gctx, Acts::Experimental::BlueprintNode &node)
Build the Itk Pixel Blueprint Node.
void buildItkStripBlueprintNode(const Acts::GeometryContext &gctx, Acts::Experimental::BlueprintNode &node)
Build the Itk Strip Blueprint Node.
void buildBeamPipeBlueprintNode(const Acts::GeometryContext &gctx, Acts::Experimental::BlueprintNode &node)
Build the Beam Pipe Blueprint Node.

◆ buildItkPixelBlueprintNode()

void ActsTrk::ItkBlueprintNodeBuilder::buildItkPixelBlueprintNode ( const Acts::GeometryContext & gctx,
Acts::Experimental::BlueprintNode & node )
private

Build the Itk Pixel Blueprint Node.

Parameters
gctxGeometry context
nodeThe node to add the pixel node to

Definition at line 243 of file ItkBlueprintNodeBuilder.cxx.

244 {
245
246 // Get ITkPixel parameters from detector manager
247 if (!m_itkPixelMgr) {
248 ATH_MSG_ERROR("ITkPixel manager not available");
249 throw std::runtime_error("ITkPixel manager not available");
250 }
251
252 ATH_MSG_DEBUG("Detector manager has "
253 << m_itkPixelMgr->getDetectorElementCollection()->size()
254 << " elements");
255
256 std::vector<std::shared_ptr<ActsDetectorElement>> elements;
257
259 for (const auto* element :
260 *m_itkPixelMgr->getDetectorElementCollection()) {
261 const InDetDD::SiDetectorElement* siDetElement =
262 dynamic_cast<const InDetDD::SiDetectorElement*>(element);
263 if (siDetElement == nullptr) {
264 ATH_MSG_ERROR("Detector element was nullptr");
265 throw std::runtime_error{"Corrupt detector element collection"};
266 }
267 elements.push_back(std::make_shared<ActsDetectorElement>(*siDetElement));
268 }
269 ATH_MSG_VERBOSE("Retrieved " << elements.size() << " elements");
270
271 // Copy to service level store to extend lifetime
272 m_elementStore->vector().insert(m_elementStore->vector().end(),
273 elements.begin(), elements.end());
274
275 // Create containers for inner and outer pixel parts
276 node.addMaterial("InnerPixelMaterial", [&](auto& mat) {
277 mat.configureFace(OuterCylinder, {AxisRPhi, Bound, 20}, {AxisZ, Bound, 20});
278
279 auto& innerPixelContainer = mat.addCylinderContainer("InnerPixel", AxisZ);
280
281 // Add barrel container
282 auto& barrelGeoId = innerPixelContainer.withGeometryIdentifier();
283 barrelGeoId.setAllVolumeIdsTo(s_innerPixelVolumeId)
284 .incrementLayerIds(1)
285 .sortBy([](auto& a, auto& b) {
286 auto& boundsA =
287 dynamic_cast<const Acts::CylinderVolumeBounds&>(a.volumeBounds());
288 auto& boundsB =
289 dynamic_cast<const Acts::CylinderVolumeBounds&>(b.volumeBounds());
290
291 using enum Acts::CylinderVolumeBounds::BoundValues;
292 double aMidR = (boundsA.get(eMinR) + boundsA.get(eMaxR)) / 2.0;
293 double bMidR = (boundsB.get(eMinR) + boundsB.get(eMaxR)) / 2.0;
294
295 return aMidR < bMidR;
296 });
297
298 auto& barrel = barrelGeoId.addCylinderContainer("InnerPixel_Brl", AxisR);
299 barrel.setAttachmentStrategy(AttachmentStrategy::Gap);
300 barrel.setResizeStrategy(ResizeStrategy::Gap);
301
302 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
303
304 for (auto& element : elements) {
305 IdentityHelper id = element->identityHelper();
306 if (id.bec() != 0) {
307 continue;
308 }
309
310 if (id.layer_disk() >= 2) {
311 continue;
312 }
313
314 int elementLayer = id.layer_disk();
315 layers[elementLayer].push_back(element->surface().getSharedPtr());
316 }
317
318 ATH_MSG_DEBUG("Adding " << layers.size() << " layers to InnerPixel barrel");
319
320 for (const auto& [ilayer, surfaces] : layers) {
321 ATH_MSG_DEBUG("- Layer " << ilayer << " has " << surfaces.size()
322 << " surfaces");
323
324 barrel.addMaterial(
325 std::format("InnerPixel_Brl_{}_Material", ilayer), [&](auto& lmat) {
326 // Innermost layer: outer cylinder, else inner cylinder
327 lmat.configureFace(OuterCylinder, {AxisRPhi, Bound, 40},
328 {AxisZ, Bound, 20});
329
330 // Add layer with surfaces
331 auto& layer =
332 lmat.addLayer(std::format("InnerPixel_Brl_{}", ilayer));
333
334 // Set navigation policy for efficient surface lookup
335 layer.setNavigationPolicyFactory(
336 Acts::NavigationPolicyFactory{}
337 .add<Acts::SurfaceArrayNavigationPolicy>(
338 Acts::SurfaceArrayNavigationPolicy::Config{
339 .layerType = Cylinder,
340 .bins = {30, 10}}) // @TODO: Improve this logic
341 .add<Acts::TryAllNavigationPolicy>(
342 Acts::TryAllNavigationPolicy::Config{.sensitives =
343 false})
344 .asUniquePtr());
345
346 layer.setSurfaces(surfaces);
347 layer.setEnvelope(Acts::ExtentEnvelope{{
348 .z = {5_mm, 5_mm},
349 .r = {2_mm, 2_mm},
350 }});
351 });
352 }
353
354 // Add endcap containers
355 for (int bec : {-2, 2}) { // Negative and positive endcaps
356 std::string s = bec > 0 ? "p" : "n";
357 auto& ecGeoId = innerPixelContainer.withGeometryIdentifier();
358 ecGeoId.setAllVolumeIdsTo(s_innerPixelVolumeId + std::floor(bec / 2))
359 .incrementLayerIds(1);
360 auto& ec = ecGeoId.addCylinderContainer("InnerPixel_" + s + "EC", AxisZ);
361 ec.setAttachmentStrategy(AttachmentStrategy::Gap);
362 ec.setResizeStrategy(ResizeStrategy::Expand);
363
364 std::map<std::tuple<int, int, int>,
365 std::vector<std::shared_ptr<Acts::Surface>>>
366 initialLayers{};
367
368 for (auto& element : elements) {
369 IdentityHelper id = element->identityHelper();
370 if (id.bec() * bec <= 0) {
371 continue; // Skip if not in the right endcap
372 }
373
374 if (id.layer_disk() >= 3) {
375 continue; // Only include first 3 disks for inner pixel
376 }
377
378 std::tuple<int, int, int> key{id.bec(), id.layer_disk(),
379 id.eta_module()};
380 initialLayers[key].push_back(element->surface().getSharedPtr());
381 }
382
383 ATH_MSG_DEBUG("Found " << initialLayers.size()
384 << " initial layers to InnerPixel " << s << "EC");
385
386 // Create proto layers from surfaces
387 std::vector<LayerData> protoLayers;
388 protoLayers.reserve(initialLayers.size());
389
390 for (const auto& [key, surfaces] : initialLayers) {
391 auto& layer = protoLayers.emplace_back(gctx, surfaces);
392 layer.protoLayer.envelope[AxisR] = {2_mm, 2_mm};
393 layer.protoLayer.envelope[AxisZ] = {1_mm, 1_mm};
394 }
395
396 // Sort by z position
397 std::ranges::sort(protoLayers,
398 [](const LayerData& a, const LayerData& b) {
399 return std::abs(a.protoLayer.medium(AxisZ)) <
400 std::abs(b.protoLayer.medium(AxisZ));
401 });
402
403 ATH_MSG_DEBUG("Found " << protoLayers.size() << " initial layers");
404
405 // Merge overlapping layers
406 std::vector<LayerData> mergedLayers;
408 mergedLayers = mergeLayers(gctx, std::move(protoLayers));
409 } else {
410 mergedLayers = std::move(protoLayers);
411 }
412
413 ATH_MSG_DEBUG("After merging: " << mergedLayers.size() << " layers");
414
415 // Create layers from merged proto layers
416 for (const auto [key, pl] : Acts::enumerate(mergedLayers)) {
417 ATH_MSG_DEBUG("- Layer " << key << " has " << pl.surfaces.size()
418 << " surfaces");
419
420 pl.protoLayer.medium(AxisZ);
421 auto layerName = std::format("InnerPixel_{}EC_{}", key, s);
422
423 auto addLayer = [&layerName, &pl](auto& parent) {
424 // Add layer with surfaces
425 auto& layer = parent.addLayer(layerName);
426
427 // Set navigation policy for efficient surface lookup
428 layer.setNavigationPolicyFactory(
429 Acts::NavigationPolicyFactory{}
430 .add<Acts::SurfaceArrayNavigationPolicy>(
431 Acts::SurfaceArrayNavigationPolicy::Config{
432 .layerType = Disc,
433 .bins = {30, 30}}) // @TODO: Improve this logic
434 .add<Acts::TryAllNavigationPolicy>(
435 Acts::TryAllNavigationPolicy::Config{.sensitives = false})
436 .asUniquePtr());
437
438 layer.setSurfaces(pl.surfaces);
439 layer.setEnvelope(Acts::ExtentEnvelope{{
440 .z = {1_mm, 1_mm},
441 .r = {2_mm, 2_mm},
442 }});
443 };
444
445 ATH_MSG_VERBOSE("Add inner pixel layer"
446 << key << " / " << mergedLayers.size()
447 << " at z = " << pl.protoLayer.medium(AxisZ));
448 if (key < mergedLayers.size() - 1) {
449 ATH_MSG_VERBOSE("Adding material for layer "
450 << layerName );
451 ec.addMaterial(layerName + "_Material", [&](auto& lmat) {
452 // Set binning for endcap layer
453 lmat.configureFace(bec < 0 ? NegativeDisc : PositiveDisc,
454 {AxisR, Bound, 40}, {AxisPhi, Bound, 40});
455 addLayer(lmat);
456 });
457 } else {
458 addLayer(ec);
459 }
460 }
461 }
462 });
463
464 // Add outer pixel part
465 node.addMaterial("OuterPixelMaterial", [&](auto& mat) {
466 mat.configureFace(OuterCylinder, {AxisRPhi, Bound, 20}, {AxisZ, Bound, 20});
467
468 auto& outerPixelContainer = mat.addCylinderContainer("OuterPixel", AxisZ);
469
470 // Add barrel container
471 auto& barrelGeoId = outerPixelContainer.withGeometryIdentifier();
472 barrelGeoId.setAllVolumeIdsTo(s_outerPixelVolumeId).incrementLayerIds(1);
473
474 auto& barrel = barrelGeoId.addCylinderContainer("OuterPixel_Brl", AxisR);
475 barrel.setAttachmentStrategy(AttachmentStrategy::Gap);
476 barrel.setResizeStrategy(ResizeStrategy::Gap);
477
478 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
479
480 for (auto& element : elements) {
481 IdentityHelper id = element->identityHelper();
482 if (id.bec() != 0) {
483 continue;
484 }
485
486 if (id.layer_disk() <= 1) {
487 continue;
488 }
489
490 int elementLayer = id.layer_disk();
491 layers[elementLayer].push_back(element->surface().getSharedPtr());
492 }
493
494 ATH_MSG_DEBUG("Adding " << layers.size() << " layers to OuterPixel barrel");
495
496 for (const auto& [ilayer, surfaces] : layers) {
497 ATH_MSG_DEBUG("- Layer " << ilayer << " has " << surfaces.size()
498 << " surfaces");
499
500 barrel.addMaterial(
501 std::format("OuterPixel_Brl_{}_Material", ilayer), [&](auto& lmat) {
502 // Innermost layer: outer cylinder, else inner cylinder
503 lmat.configureFace(OuterCylinder, {AxisRPhi, Bound, 40},
504 {AxisZ, Bound, 20});
505
506 // Add layer with surfaces
507 auto& layer =
508 lmat.addLayer("OuterPixel_Brl_" + std::to_string(ilayer));
509
510 // Set navigation policy for efficient surface lookup
511 layer.setNavigationPolicyFactory(
512 Acts::NavigationPolicyFactory{}
513 .add<Acts::SurfaceArrayNavigationPolicy>(
514 Acts::SurfaceArrayNavigationPolicy::Config{
515 .layerType = Cylinder,
516 .bins = {30, 10}}) // @TODO: Improve this logic
517 .add<Acts::TryAllNavigationPolicy>(
518 Acts::TryAllNavigationPolicy::Config{.sensitives =
519 false})
520 .asUniquePtr());
521
522 layer.setSurfaces(surfaces);
523 layer.setEnvelope(Acts::ExtentEnvelope{{
524 .z = {5_mm, 5_mm},
525 .r = {2_mm, 2_mm},
526 }});
527 });
528 }
529
530 constexpr static auto addEndcapLayer = [](auto& parent, const auto& name,
531 const auto& surfaces) {
532 parent.addLayer(name, [&surfaces](auto& layer) {
533 layer.setNavigationPolicyFactory(
534 Acts::NavigationPolicyFactory{}
535 .add<Acts::SurfaceArrayNavigationPolicy>(
536 Acts::SurfaceArrayNavigationPolicy::Config{
537 .layerType = Disc, .bins = {30, 30}})
538 .add<Acts::TryAllNavigationPolicy>(
539 Acts::TryAllNavigationPolicy::Config{.sensitives = false})
540 .asUniquePtr());
541
542 layer.setSurfaces(surfaces);
543 });
544 };
545
546 // Add outer pixel endcaps
547 for (int bec : {-2, 2}) { // Negative and positive endcaps
548 const std::string s = bec > 0 ? "p" : "n";
549
550 // R stacked Z rings
551
552 auto& ec_outer_geoId = outerPixelContainer.withGeometryIdentifier();
553 ec_outer_geoId
554 .setAllVolumeIdsTo(s_outerPixelVolumeId + std::floor(bec / 2))
555 .incrementLayerIds(1);
556
557 auto& ec_outer =
558 ec_outer_geoId.addCylinderContainer("OuterPixel_" + s + "EC", AxisR);
559
560 // Three groups of disks stacked in R
561 std::array diskGroups{std::pair{3, 4}, std::pair{6, 5}, std::pair{7, 8}};
562
563 for (size_t idx = 0; idx < diskGroups.size(); ++idx) {
564 auto [disk1, disk2] = diskGroups[idx];
565
566 auto& ec_stack = ec_outer.addCylinderContainer(
567 "OuterPixel_" + s + "EC_" + std::to_string(idx), AxisZ);
568
569 ec_stack.setAttachmentStrategy(AttachmentStrategy::Gap);
570 ec_stack.setResizeStrategy(ResizeStrategy::Expand);
571
572 // Group sensors by eta rings
573 std::map<std::tuple<int, int>,
574 std::vector<std::shared_ptr<Acts::Surface>>>
575 eta_rings;
576
577 for (auto& element : elements) {
578 IdentityHelper id = element->identityHelper();
579 if (id.bec() != bec ||
580 (id.layer_disk() != disk1 && id.layer_disk() != disk2)) {
581 continue;
582 }
583 std::tuple<int, int> key{id.layer_disk(), id.eta_module()};
584 eta_rings[key].push_back(element->surface().getSharedPtr());
585 }
586
587 ATH_MSG_DEBUG("Found " << eta_rings.size() << " eta rings in group "
588 << idx);
589
590 // Sort rings by absolute z position
591 std::vector<std::vector<std::shared_ptr<Acts::Surface>>> sorted_rings;
592 sorted_rings.reserve(eta_rings.size());
593 for (const auto& [key, surfaces] : eta_rings) {
594 sorted_rings.push_back(surfaces);
595 }
596
597 std::ranges::sort(sorted_rings, [&gctx](const auto& a, const auto& b) {
598 Acts::ProtoLayer pl_a(gctx, makeConstPtrVector(a));
599 Acts::ProtoLayer pl_b(gctx, makeConstPtrVector(b));
600 return std::abs(pl_a.min(AxisZ)) < std::abs(pl_b.min(AxisZ));
601 });
602
603 // Create layers from sorted rings
604 for (size_t i = 0; i < sorted_rings.size(); ++i) {
605 const auto& surfaces = sorted_rings[i];
606 auto layerName = "OuterPixel_" + s + "EC_" + std::to_string(idx) +
607 "_" + std::to_string(i);
608
609 if (i < sorted_rings.size() - 1) {
610 ec_stack.addMaterial(layerName + "_Material", [&](auto& mat) {
611 mat.configureFace(bec > 0 ? PositiveDisc : NegativeDisc,
612 {AxisR, Bound, 20}, {AxisPhi, Bound, 40});
613 addEndcapLayer(mat, layerName, surfaces);
614 });
615 } else {
616 addEndcapLayer(ec_stack, layerName, surfaces);
617 }
618 }
619 }
620 }
621 });
622
623}
#define ATH_MSG_DEBUG(x)
static Double_t a
const InDetDD::SiDetectorManager * m_itkPixelMgr
std::shared_ptr< ActsElementVector > m_elementStore
Gaudi::Property< bool > m_doEndcapLayerMerging
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
layers(flags, cells_name, *args, **kw)
Here we define wrapper functions to set up all of the standard corrections.
const std::string & layerName(LayerIndex index)
convert LayerIndex into a string
@ layer
Definition HitInfo.h:79

◆ buildItkStripBlueprintNode()

void ActsTrk::ItkBlueprintNodeBuilder::buildItkStripBlueprintNode ( const Acts::GeometryContext & gctx,
Acts::Experimental::BlueprintNode & node )
private

Build the Itk Strip Blueprint Node.

Parameters
gctxGeometry context
nodeThe node to add the strip node to

Definition at line 625 of file ItkBlueprintNodeBuilder.cxx.

626 {
627
628 // Get ITkStrip parameters from detector manager
629 if (!m_itkStripMgr) {
630 ATH_MSG_ERROR("ITkStrip manager not available");
631 throw std::runtime_error("ITkStrip manager not available");
632 }
633
634 ATH_MSG_DEBUG("Detector manager has "
635 << m_itkStripMgr->getDetectorElementCollection()->size()
636 << " elements");
637
638 std::vector<std::shared_ptr<ActsDetectorElement>> elements;
639
641 for (const auto* element :
642 *m_itkStripMgr->getDetectorElementCollection()) {
643 const InDetDD::SiDetectorElement* siDetElement =
644 dynamic_cast<const InDetDD::SiDetectorElement*>(element);
645 if (siDetElement == nullptr) {
646 ATH_MSG_ERROR("Detector element was nullptr");
647 throw std::runtime_error{"Corrupt detector element collection"};
648 }
649 elements.push_back(std::make_shared<ActsDetectorElement>(*siDetElement));
650 }
651 ATH_MSG_VERBOSE("Retrieved " << elements.size() << " elements");
652
653 // Copy to service level store to extend lifetime
654 m_elementStore->vector().insert(m_elementStore->vector().end(),
655 elements.begin(), elements.end());
656
657 // Create container for strip part
658 node.addMaterial("StripMaterial", [&](auto& mat) {
659 mat.configureFace(OuterCylinder, {AxisRPhi, Bound, 20}, {AxisZ, Bound, 20});
660
661 mat.addCylinderContainer("Strip", AxisZ, [&](auto& strips) {
662 // Add barrel container
663 strips.withGeometryIdentifier([this, &elements](auto& geoId) {
664 geoId.setAllVolumeIdsTo(s_stripVolumeId).incrementLayerIds(1);
665
666 geoId.addCylinderContainer(
667 "Strip_Brl", AxisR, [this, &elements](auto& barrel) {
668 barrel.setAttachmentStrategy(AttachmentStrategy::Gap);
669 barrel.setResizeStrategy(ResizeStrategy::Gap);
670
671 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>>
672 layers{};
673
674 for (auto& element : elements) {
675 IdentityHelper id = element->identityHelper();
676 if (id.bec() != 0) {
677 continue;
678 }
679
680 int elementLayer = id.layer_disk();
681 layers[elementLayer].push_back(
682 element->surface().getSharedPtr());
683 }
684
685 ATH_MSG_DEBUG("Adding " << layers.size()
686 << " layers to Strip barrel");
687
688 for (const auto& [ilayer, surfaces] : layers) {
689 ATH_MSG_DEBUG("- Layer " << ilayer << " has " << surfaces.size()
690 << " surfaces");
691 addStripBarrelLayer(barrel, ilayer, surfaces);
692 }
693 });
694 });
695
696 // Add endcap containers
697 for (int bec : {-2, 2}) { // Negative and positive endcaps
698 const std::string s = bec > 0 ? "p" : "n";
699
700 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
701
702 for (auto& element : elements) {
703 IdentityHelper id = element->identityHelper();
704 if (id.bec() * bec <= 0) {
705 continue; // Skip if not in the right endcap
706 }
707
708 layers[id.layer_disk()].push_back(element->surface().getSharedPtr());
709 }
710
711 ATH_MSG_DEBUG("Found " << layers.size() << " layers in Strip " << s
712 << "EC");
713
714 // Sort layers by absolute z position
715 std::vector<std::vector<std::shared_ptr<Acts::Surface>>> sorted_layers;
716 sorted_layers.reserve(layers.size());
717 for (const auto& [key, surfaces] : layers) {
718 sorted_layers.push_back(surfaces);
719 }
720
721 std::sort(sorted_layers.begin(), sorted_layers.end(),
722 [&gctx](const auto& a, const auto& b) {
723 Acts::ProtoLayer pl_a(gctx, makeConstPtrVector(a));
724 Acts::ProtoLayer pl_b(gctx, makeConstPtrVector(b));
725 return std::abs(pl_a.min(AxisZ)) <
726 std::abs(pl_b.min(AxisZ));
727 });
728
729 strips.withGeometryIdentifier([&sorted_layers, bec, &s](auto& geoId) {
730 geoId.setAllVolumeIdsTo(s_stripVolumeId + std::floor(bec / 2))
731 .incrementLayerIds(1);
732
733 geoId.addCylinderContainer(
734 "Strip_" + s + "EC", AxisZ, [&sorted_layers, bec, &s](auto& ec) {
735 ec.setAttachmentStrategy(AttachmentStrategy::Gap);
736 ec.setResizeStrategy(ResizeStrategy::Gap);
737
738 // Create layers from sorted layers
739 for (size_t i = 0; i < sorted_layers.size(); ++i) {
740 const auto& surfaces = sorted_layers[i];
741 auto layerName = "Strip_" + s + "EC_" + std::to_string(i);
742
743 addStripEndcapLayer(ec, bec, layerName, surfaces);
744 }
745 });
746 });
747 }
748
749 });
750 });
751 }
const InDetDD::SiDetectorManager * m_itkStripMgr
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.

◆ initialize()

StatusCode ActsTrk::ItkBlueprintNodeBuilder::initialize ( )
override

Definition at line 206 of file ItkBlueprintNodeBuilder.cxx.

206 {
207 ATH_CHECK(detStore()->retrieve(m_itkStripMgr, "ITkStrip"));
208 ATH_CHECK(detStore()->retrieve(m_itkPixelMgr, "ITkPixel"));
209 if(m_buildBeamPipe) {
210 ATH_CHECK(detStore()->retrieve(m_beamPipeMgr, "BeamPipe"));
211 }
212 m_elementStore = std::make_shared<ActsElementVector>();
213 return StatusCode::SUCCESS;
214
215}
#define ATH_CHECK
Evaluate an expression and check for errors.
retrieve(aClass, aKey=None)
Definition PyKernel.py:110

Member Data Documentation

◆ m_beamPipeMgr

const BeamPipeDetectorManager* ActsTrk::ItkBlueprintNodeBuilder::m_beamPipeMgr {nullptr}
private

Definition at line 44 of file ItkBlueprintNodeBuilder.h.

44{nullptr};

◆ m_buildBeamPipe

Gaudi::Property<bool> ActsTrk::ItkBlueprintNodeBuilder::m_buildBeamPipe {this, "buildBeamPipe", true}
private

Definition at line 50 of file ItkBlueprintNodeBuilder.h.

50{this, "buildBeamPipe", true}; // Flag to control beam pipe building

◆ m_doEndcapLayerMerging

Gaudi::Property<bool> ActsTrk::ItkBlueprintNodeBuilder::m_doEndcapLayerMerging {this, "doEndcapLayerMerging", true}
private

Definition at line 48 of file ItkBlueprintNodeBuilder.h.

48{this, "doEndcapLayerMerging", true}; // Flag to control endcap layer merging

◆ m_elementStore

std::shared_ptr<ActsElementVector> ActsTrk::ItkBlueprintNodeBuilder::m_elementStore {nullptr}
private

Definition at line 46 of file ItkBlueprintNodeBuilder.h.

46{nullptr};

◆ m_itkPixelMgr

const InDetDD::SiDetectorManager* ActsTrk::ItkBlueprintNodeBuilder::m_itkPixelMgr {nullptr}
private

Definition at line 40 of file ItkBlueprintNodeBuilder.h.

40{nullptr};

◆ m_itkStripMgr

const InDetDD::SiDetectorManager* ActsTrk::ItkBlueprintNodeBuilder::m_itkStripMgr {nullptr}
private

Definition at line 42 of file ItkBlueprintNodeBuilder.h.

42{nullptr};

The documentation for this class was generated from the following files: