Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-01 07:53:40

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include "Acts/Plugins/GeoModel/GeoModelDetectorObjectFactory.hpp"
0010 
0011 #include "Acts/Detector/GeometryIdGenerator.hpp"
0012 #include "Acts/Detector/PortalGenerators.hpp"
0013 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0014 #include "Acts/Geometry/CutoutCylinderVolumeBounds.hpp"
0015 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0016 #include "Acts/Geometry/GeometryIdentifier.hpp"
0017 #include "Acts/Geometry/TrapezoidVolumeBounds.hpp"
0018 #include "Acts/Navigation/InternalNavigation.hpp"
0019 #include "Acts/Plugins/GeoModel/GeoModelConverters.hpp"
0020 #include "Acts/Plugins/GeoModel/IGeoShapeConverter.hpp"
0021 
0022 #include <algorithm>
0023 #include <iostream>
0024 #include <typeinfo>
0025 
0026 #include <GeoModelHelpers/GeoShapeUtils.h>
0027 #include <GeoModelKernel/GeoBox.h>
0028 #include <GeoModelKernel/GeoPcon.h>
0029 #include <GeoModelKernel/GeoShapeShift.h>
0030 #include <GeoModelKernel/GeoShapeSubtraction.h>
0031 #include <GeoModelKernel/GeoShapeUnion.h>
0032 #include <GeoModelKernel/GeoSimplePolygonBrep.h>
0033 #include <GeoModelKernel/GeoTrd.h>
0034 #include <GeoModelKernel/GeoTube.h>
0035 #include <GeoModelKernel/GeoTubs.h>
0036 
0037 namespace Acts {
0038 
0039 GeoModelDetectorObjectFactory::GeoModelDetectorObjectFactory(
0040     const Config &cfg, std::unique_ptr<const Logger> mlogger)
0041     : m_logger(std::move(mlogger)), m_cfg(cfg) {}
0042 
0043 void GeoModelDetectorObjectFactory::construct(Cache &cache,
0044                                               const GeometryContext &gctx,
0045                                               const GeoModelTree &geoModelTree,
0046                                               const Options &options) {
0047   if (geoModelTree.geoReader == nullptr) {
0048     throw std::invalid_argument("GeoModelTree has no GeoModelReader");
0049   }
0050   for (const auto &q : options.queries) {
0051     ACTS_VERBOSE("Constructing detector elements for query " << q);
0052     // load data from database according to querie (Muon)
0053     auto qFPV = geoModelTree.geoReader
0054                     ->getPublishedNodes<std::string, GeoFullPhysVol *>(q);
0055 
0056     /** Full physical volumes represent  logical detector units.*/
0057     for (const auto &[name, fpv] : qFPV) {
0058       FPVConstLink physVol{fpv};
0059       ACTS_INFO("Convert volume " << name);
0060       convertFpv(name, physVol, cache, gctx);
0061     }
0062   }
0063 }
0064 
0065 void GeoModelDetectorObjectFactory::convertSensitive(
0066     const PVConstLink &geoPV, const Transform3 &transform,
0067     SurfaceBoundFactory &boundFactory,
0068     std::vector<GeoModelSensitiveSurface> &sensitives) {
0069   const GeoLogVol *logVol = geoPV->getLogVol();
0070   const GeoShape *shape = logVol->getShape();
0071   int shapeId = shape->typeID();
0072   const std::string &name = logVol->getName();
0073   std::shared_ptr<const IGeoShapeConverter> converter =
0074       geoShapesConverters(shapeId);
0075   if (converter == nullptr) {
0076     throw std::runtime_error("The converter for " + printGeoShape(shape) +
0077                              " is a nullptr");
0078   }
0079 
0080   auto converted =
0081       converter->toSensitiveSurface(geoPV, transform, boundFactory);
0082   if (converted.ok()) {
0083     const auto &[el, sf] = converted.value();
0084 
0085     if (!el || !sf) {
0086       throw std::runtime_error(
0087           "The Detector Element or the Surface is a nullptr");
0088     }
0089     sensitives.push_back(converted.value());
0090     ACTS_VERBOSE("(successfully converted: "
0091                  << name << " / " << printGeoShape(shape) << " / "
0092                  << logVol->getMaterial()->getName() << ")");
0093     return;
0094   }
0095   ACTS_ERROR(name << " / " << printGeoShape(shape)
0096                   << " could not be converted by any converter");
0097 }
0098 
0099 std::vector<GeoChildNodeWithTrf>
0100 GeoModelDetectorObjectFactory::findAllSubVolumes(const PVConstLink &vol) const {
0101   /// Fetch the direct children of the volume
0102   std::vector<GeoChildNodeWithTrf> subvolumes = getChildrenWithRef(vol, false);
0103   std::vector<GeoChildNodeWithTrf> sensitives;
0104   sensitives.reserve(subvolumes.size());
0105   for (auto &subvolume : subvolumes) {
0106     /// Check whether material or GeoNameTag satisfy the user defined patterns
0107     if (matches(subvolume.nodeName, subvolume.volume)) {
0108       sensitives.push_back(subvolume);
0109     }
0110     /// If the volume has no children nothing can be done further
0111     if (subvolume.volume->getNChildVols() == 0) {
0112       continue;
0113     }
0114     /// Enter the next recursion level to check whether there're sensitive
0115     /// children
0116     std::vector<GeoChildNodeWithTrf> senssubsubvolumes =
0117         findAllSubVolumes(subvolume.volume);
0118     /* Append the found volumes to the output, but  update the transforms
0119      * of the nodes before. They're expressed with respect to their parent,
0120      * which is the grand child of the volume passed to the function call
0121      * -> apply on each grand child also the transform of the child. */
0122     std::transform(std::make_move_iterator(senssubsubvolumes.begin()),
0123                    std::make_move_iterator(senssubsubvolumes.end()),
0124                    std::back_inserter(sensitives),
0125                    [&subvolume](GeoChildNodeWithTrf &&volume) {
0126                      volume.transform = subvolume.transform * volume.transform;
0127                      return volume;
0128                    });
0129   }
0130   return sensitives;
0131 }
0132 
0133 bool GeoModelDetectorObjectFactory::convertBox(const std::string &name) const {
0134   auto convB = std::ranges::any_of(m_cfg.convertBox, [&](const auto &n) {
0135     return name.find(n) != std::string::npos;
0136   });
0137   return convB;
0138 }
0139 
0140 void GeoModelDetectorObjectFactory::convertFpv(const std::string &name,
0141                                                const FPVConstLink &fpv,
0142                                                Cache &cache,
0143                                                const GeometryContext &gctx) {
0144   const std::size_t prevSize = cache.sensitiveSurfaces.size();
0145   {
0146     /** Search all subvolumes that may be converted to sensitive surfaces */
0147     std::vector<GeoChildNodeWithTrf> subVolToTrf = findAllSubVolumes(fpv);
0148 
0149     std::vector<GeoModelSensitiveSurface> sensitives;
0150     sensitives.reserve(subVolToTrf.size());
0151 
0152     for (const auto &trfMe : subVolToTrf) {
0153       /** Align the surface with the global position of the detector */
0154       const Transform3 transform =
0155           fpv->getAbsoluteTransform() * trfMe.transform;
0156       convertSensitive(trfMe.volume, transform, *cache.surfBoundFactory,
0157                        sensitives);
0158     }
0159 
0160     if (sensitives.empty() && matches(name, fpv)) {
0161       convertSensitive(fpv, fpv->getAbsoluteTransform(),
0162                        *cache.surfBoundFactory, cache.sensitiveSurfaces);
0163     }
0164     cache.sensitiveSurfaces.insert(cache.sensitiveSurfaces.end(),
0165                                    std::make_move_iterator(sensitives.begin()),
0166                                    std::make_move_iterator(sensitives.end()));
0167     // Set the corresponding database entry name to all sensitive surfaces
0168     for (auto i = prevSize; i < cache.sensitiveSurfaces.size(); ++i) {
0169       const auto &detEl = std::get<0>(cache.sensitiveSurfaces[i]);
0170       detEl->setDatabaseEntryName(name);
0171       ACTS_VERBOSE("Set database name of the DetectorElement to "
0172                    << detEl->databaseEntryName());
0173     }
0174   }
0175   // Extract the bounding box surrounding the surface
0176   if (convertBox(name)) {
0177     auto volume = GeoModel::convertVolume(fpv->getAbsoluteTransform(),
0178                                           fpv->getLogVol()->getShape(),
0179                                           *cache.volumeBoundFactory);
0180 
0181     std::vector<std::shared_ptr<Surface>> surfacesToPut{};
0182     std::transform(cache.sensitiveSurfaces.begin() + prevSize,
0183                    cache.sensitiveSurfaces.end(),
0184                    std::back_inserter(surfacesToPut),
0185                    [](const GeoModelSensitiveSurface &sensitive) {
0186                      return std::get<1>(sensitive);
0187                    });
0188     // convert bounding boxes with surfaces inside
0189     auto volumeGen2 =
0190         GeoModel::convertDetectorVolume(gctx, *volume, name, surfacesToPut);
0191     cache.volumeBoxFPVs.emplace_back(std::make_tuple(volume, volumeGen2, fpv));
0192   }
0193 }
0194 // function to determine if object fits query
0195 bool GeoModelDetectorObjectFactory::matches(const std::string &name,
0196                                             const PVConstLink &physvol) const {
0197   if (m_cfg.nameList.empty() && m_cfg.materialList.empty()) {
0198     return true;
0199   }
0200 
0201   auto matchName = std::ranges::any_of(m_cfg.nameList, [&](const auto &n) {
0202     return name.find(n) != std::string::npos;
0203   });
0204 
0205   std::string matStr = physvol->getLogVol()->getMaterial()->getName();
0206 
0207   auto matchMaterial = std::ranges::any_of(
0208       m_cfg.materialList,
0209       [&](const auto &m) { return matStr.find(m) != std::string::npos; });
0210 
0211   bool match = matchMaterial && matchName;
0212 
0213   // for the fullphysvol we only check the name
0214   if (m_cfg.nameList.empty()) {
0215     return matchMaterial;
0216   }
0217 
0218   // if no material specified or we're looking at fpv judge by name only
0219   if (m_cfg.materialList.empty() ||
0220       dynamic_pointer_cast<const GeoVFullPhysVol>(physvol)) {
0221     return matchName;
0222   }
0223   return match;
0224 }
0225 }  // namespace Acts