From e8f702e7e746676c28cbdb12cbc7a824222f42c5 Mon Sep 17 00:00:00 2001 From: Stephen Nicholas Swatman <s.swatman@nikhef.nl> Date: Fri, 24 Jul 2020 09:48:18 +0000 Subject: [PATCH] Create an interface for boundary checking tools In order to lift the bounds checking code from the hole search tool to a separate new tool, we must first create an interface for it. This interface is WIP and may change. --- .../InDetBoundaryCheckTool/CMakeLists.txt | 37 +++ .../InDetBoundaryCheckTool.h | 81 +++++ .../src/InDetBoundaryCheckTool.cxx | 296 ++++++++++++++++++ .../InDetBoundaryCheckTool_entries.cxx | 7 + .../TrkToolInterfaces/IBoundaryCheckTool.h | 31 ++ 5 files changed, 452 insertions(+) create mode 100644 InnerDetector/InDetRecTools/InDetBoundaryCheckTool/CMakeLists.txt create mode 100644 InnerDetector/InDetRecTools/InDetBoundaryCheckTool/InDetBoundaryCheckTool/InDetBoundaryCheckTool.h create mode 100644 InnerDetector/InDetRecTools/InDetBoundaryCheckTool/src/InDetBoundaryCheckTool.cxx create mode 100644 InnerDetector/InDetRecTools/InDetBoundaryCheckTool/src/components/InDetBoundaryCheckTool_entries.cxx create mode 100644 Tracking/TrkTools/TrkToolInterfaces/TrkToolInterfaces/IBoundaryCheckTool.h diff --git a/InnerDetector/InDetRecTools/InDetBoundaryCheckTool/CMakeLists.txt b/InnerDetector/InDetRecTools/InDetBoundaryCheckTool/CMakeLists.txt new file mode 100644 index 00000000000..8340c6d1b91 --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetBoundaryCheckTool/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +# Package: InDetBoundaryCheckTool + +# Declare the package name +atlas_subdir( + InDetBoundaryCheckTool +) + +# Declare the package's dependencies +atlas_depends_on_subdirs( + PUBLIC + Control/AthenaBaseComps + Tracking/TrkTools/TrkToolInterfaces + InnerDetector/InDetConditions/InDetConditionsSummaryService + InnerDetector/InDetDetDescr/InDetReadoutGeometry + InnerDetector/InDetRecToolInterfaces +) + +# Component(s) in the package: +atlas_add_component( + InDetBoundaryCheckTool + src/*.cxx + src/components/*.cxx + LINK_LIBRARIES + AthenaBaseComps + GaudiKernel + TrkParameters + TrkToolInterfaces + TrkTrack + InDetReadoutGeometry +) + +# Install files from the package: +atlas_install_headers( + InDetBoundaryCheckTool +) + diff --git a/InnerDetector/InDetRecTools/InDetBoundaryCheckTool/InDetBoundaryCheckTool/InDetBoundaryCheckTool.h b/InnerDetector/InDetRecTools/InDetBoundaryCheckTool/InDetBoundaryCheckTool/InDetBoundaryCheckTool.h new file mode 100644 index 00000000000..d5b041ac01f --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetBoundaryCheckTool/InDetBoundaryCheckTool/InDetBoundaryCheckTool.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ + +#ifndef ATHENA_INNERDETECTOR_TOOLS_BOUNDARYCHECKTOOL +#define ATHENA_INNERDETECTOR_TOOLS_BOUNDARYCHECKTOOL + +#include "AthenaBaseComps/AthAlgTool.h" + +#include "InDetConditionsSummaryService/IInDetConditionsTool.h" +#include "InDetReadoutGeometry/SiDetectorElement.h" +#include "InDetRecToolInterfaces/IInDetTestPixelLayerTool.h" + +#include "TrkParameters/TrackParameters.h" +#include "TrkToolInterfaces/IBoundaryCheckTool.h" + +#include "GeoModelInterfaces/IGeoModelSvc.h" + +namespace InDet { + class InDetBoundaryCheckTool : public AthAlgTool, virtual public Trk::IBoundaryCheckTool { + public: + InDetBoundaryCheckTool( + const std::string &, + const std::string &, + const IInterface * + ); + + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + + virtual Trk::BoundaryCheckResult boundaryCheck( + const Trk::TrackParameters & + ) const override; + private: + bool isAlivePixel( + const InDetDD::SiDetectorElement &element, + const Trk::TrackParameters ¶meters + ) const; + + bool isAliveSCT( + const InDetDD::SiDetectorElement &element, + const Trk::TrackParameters ¶meters + ) const; + + bool isBadSCTChipStrip( + const Identifier &, + const Trk::TrackParameters &, + const InDetDD::SiDetectorElement & + ) const; + + Trk::BoundaryCheckResult boundaryCheckSiElement( + const InDetDD::SiDetectorElement &, + const Trk::TrackParameters & + ) const; + + ServiceHandle<IGeoModelSvc> m_geoModelSvc; + + ToolHandle<IInDetConditionsTool> m_sctCondSummaryTool{ + this, + "SctSummaryTool", + "SCT_ConditionsSummaryTool/InDetSCT_ConditionsSummaryTool", + "Tool to retrieve SCT Conditions summary" + }; + ToolHandle<IInDetTestPixelLayerTool> m_pixelLayerTool; + + const AtlasDetectorID *m_atlasId; + + /** eta and phi tolerances **/ + Gaudi::Property<double> m_etaTol = 3.0; + Gaudi::Property<double> m_phiTol = 3.0; + + /** Control usage of pixel and SCT info */ + Gaudi::Property<bool> m_usePixel; + Gaudi::Property<bool> m_useSCT; + + /** Control check of bad SCT chip (should be false for ITk Strip) */ + Gaudi::Property<bool> m_checkBadSCT; + }; +} + +#endif diff --git a/InnerDetector/InDetRecTools/InDetBoundaryCheckTool/src/InDetBoundaryCheckTool.cxx b/InnerDetector/InDetRecTools/InDetBoundaryCheckTool/src/InDetBoundaryCheckTool.cxx new file mode 100644 index 00000000000..52e6de3ac1d --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetBoundaryCheckTool/src/InDetBoundaryCheckTool.cxx @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ + +#include "TrkToolInterfaces/IBoundaryCheckTool.h" +#include "TrkParameters/TrackParameters.h" +#include "InDetBoundaryCheckTool/InDetBoundaryCheckTool.h" +#include "GeoModelInterfaces/IGeoModelSvc.h" + +InDet::InDetBoundaryCheckTool::InDetBoundaryCheckTool( + const std::string& t, + const std::string& n, + const IInterface* p +): + AthAlgTool(t, n, p), + m_geoModelSvc("GeoModelSvc", n), + m_pixelLayerTool("InDet::InDetTestPixelLayerTool"), + m_atlasId(nullptr) +{ + declareInterface<IBoundaryCheckTool>(this); + declareProperty("GeoModelService", m_geoModelSvc); + declareProperty("PixelLayerTool", m_pixelLayerTool); +} + +StatusCode InDet::InDetBoundaryCheckTool::initialize() { + StatusCode sc = AlgTool::initialize(); + + if (sc.isFailure()) return sc; + + ATH_CHECK(detStore()->retrieve(m_atlasId, "AtlasID")); + + ATH_CHECK(m_pixelLayerTool.retrieve(DisableTool{!m_usePixel.value()})); + ATH_CHECK(m_sctCondSummaryTool.retrieve(DisableTool{!m_useSCT.value()})); + + if (m_checkBadSCT.value()) { + /* + * Check if ITk Strip is used because isBadSCTChipStrip method is + * valid only for SCT. + */ + ATH_CHECK(m_geoModelSvc.retrieve()); + + if (m_geoModelSvc->geoConfig()==GeoModel::GEO_RUN4 or + m_geoModelSvc->geoConfig()==GeoModel::GEO_ITk) { + m_checkBadSCT.set(false); + ATH_MSG_WARNING("Since ITk Strip is used, m_check_bad_sct is turned off."); + } + } + + ATH_MSG_INFO("InDeTBoundaryCheckTool::initialize() successful in " << name()); + return StatusCode::SUCCESS; +} + +StatusCode InDet::InDetBoundaryCheckTool::finalize() { + return AlgTool::finalize(); +} + +bool InDet::InDetBoundaryCheckTool::isAlivePixel( + [[maybe_unused]] const InDetDD::SiDetectorElement &element, + const Trk::TrackParameters ¶meters +) const { + return m_pixelLayerTool->expectHit(¶meters); +} + +bool InDet::InDetBoundaryCheckTool::isAliveSCT( + const InDetDD::SiDetectorElement &element, + const Trk::TrackParameters ¶meters +) const { + if (m_checkBadSCT.value() && isBadSCTChipStrip(element.identify(), parameters, element)) { + return false; + } + + return m_sctCondSummaryTool->isGood(element.identifyHash()); +} + +Trk::BoundaryCheckResult InDet::InDetBoundaryCheckTool::boundaryCheckSiElement( + const InDetDD::SiDetectorElement &siElement, + const Trk::TrackParameters ¶meters +) const { + /* + * We're supporting SCT and Pixel elements. Some of the checking code can + * be shared, and some of it is different for these detector types. This + * method will perform all the shared checks that apply to both SCTs and + * pixels. + */ + double phitol; + double etatol; + + /* + * We set our \phi and \eta tolerances by scaling the configured value in + * the tool's parameters by the standard deviation of the relative + * positions. If we do not have a covariance matrix to gather these \sigma + * values from, we use default parameters of 2.5 for \phi and 5.0 for + * \eta. + */ + if (parameters.covariance() != nullptr) { + /* + * From the covariance matrix, we grab the diagonal to get the + * variance vector. Then, if we take the component-wise square root + * of that, we get a vector of \sigma. Then all we need to do is use + * the right indexes to retrieve the values for \eta and \phi. + */ + Eigen::Matrix<double, 5, 1> var = parameters.covariance()->diagonal().cwiseSqrt(); + etatol = m_etaTol.value() * var(Trk::iEta); + phitol = m_phiTol.value() * var(Trk::iPhi); + } else { + /* + * If we don't have the covariance matrix, set our defaults. In the + * future, these two default values could be lifted into separate + * configuration parameters. + */ + phitol = 2.5; + etatol = 5.0; + } + + /* + * First, we check whether the local position on the silicon element is + * near the bonding gap of the module, which is insensitive. For this, we + * can simply delegate to the SiDetectorElement::newBondGap() method. + * + * Keen-eyed readers may note that bond gaps are only relevant for SCT + * modules and that Pixels do not have them. Therefore, we can technically + * consider this a check relevant only to SCTs. However, as this logic is + * abstracted into the SiDetectorElement class, we will treat is as a + * shared property and a shared check. + */ + if (siElement.nearBondGap(parameters.localPosition(), etatol)) { + ATH_MSG_VERBOSE( + "Track parameter on bond gap within " << etatol << ", so hit " << + "is on an insensitive part of the element." + ); + return Trk::BoundaryCheckResult::Insensitive; + } + + /* + * Next, we determine whether the hit is in the active region of the + * element using the SiDetectorElement::inDetector() method followed by + * the SiIntersect::in() method. + */ + InDetDD::SiIntersect intersection = siElement.inDetector( + parameters.localPosition(), phitol, etatol + ); + bool isActiveElement = intersection.in(); + + if (!isActiveElement) { + /* + * In this case, we are _not_ inside the active region of the element, + * but we may still want to determine if the element is active at all. + * First though, we handle a few edge conditions that may still lead + * to an inactive region result. + */ + ATH_MSG_VERBOSE( + "Track parameter not inside (active?) detector within " << + phitol << " " << etatol << ", but check for dead module anyway" + ); + + /* + * Next, we check the precision of our tolerances. If the tolerances + * are too high, which is to say higher than the defaults of 2.5 for + * \phi and 5.0 for \eta, we do an adjusted intersection check with + * the defaults. + */ + if (phitol > 2.5 || etatol > 5) { + /* + * If, after scaling back the parameters, we still don't hit the + * active region of the detector, we know for sure we are in an + * insensitive region. + */ + if (!siElement.inDetector(parameters.localPosition(), 2.5, 5.).in()) { + ATH_MSG_VERBOSE("Parameter position too close to inactive detector; abort search for dead module"); + return Trk::BoundaryCheckResult::Insensitive; + } + } else { + /* + * If our tolerances are sufficiently narrow, that is to say our + * hit is sufficiently accurate, and we don't have an intersection + * with the active region, we can conclude that we have hit an + * inactive zone. + */ + ATH_MSG_VERBOSE("Parameter precise enough and too close to inactive detector; abort search for dead module"); + return Trk::BoundaryCheckResult::Insensitive; + } + } + + Identifier id = siElement.identify(); + + bool alive; + + /* + * If we have not yet determined our hit to lie in any inactive region, we + * check whether the module hit is actually alive. For this, we deletage + * to two dedicated methods which essentially wrap external tools which + * know about element states. + */ + if (m_usePixel.value() && m_atlasId->is_pixel(id)) { + alive = isAlivePixel(siElement, parameters); + } else if (m_useSCT.value() && m_atlasId->is_sct(id)) { + alive = isAliveSCT(siElement, parameters); + } else { + ATH_MSG_WARNING("Unsupported identifier type!"); + return Trk::BoundaryCheckResult::Error; + } + + /* + * We now have all the necessary information to make a judgement about the + * track parameters. + */ + if (alive && isActiveElement) { + /* + * If the module is alive and we hit the active region on it, we know + * we have a good hit. Note that this is the only way we can return a + * Candidate result! It's the only success state. + */ + ATH_MSG_VERBOSE("Module is good, and we're hitting a sensitive part!"); + return Trk::BoundaryCheckResult::Candidate; + } else if (alive) { + /* + * If the module is alive, but we do not hit the sensitive part, we + * have another insensitive result. We've thrown a lot of those + * already, and this one is mostly meant to be a fall-back. + */ + ATH_MSG_VERBOSE("Track is hiting the insensitive part of a good module!"); + return Trk::BoundaryCheckResult::Insensitive; + } else { + /* + * Finally, if the module is not alive, we simply return a DeadElement + * result. + */ + ATH_MSG_VERBOSE("Track is hiting a bad module!"); + return Trk::BoundaryCheckResult::DeadElement; + } +} + +Trk::BoundaryCheckResult InDet::InDetBoundaryCheckTool::boundaryCheck( + const Trk::TrackParameters ¶meters +) const { + /* + * Retrieve the detector element associated with our track parameters. If + * such an element does not exist for whatever reason, return a negative + * result. + */ + const Trk::TrkDetElementBase *element = parameters.associatedSurface().associatedDetectorElement(); + + if (element == nullptr) { + return Trk::BoundaryCheckResult::Error; + } + + /* + * Try to see if detector element is a silicon element, otherwise return a + * negative result: this tool is not designed to work on non-silicon + * elements. + */ + const InDetDD::SiDetectorElement *siElement = dynamic_cast<const InDetDD::SiDetectorElement *>(element); + + if (siElement != nullptr) { + return boundaryCheckSiElement(*siElement, parameters); + } else { + ATH_MSG_DEBUG("TrackParameters do not belong to a type of element we can process"); + return Trk::BoundaryCheckResult::Error; + } +} + +bool InDet::InDetBoundaryCheckTool::isBadSCTChipStrip( + const Identifier &waferId, + const Trk::TrackParameters ¶meters, + const InDetDD::SiDetectorElement &siElement +) const { + // Check if the track passes through a bad SCT ABCD chip or a bad SCT strip. + // A chip and a strip are determined by the parameter position. + // Algorithm is based on InnerDetector/InDetMonitoring/SCT_Monitoring/src/SCTHitEffMonTool.cxx + + // Check the input. + if (!m_atlasId->is_sct(waferId)) { + ATH_MSG_ERROR(waferId << " is not an SCT Identifier"); + return true; + } + + // Get strip id from local position. + // Due to the limited position resolution, we may pick up a neighboring strip... + const Amg::Vector2D localPos(parameters.localPosition()); + const Identifier stripIdentifier(siElement.identifierOfPosition(localPos)); + + if (!m_atlasId->is_sct(stripIdentifier)) { + ATH_MSG_WARNING(stripIdentifier << " is not an SCT Identifier"); + return true; + } + + if (!m_sctCondSummaryTool->isGood(stripIdentifier, InDetConditions::SCT_CHIP)) { + // The position is on a bad chip. + return true; + } else if (!m_sctCondSummaryTool->isGood(stripIdentifier, InDetConditions::SCT_STRIP)) { + // The position is on a bad strip. (We may need to check neighboring strips.) + return true; + } + + return false; +} diff --git a/InnerDetector/InDetRecTools/InDetBoundaryCheckTool/src/components/InDetBoundaryCheckTool_entries.cxx b/InnerDetector/InDetRecTools/InDetBoundaryCheckTool/src/components/InDetBoundaryCheckTool_entries.cxx new file mode 100644 index 00000000000..14099dbef0b --- /dev/null +++ b/InnerDetector/InDetRecTools/InDetBoundaryCheckTool/src/components/InDetBoundaryCheckTool_entries.cxx @@ -0,0 +1,7 @@ +/* + * Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ + +#include "InDetBoundaryCheckTool/InDetBoundaryCheckTool.h" + +DECLARE_COMPONENT(InDet::InDetBoundaryCheckTool) diff --git a/Tracking/TrkTools/TrkToolInterfaces/TrkToolInterfaces/IBoundaryCheckTool.h b/Tracking/TrkTools/TrkToolInterfaces/TrkToolInterfaces/IBoundaryCheckTool.h new file mode 100644 index 00000000000..3e4a7f07566 --- /dev/null +++ b/Tracking/TrkTools/TrkToolInterfaces/TrkToolInterfaces/IBoundaryCheckTool.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ + +#ifndef ATHENA_TRK_TOOLS_INTERFACES_BOUNDARYCHECKTOOL +#define ATHENA_TRK_TOOLS_INTERFACES_BOUNDARYCHECKTOOL + +#include "GaudiKernel/IAlgTool.h" +#include "TrkParameters/TrackParameters.h" + +static const InterfaceID IID_IBoundaryCheckTool("Trk::IBoundaryCheckTool", 1, 0); + +namespace Trk { + enum class BoundaryCheckResult { + Candidate, + Insensitive, + DeadElement, + Error + }; + + class IBoundaryCheckTool : virtual public IAlgTool { + public: + virtual BoundaryCheckResult boundaryCheck(const Trk::TrackParameters &) const = 0; + + static const InterfaceID &interfaceID() { + return IID_IBoundaryCheckTool; + } + }; +} + +#endif -- GitLab