From 99d43bd226d165f3f7d47a889d61868849aaef04 Mon Sep 17 00:00:00 2001 From: Andreas Salzburger Date: Fri, 16 Dec 2022 15:57:18 +0100 Subject: [PATCH 01/13] preparation work for the Geant4 detector --- Core/include/Acts/Geometry/CylinderLayer.hpp | 8 +- Core/include/Acts/Geometry/DiscLayer.hpp | 8 +- Core/include/Acts/Geometry/Extent.hpp | 22 +- .../KDTreeTrackingGeometryBuilder.hpp | 117 ++++++++++ Core/include/Acts/Geometry/ProtoDetector.hpp | 107 +++++++++ Core/include/Acts/Surfaces/Surface.hpp | 7 + Core/include/Acts/Utilities/BinUtility.hpp | 41 ++-- Core/include/Acts/Utilities/BinningData.hpp | 26 ++- Core/src/Geometry/CMakeLists.txt | 2 + Core/src/Geometry/Extent.cpp | 42 +++- .../KDTreeTrackingGeometryBuilder.cpp | 220 ++++++++++++++++++ Core/src/Geometry/ProtoDetector.cpp | 209 +++++++++++++++++ Core/src/Geometry/ProtoLayer.cpp | 4 +- Core/src/Surfaces/Surface.cpp | 7 + Tests/UnitTests/Core/Geometry/CMakeLists.txt | 1 + .../Core/Geometry/ProtoDetectorTests.cpp | 203 ++++++++++++++++ docs/core/geometry.md | 12 + 17 files changed, 998 insertions(+), 38 deletions(-) create mode 100644 Core/include/Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp create mode 100644 Core/include/Acts/Geometry/ProtoDetector.hpp create mode 100644 Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp create mode 100644 Core/src/Geometry/ProtoDetector.cpp create mode 100644 Tests/UnitTests/Core/Geometry/ProtoDetectorTests.cpp diff --git a/Core/include/Acts/Geometry/CylinderLayer.hpp b/Core/include/Acts/Geometry/CylinderLayer.hpp index 5ede214d416..489b974d9df 100644 --- a/Core/include/Acts/Geometry/CylinderLayer.hpp +++ b/Core/include/Acts/Geometry/CylinderLayer.hpp @@ -40,15 +40,15 @@ class CylinderLayer : public CylinderSurface, public Layer { /// @todo ApproachDescriptor to unique_ptr /// /// @return The return object is a shared poiter to the layer. - static MutableLayerPtr create( + static std::shared_ptr create( const Transform3& transform, const std::shared_ptr& cbounds, std::unique_ptr surfaceArray = nullptr, double thickness = 0., std::unique_ptr ad = nullptr, LayerType laytyp = passive) { - return MutableLayerPtr(new CylinderLayer(transform, cbounds, - std::move(surfaceArray), thickness, - std::move(ad), laytyp)); + return std::shared_ptr( + new CylinderLayer(transform, cbounds, std::move(surfaceArray), + thickness, std::move(ad), laytyp)); } CylinderLayer(const CylinderLayer& cla) = delete; diff --git a/Core/include/Acts/Geometry/DiscLayer.hpp b/Core/include/Acts/Geometry/DiscLayer.hpp index 913eec407fd..7d58d1a1b78 100644 --- a/Core/include/Acts/Geometry/DiscLayer.hpp +++ b/Core/include/Acts/Geometry/DiscLayer.hpp @@ -40,15 +40,15 @@ class DiscLayer : virtual public DiscSurface, public Layer { /// @todo move ApproachDescriptor to unqique_ptr /// /// @return a sharted pointer to the new layer - static MutableLayerPtr create( + static std::shared_ptr create( const Transform3& transform, const std::shared_ptr& dbounds, std::unique_ptr surfaceArray = nullptr, double thickness = 0., std::unique_ptr ad = nullptr, LayerType laytyp = Acts::passive) { - return MutableLayerPtr(new DiscLayer(transform, dbounds, - std::move(surfaceArray), thickness, - std::move(ad), laytyp)); + return std::shared_ptr( + new DiscLayer(transform, dbounds, std::move(surfaceArray), thickness, + std::move(ad), laytyp)); } DiscLayer() = delete; diff --git a/Core/include/Acts/Geometry/Extent.hpp b/Core/include/Acts/Geometry/Extent.hpp index 4ec8ecc4cd9..e7e086f4147 100644 --- a/Core/include/Acts/Geometry/Extent.hpp +++ b/Core/include/Acts/Geometry/Extent.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include namespace Acts { @@ -42,6 +43,12 @@ class Extent { /// Constructor with (optional) @param envelope Extent(const ExtentEnvelope& envelope = zeroEnvelopes); + /// Define a comparison operator + bool operator==(const Extent& e) const; + + /// Define a comparison operator + bool operator!=(const Extent& e) const { return (not operator==(e)); } + /// Extend with a position vertex /// /// @param vtx the vertex to be used for extending @@ -88,6 +95,16 @@ class Extent { const std::vector& bValues = s_binningValues, bool applyEnv = true); + /// Constrain an extent by another one, this is + /// - values that are already constrained are not touched + /// - values not constrained by @param rhs are not touched + /// - values that are constrained by the external one, but not + /// by the current one, are touched + /// @param envelope an envelope applied to the constrained value + /// + void addConstrain(const Extent& rhs, + const ExtentEnvelope& envelope = zeroEnvelopes); + /// Set a range for a dedicated binning value /// /// @param bValue the binning identification @@ -181,8 +198,9 @@ class Extent { bool constrains(BinningValue bValue = binValues) const; /// Convert to output stream for screen output - /// @param sl [in,out] The output stream - std::ostream& toStream(std::ostream& sl) const; + /// + /// @param indent indentation for the screen display + std::string toString(const std::string& indent = "") const; private: /// A bitset that remembers the constraint values diff --git a/Core/include/Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp b/Core/include/Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp new file mode 100644 index 00000000000..95139999416 --- /dev/null +++ b/Core/include/Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp @@ -0,0 +1,117 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2022 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/ProtoDetector.hpp" +#include "Acts/Geometry/TrackingGeometryBuilder.hpp" +#include "Acts/Utilities/KDTree.hpp" +#include "Acts/Utilities/Logger.hpp" + +#include +#include + +namespace Acts { + +class TrackingGeometry; +class Layer; +class LayerCreator; +class Surface; + +/// A Tracking Geometry builder restricted to cylindrical geometries +/// +/// It takes some helper tools and a vector of surface objects, +/// together with a ProtoDetector description that is used to query a +/// KDTree for contained surfaces in structures defined by the proto +/// volume. +class KDTreeTrackingGeometryBuilder : public ITrackingGeometryBuilder { + public: + /// Nested Configuration for this TrackingGeometryBuilder + struct Config { + /// The tracking volume helper for detector construction + std::shared_ptr trackingVolumeHelper = nullptr; + /// The layer crator - for sensitives + std::shared_ptr layerCreator = nullptr; + /// The created surfaces + std::vector> surfaces = {}; + /// The proto tracking geometry description + ProtoDetector protoDetector; + /// Optional geometry identfier hook to be used during closure + /// @note Will be @b copied when calling the geometry building + GeometryIdentifierHook geometryIdentifierHook; + /// For screen output + std::string hierarchyIndent = " "; + }; + + using SurfaceKDT = + KDTree<2u, std::shared_ptr, ActsScalar, std::array, 100>; + + /// Constructor + /// + /// @param [in] cgbConfig is the configuration struct for this builder + /// @param [in] logger logging instance + KDTreeTrackingGeometryBuilder( + const Config& cgbConfig, + std::unique_ptr logger = + getDefaultLogger("KDTreeTrackingGeometryBuilder", Logging::INFO)); + + /// Destructor + ~KDTreeTrackingGeometryBuilder() override = default; + + /// TrackingGeometry Interface method + /// + /// @param gctx geometry context of that building call + /// + /// @return a unique pointer to a TrackingGeometry + std::unique_ptr trackingGeometry( + const GeometryContext& gctx) const final; + + private: + /// Configuration member + Config m_cfg; + + /// Private access method to the logger + const Logger& logger() const { return *m_logger; } + + /// the logging instance + std::unique_ptr m_logger; + + /// Private construction cache + struct Cache { + size_t surfaceCounter = 0; + }; + + /// Translate a proto tracking volume into a Acts::TrackingVolume + /// + /// @param cCache is a cache used to extract the built detector elements + /// @param gctx is the current geometry context at building + /// @param kdt is the pre-filled kdt tree for the surface query + /// @param ptVolume the proto volume to be translated + /// @param indent is a screen output indentation + /// + /// @return a new tracking volume + std::shared_ptr translateVolume( + Cache& cCache, const GeometryContext& gctx, const SurfaceKDT& kdt, + const ProtoVolume& ptVolume, const std::string& indent = "") const; + + /// Translate a layer volume + /// + /// @param cCache is a cache used to extract the built detector elements + /// @param gctx is the current geometry context at building + /// @param kdt is the pre-filled kdt tree for the surface query + /// @param plVolume the proto volume representaion a layer to be translated + /// @param indent is a screen output indentation + /// + /// @return a new tracking volume + std::shared_ptr translateLayer( + Cache& cCache, const GeometryContext& gctx, const SurfaceKDT& kdt, + const ProtoVolume& plVolume, const std::string& indent = "") const; +}; + +} // namespace Acts diff --git a/Core/include/Acts/Geometry/ProtoDetector.hpp b/Core/include/Acts/Geometry/ProtoDetector.hpp new file mode 100644 index 00000000000..86dff6f8d9e --- /dev/null +++ b/Core/include/Acts/Geometry/ProtoDetector.hpp @@ -0,0 +1,107 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2022 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Geometry/Extent.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "Acts/Utilities/BinningData.hpp" + +#include + +namespace Acts { + +/// A proto volume description being used to define an overall +/// structure of either a TrackingVolume or Experimental::DetectorVolume +struct ProtoVolume { + /// Name of the proto volume + std::string name = ""; + /// The extent of this layer + Extent extent; + /// Boolean to indicate this is a container, needed for legacy + bool layerContainer = false; + + /// Set the layer type to indicate the layer volume + Acts::Surface::SurfaceType layerType = Acts::Surface::SurfaceType::Other; + /// The surface binninng fo the layer + std::vector layerSurfaceBinning = {}; + + /// Internal structure container + std::vector constituentVolumes = {}; + /// The constituent binning if this a container + std::vector constituentBinning = {}; + + /// Define an operator== + /// + /// @param pv the proto volume to be checked + bool operator==(const ProtoVolume& pv) const; + + /// Harmonize the detector information, this can run in two + /// modes, steered by the @param legacy boolean + /// + /// The legacy mode prepares everything for `Acts::TrackingVolume`, + /// if off it creates a description for `Acts::Detector`. + void harmonize(bool legacy = true); + + /// Extend the tracking volume with the its own constituents, + /// upwards here means that extens are promoted to the mother + /// + /// @param pVolume the protoVolume + void extendUp(ProtoVolume& pVolume); + + /// Extend the tracking volume with the its own constituents + /// @param bValue the binning value that is propagated + void propagateMinDown(BinningValue bValue); + + /// Extend the tracking volume with the its own constituents + /// @param bValue the binning value that is propagated + void propagateMaxDown(BinningValue bValue); + + /// Constrain the daughter volumes with this volume + /// + /// @param pVolume is the proto volume from which the constrain + /// is taken + void constrainDown(const ProtoVolume& pVolume); + + /// Write the tracking volume to screen + /// @param indent the current indentation + std::string toString(const std::string& indent = "") const; +}; + +/// A proto detector description being used to define an overall +/// structure of either a TrackingGeometry or Experimental::Detector +struct ProtoDetector { + std::string name = ""; + ProtoVolume worldVolume; + + /// Harmonize the detector information, this can run in two + /// modes, steered by the @param legacy boolean + /// + /// The legacy mode prepares everything for `Acts::TrackingVolume`, + /// if off it creates a description for `Acts::Detector`. + /// + void harmonize(bool legacy = true) { + worldVolume.extendUp(worldVolume); + worldVolume.constrainDown(worldVolume); + worldVolume.harmonize(legacy); + } + + /// Define an operator== + /// + /// @param pd the proto detector to be checked + bool operator==(const ProtoDetector& pd) const { + return (name == pd.name and worldVolume == pd.worldVolume); + } + + /// Write the tracking volume to screen + /// @param indent the current indentation + std::string toString(const std::string& indent = "") const; +}; + +} // namespace Acts diff --git a/Core/include/Acts/Surfaces/Surface.hpp b/Core/include/Acts/Surfaces/Surface.hpp index b8e2abca4ef..b4fd97ff4cb 100644 --- a/Core/include/Acts/Surfaces/Surface.hpp +++ b/Core/include/Acts/Surfaces/Surface.hpp @@ -25,6 +25,8 @@ #include "Acts/Utilities/Result.hpp" #include +#include +#include namespace Acts { @@ -402,6 +404,11 @@ class Surface : public virtual GeometryObject, virtual std::ostream& toStream(const GeometryContext& gctx, std::ostream& sl) const; + /// Output into a std::string + /// + /// @param gctx The current geometry context object, e.g. alignment + std::string toString(const GeometryContext& gctx) const; + /// Return properly formatted class name virtual std::string name() const = 0; diff --git a/Core/include/Acts/Utilities/BinUtility.hpp b/Core/include/Acts/Utilities/BinUtility.hpp index b71dd887079..56cd01a1f41 100644 --- a/Core/include/Acts/Utilities/BinUtility.hpp +++ b/Core/include/Acts/Utilities/BinUtility.hpp @@ -11,6 +11,7 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/Utilities/BinningData.hpp" #include "Acts/Utilities/BinningType.hpp" +#include "Acts/Utilities/Enumerate.hpp" #include #include @@ -303,31 +304,31 @@ class BinUtility { /// Output Method for std::ostream, to be overloaded by child classes /// /// @param sl is the ostream to be dumped into - std::ostream& toStream(std::ostream& sl) const { - sl << "BinUtility for " << m_binningData.size() + /// @param indent the current indentation + /// + /// @return the input stream + std::ostream& toStream(std::ostream& sl, + const std::string& indent = "") const { + sl << indent << "BinUtility for " << m_binningData.size() << "- dimensional array:" << std::endl; - std::vector::const_iterator bdIter = m_binningData.begin(); - for (size_t ibd = 0; bdIter != m_binningData.end(); ++bdIter, ++ibd) { - sl << "dimension : " << ibd << std::endl; - sl << " - type : " << size_t((*bdIter).type) << std::endl; - sl << " - option : " << size_t((*bdIter).option) << std::endl; - sl << " - value : " << size_t((*bdIter).binvalue) << std::endl; - sl << " - bins : " << (*bdIter).bins() << std::endl; - sl << " - min/max : " << (*bdIter).min << " / " << (*bdIter).max - << std::endl; - if ((*bdIter).type == equidistant) { - sl << " - step : " << (*bdIter).step << std::endl; - } - sl << " - boundaries : | "; - std::vector::const_iterator bIter = (*bdIter).boundaries().begin(); - for (; bIter != (*bdIter).boundaries().end(); ++bIter) { - sl << (*bIter) << " | "; - } - sl << std::endl; + for (auto [ibd, bd] : enumerate(m_binningData)) { + sl << indent << "dimension : " << ibd << std::endl; + sl << bd.toString(indent) << std::endl; } return sl; } + /// Output into a string + /// + /// @param indent the current indentation + /// + /// @return a string with the stream information + std::string toString(const std::string& indent = "") const { + std::stringstream ss; + toStream(ss, indent); + return ss.str(); + } + private: std::vector m_binningData; /// vector of BinningData Transform3 m_transform; /// shared transform diff --git a/Core/include/Acts/Utilities/BinningData.hpp b/Core/include/Acts/Utilities/BinningData.hpp index 6ab7cc0ec9a..f1cae0d854f 100644 --- a/Core/include/Acts/Utilities/BinningData.hpp +++ b/Core/include/Acts/Utilities/BinningData.hpp @@ -14,8 +14,9 @@ #include #include -#include #include +#include +#include #include #include @@ -523,5 +524,28 @@ class BinningData { return static_cast(std::distance(bData.m_boundaries.begin(), lb) - 1); } + + public: + /// String screen output methd + /// @param indent the current indentation + /// @return a string containing the screen information + std::string toString(const std::string& indent) const { + std::stringstream sl; + sl << indent << "BinngingData object:" << '\n'; + sl << indent << " - type : " << size_t(type) << '\n'; + sl << indent << " - option : " << size_t(option) << '\n'; + sl << indent << " - value : " << size_t(binvalue) << '\n'; + sl << indent << " - bins : " << bins() << '\n'; + sl << indent << " - min/max : " << min << " / " << max << '\n'; + if (type == equidistant) { + sl << indent << " - step : " << step << '\n'; + } + sl << indent << " - boundaries : | "; + for (const auto& b : boundaries()) { + sl << b << " | "; + } + sl << '\n'; + return sl.str(); + } }; } // namespace Acts diff --git a/Core/src/Geometry/CMakeLists.txt b/Core/src/Geometry/CMakeLists.txt index b0383771654..f2149857c6b 100644 --- a/Core/src/Geometry/CMakeLists.txt +++ b/Core/src/Geometry/CMakeLists.txt @@ -12,6 +12,7 @@ target_sources( CylinderVolumeBuilder.cpp CylinderVolumeHelper.cpp Extent.cpp + KDTreeTrackingGeometryBuilder.cpp Detector.cpp DetectorVolume.cpp DiscLayer.cpp @@ -28,6 +29,7 @@ target_sources( Polyhedron.cpp Portal.cpp ProtoLayer.cpp + ProtoDetector.cpp ProtoLayerHelper.cpp SurfaceArrayCreator.cpp TrackingGeometry.cpp diff --git a/Core/src/Geometry/Extent.cpp b/Core/src/Geometry/Extent.cpp index f450c383b1a..d287793b334 100644 --- a/Core/src/Geometry/Extent.cpp +++ b/Core/src/Geometry/Extent.cpp @@ -10,6 +10,8 @@ #include "Acts/Utilities/Helpers.hpp" +#include + Acts::Extent::Extent( const std::array, binValues>& envelope) : m_constrains(0), m_envelope(envelope) { @@ -73,6 +75,18 @@ void Acts::Extent::extend(const Extent& rhs, } } +void Acts::Extent::addConstrain(const Acts::Extent& rhs, + const ExtentEnvelope& envelope) { + for (const auto& bValue : s_binningValues) { + if (rhs.constrains(bValue) and not constrains(bValue)) { + const auto& cRange = rhs.range(bValue); + m_range[bValue].setMin(cRange.min() + envelope[bValue][0u]); + m_range[bValue].setMax(cRange.max() + envelope[bValue][1u]); + m_constrains.set(bValue); + } + } +} + void Acts::Extent::set(BinningValue bValue, ActsScalar min, ActsScalar max) { ActsScalar minval = min; if (bValue == binR and minval < 0.) { @@ -137,19 +151,37 @@ bool Acts::Extent::constrains(BinningValue bValue) const { return m_constrains.test(size_t(bValue)); } -std::ostream& Acts::Extent::toStream(std::ostream& sl) const { - sl << "Extent in space : " << std::endl; +bool Acts::Extent::operator==(const Extent& e) const { + if (m_constrains != e.m_constrains) { + return false; + } + if (m_envelope != e.m_envelope) { + return false; + } + if (not(m_range == e.m_range)) { + return false; + } + if (m_valueHistograms != e.m_valueHistograms) { + return false; + } + return true; +} + +std::string Acts::Extent::toString(const std::string& indent) const { + std::stringstream sl; + sl << indent << "Extent in space : " << std::endl; for (size_t ib = 0; ib < static_cast(binValues); ++ib) { if (constrains((BinningValue)ib)) { - sl << " - value :" << std::setw(10) << binningValueNames()[ib] + sl << indent << " - value :" << std::setw(10) << binningValueNames()[ib] << " | range = [" << m_range[ib].min() << ", " << m_range[ib].max() << "]" << std::endl; } } - return sl; + return sl.str(); } // Overload of << operator for std::ostream for debug output std::ostream& Acts::operator<<(std::ostream& sl, const Extent& rhs) { - return rhs.toStream(sl); + sl << rhs.toString(); + return sl; } diff --git a/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp b/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp new file mode 100644 index 00000000000..db1bab90755 --- /dev/null +++ b/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp @@ -0,0 +1,220 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2022 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp" + +#include "Acts/Geometry/CylinderLayer.hpp" +#include "Acts/Geometry/CylinderVolumeBounds.hpp" +#include "Acts/Geometry/DiscLayer.hpp" +#include "Acts/Geometry/Extent.hpp" +#include "Acts/Geometry/LayerCreator.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Geometry/TrackingVolume.hpp" +#include "Acts/Surfaces/CylinderBounds.hpp" +#include "Acts/Surfaces/RadialBounds.hpp" +#include "Acts/Surfaces/Surface.hpp" + +#include + +Acts::KDTreeTrackingGeometryBuilder::KDTreeTrackingGeometryBuilder( + const Acts::KDTreeTrackingGeometryBuilder::Config& cfg, + std::unique_ptr logger) + : m_cfg(cfg), m_logger(std::move(logger)) { + m_cfg.protoDetector.harmonize(); +} + +std::unique_ptr +Acts::KDTreeTrackingGeometryBuilder::trackingGeometry( + const GeometryContext& gctx) const { + using MeasuredSurface = + std::pair, std::shared_ptr>; + // Prepare all the surfaces + std::vector surfacesMeasured; + surfacesMeasured.reserve(m_cfg.surfaces.size()); + for (auto& s : m_cfg.surfaces) { + auto ext = s->polyhedronRepresentation(gctx, 1u).extent(); + surfacesMeasured.push_back(MeasuredSurface{ + std::array{ext.medium(binZ), ext.medium(binR)}, s}); + } + + // Create the KDTree + ACTS_INFO("Full KDTree has " << surfacesMeasured.size() << " surfaces."); + SurfaceKDT surfaceKDT(std::move(surfacesMeasured)); + + // Walk through the proto builder + auto protoWorld = m_cfg.protoDetector.worldVolume; + + KDTreeTrackingGeometryBuilder::Cache cCache; + + auto worldTrackingVolume = + translateVolume(cCache, gctx, surfaceKDT, protoWorld); + + ACTS_INFO("Retrieved " << cCache.surfaceCounter + << " surfaces from the KDTree."); + + // return the geometry to the service + return std::make_unique(worldTrackingVolume); +} + +std::shared_ptr +Acts::KDTreeTrackingGeometryBuilder::translateVolume( + Cache& cCache, const GeometryContext& gctx, const SurfaceKDT& kdt, + const ProtoVolume& ptVolume, const std::string& indent) const { + ACTS_DEBUG(indent << "Processing ProtoVolume: " << ptVolume.name); + std::vector> translatedVolumes = {}; + + if (not ptVolume.constituentVolumes.empty() and not ptVolume.layerContainer) { + ACTS_VERBOSE(indent << "> container volume with " + << ptVolume.constituentVolumes.size() + << " constituents."); + for (auto& cVolume : ptVolume.constituentVolumes) { + auto dtVolume = translateVolume(cCache, gctx, kdt, cVolume, + indent + m_cfg.hierarchyIndent); + translatedVolumes.push_back(dtVolume); + } + // Make a container volume + auto tVolume = m_cfg.trackingVolumeHelper->createContainerTrackingVolume( + gctx, translatedVolumes); + ACTS_DEBUG(indent << "> translated into container volume bounds: " + << tVolume->volumeBounds()); + return tVolume; + } + + std::vector> layers = {}; + if (not ptVolume.constituentVolumes.empty()) { + ACTS_VERBOSE(indent << "> layer volume with " + << ptVolume.constituentVolumes.size() + << " layer volumes."); + for (auto& plVolume : ptVolume.constituentVolumes) { + layers.push_back(translateLayer(cCache, gctx, kdt, plVolume, + indent + m_cfg.hierarchyIndent)); + } + ACTS_VERBOSE("> translated into " << layers.size() << " layers."); + // Create a volume + auto rangeR = ptVolume.extent.range(Acts::binR); + auto rangeZ = ptVolume.extent.range(Acts::binZ); + // Create a new tracking volume with those layers + auto tVolume = m_cfg.trackingVolumeHelper->createTrackingVolume( + gctx, layers, {}, nullptr, rangeR.min(), rangeR.max(), rangeZ.min(), + rangeZ.max(), ptVolume.name); + ACTS_DEBUG(indent << "> translated into bounds: " + << tVolume->volumeBounds()); + return tVolume; + } + return nullptr; +} + +/// @return a new tracking volume +std::shared_ptr +Acts::KDTreeTrackingGeometryBuilder::translateLayer( + Cache& cCache, const GeometryContext& gctx, const SurfaceKDT& kdt, + const ProtoVolume& plVolume, const std::string& indent) const { + ACTS_DEBUG(indent + "Processing ProtoVolume: " << plVolume.name); + // Try to pull from the kd tree + RangeXD<2u, ActsScalar> zrRange; + zrRange[0u] = plVolume.extent.range(Acts::binZ); + zrRange[1u] = plVolume.extent.range(Acts::binR); + + auto layerSurfaces = kdt.rangeSearchWithKey(zrRange); + ACTS_VERBOSE(indent + ">> looking z/r range = " << zrRange.toString()); + ACTS_VERBOSE(indent + ">> found " << layerSurfaces.size() + << " surfaces in the KDTree."); + cCache.surfaceCounter += layerSurfaces.size(); + + std::shared_ptr tLayer = nullptr; + + if (layerSurfaces.size() == 1u) { + auto surface = layerSurfaces[0u].second; + const auto& transform = surface->transform(gctx); + if (plVolume.layerType == Acts::Surface::SurfaceType::Cylinder) { + ACTS_VERBOSE(indent + + ">> creating cylinder layer from a single surface."); + // Get the bounds + auto cylinderBounds = + dynamic_cast(&(surface->bounds())); + auto cylinderBoundsClone = + std::make_shared(*cylinderBounds); + auto cylinderLayer = + CylinderLayer::create(transform, cylinderBoundsClone, nullptr, 1.); + cylinderLayer->assignSurfaceMaterial(surface->surfaceMaterialSharedPtr()); + tLayer = cylinderLayer; + } else if (plVolume.layerType == Acts::Surface::SurfaceType::Disc) { + ACTS_VERBOSE(indent + + ">> creating cylinder layer from a single surface."); + // Get the bounds + auto radialBounds = + dynamic_cast(&(surface->bounds())); + auto radialBoundsClone = + std::make_shared(*radialBounds); + auto discLayer = + DiscLayer::create(transform, radialBoundsClone, nullptr, 1.); + discLayer->assignSurfaceMaterial(surface->surfaceMaterialSharedPtr()); + tLayer = discLayer; + } + + } else if (layerSurfaces.size() > 1u) { + // Make a const collection out of the surfaces + std::vector> cLayerSurfaces; + cLayerSurfaces.reserve(layerSurfaces.size()); + for (const auto& s : layerSurfaces) { + cLayerSurfaces.push_back(s.second); + } + + Acts::BinningType bType0 = Acts::equidistant; + Acts::BinningType bType1 = Acts::equidistant; + std::size_t bins0 = 0; + std::size_t bins1 = 0; + // In case explicit binning is given + if (plVolume.layerSurfaceBinning.size()) { + bType0 = plVolume.layerSurfaceBinning[0u].type; + bType1 = plVolume.layerSurfaceBinning[1u].type; + // In case explicit bin numbers are given in addition + if (bType0 == Acts::equidistant and bType1 == Acts::equidistant and + plVolume.layerSurfaceBinning[0u].bins() > 1u and + plVolume.layerSurfaceBinning[1u].bins() > 1u) { + bins0 = plVolume.layerSurfaceBinning[0u].bins(); + bins1 = plVolume.layerSurfaceBinning[1u].bins(); + ACTS_VERBOSE(indent + ">> binning provided externally to be " + << bins0 << " x " << bins1 << "."); + } + } + + Acts::ProtoLayer pLayer(gctx, cLayerSurfaces); + if (plVolume.layerType == Acts::Surface::SurfaceType::Cylinder) { + ACTS_VERBOSE(indent + ">> creating cylinder layer with " + << cLayerSurfaces.size() << " surfaces."); + pLayer.envelope[binR] = {1., 1.}; + pLayer.envelope[binZ] = {2., 2.}; + // Forced equidistant or auto-binned + tLayer = (bins0 * bins1 > 0) + ? m_cfg.layerCreator->cylinderLayer(gctx, cLayerSurfaces, + bins0, bins1, pLayer) + : m_cfg.layerCreator->cylinderLayer(gctx, cLayerSurfaces, + bType0, bType1, pLayer); + + } else if (plVolume.layerType == Acts::Surface::SurfaceType::Disc) { + ACTS_VERBOSE(indent + ">> creating disc layer with " + << cLayerSurfaces.size() << " surfaces."); + pLayer.envelope[binR] = {2., 2.}; + pLayer.envelope[binZ] = {1., 1.}; + // Forced equidistant or auto-binned + tLayer = (bins0 * bins1 > 0) + ? m_cfg.layerCreator->discLayer(gctx, cLayerSurfaces, bins0, + bins1, pLayer) + + : m_cfg.layerCreator->discLayer(gctx, cLayerSurfaces, bType0, + bType1, pLayer); + } + } + if (tLayer != nullptr and tLayer->representingVolume() != nullptr) { + ACTS_DEBUG(indent << "> translated into layer bounds: " + << tLayer->representingVolume()->volumeBounds()); + } + + return tLayer; +} \ No newline at end of file diff --git a/Core/src/Geometry/ProtoDetector.cpp b/Core/src/Geometry/ProtoDetector.cpp new file mode 100644 index 00000000000..630c6112778 --- /dev/null +++ b/Core/src/Geometry/ProtoDetector.cpp @@ -0,0 +1,209 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2018-2020 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "Acts/Geometry/ProtoDetector.hpp" + +#include "Acts/Utilities/Enumerate.hpp" + +#include +#include + +void Acts::ProtoVolume::extendUp(Acts::ProtoVolume& ptVolume) { + ptVolume.extent.extend(extent); + + for (auto& cv : constituentVolumes) { + ptVolume.extent.extend(cv.extent); + cv.extendUp(ptVolume); + } +} + +void Acts::ProtoVolume::propagateMinDown(BinningValue bValue) { + for (auto& cv : constituentVolumes) { + cv.extent.set(bValue, extent.min(bValue), cv.extent.max(bValue)); + cv.propagateMinDown(bValue); + } +} + +void Acts::ProtoVolume::propagateMaxDown(BinningValue bValue) { + for (auto& cv : constituentVolumes) { + cv.extent.set(bValue, cv.extent.min(bValue), extent.max(bValue)); + cv.propagateMaxDown(bValue); + } +} + +void Acts::ProtoVolume::constrainDown(const Acts::ProtoVolume& ptVolume) { + extent.addConstrain(ptVolume.extent); + for (auto& cv : constituentVolumes) { + cv.extent.addConstrain(extent); + } +} + +void Acts::ProtoVolume::harmonize(bool legacy) { + std::vector otherConstrains; + + // Deal with the constituents + if (not constituentVolumes.empty()) { + if (constituentBinning.empty()) { + std::string errorMsg = std::string("ProtoVolume '") + name + + std::string("' with constituents, but no binning"); + throw std::runtime_error(errorMsg); + } + + // For legacy volumes, check if layers are present + bool layersPresent = layerContainer; + for (const auto& cv : constituentVolumes) { + layersPresent = + layersPresent or cv.layerType != Surface::SurfaceType::Other; + if (layersPresent) { + break; + } + } + + // If layers are present, it can't be a container in the legacy style + layerContainer = layersPresent; + auto binValue = constituentBinning[0].binvalue; + // Set the first last + auto& fVolume = *constituentVolumes.begin(); + auto& lVolume = constituentVolumes.back(); + + std::vector borders = {}; + + // The volumes should be harmonized in all other constraining values + for (auto obValue : s_binningValues) { + if (obValue != binValue and extent.constrains(obValue)) { + otherConstrains.push_back(obValue); + } + } + + // Legacy conversion - layers are kept untouched + if (not layerContainer) { + // Set the outer boundaries + fVolume.extent.set(binValue, extent.min(binValue), + fVolume.extent.max(binValue)); + lVolume.extent.set(binValue, lVolume.extent.min(binValue), + extent.max(binValue)); + // Align the containers + borders.push_back(static_cast(fVolume.extent.min(binValue))); + for (unsigned int iv = 1; iv < constituentVolumes.size(); ++iv) { + auto& lv = constituentVolumes[iv - 1u]; + ActsScalar zero = lv.extent.min(binValue); + ActsScalar low = lv.extent.max(binValue); + + auto& hv = constituentVolumes[iv]; + ActsScalar high = hv.extent.min(binValue); + ActsScalar mid = 0.5 * (low + high); + ActsScalar max = hv.extent.max(binValue); + lv.extent.set(binValue, zero, mid); + hv.extent.set(binValue, mid, max); + borders.push_back(mid); + } + borders.push_back(constituentVolumes.back().extent.max(binValue)); + + } else if (layerContainer and not legacy) { + // Count the gaps + std::size_t gaps = 0; + std::vector boundaries = {}; + // New container vector + std::vector updatedConstituents; + ActsScalar containerMin = extent.min(binValue); + if (fVolume.extent.min(binValue) > containerMin) { + ProtoVolume gap; + gap.name = name + "-gap-" + std::to_string(gaps++); + gap.extent.set(binValue, containerMin, fVolume.extent.min(binValue)); + updatedConstituents.push_back(gap); + borders.push_back(static_cast(containerMin)); + } + // Fill the gaps + for (unsigned int iv = 1; iv < constituentVolumes.size(); ++iv) { + auto& lv = constituentVolumes[iv - 1u]; + // This volume is one to save + updatedConstituents.push_back(lv); + borders.push_back(static_cast(lv.extent.min(binValue))); + // check if a gap to the next is needed + ActsScalar low = lv.extent.max(binValue); + auto& hv = constituentVolumes[iv]; + ActsScalar high = hv.extent.min(binValue); + if (high > low) { + ProtoVolume gap; + gap.name = name + "-gap-" + std::to_string(gaps++); + gap.extent.set(binValue, low, high); + updatedConstituents.push_back(gap); + borders.push_back(static_cast(low)); + } + } + ActsScalar constituentsMax = lVolume.extent.max(binValue); + updatedConstituents.push_back(lVolume); + borders.push_back(static_cast(constituentsMax)); + // Check the container min/max setting + ActsScalar containerMax = extent.max(binValue); + if (constituentsMax < containerMax) { + ProtoVolume gap; + gap.name = name + "-gap-" + std::to_string(gaps++); + gap.extent.set(binValue, constituentsMax, containerMax); + updatedConstituents.push_back(gap); + borders.push_back(static_cast(containerMax)); + } + constituentVolumes = updatedConstituents; + } else if (legacy and layerContainer) { + borders = {0., 1.}; + } + constituentBinning = { + BinningData(constituentBinning[0].option, binValue, borders)}; + } + + // Harmonize downwards + for (auto& cv : constituentVolumes) { + cv.extent.extend(extent, otherConstrains); + cv.harmonize(legacy); + } +} + +bool Acts::ProtoVolume::operator==(const Acts::ProtoVolume& pv) const { + // Simple checks + if (name != pv.name or extent != pv.extent or + layerContainer != pv.layerContainer or layerType != pv.layerType) { + return false; + } + if (layerSurfaceBinning != pv.layerSurfaceBinning) { + return false; + } + if (constituentVolumes != pv.constituentVolumes or + constituentBinning != pv.constituentBinning) { + return false; + } + return true; +} + +std::string Acts::ProtoVolume::toString(const std::string& indent) const { + std::string subIndent(" "); + std::stringstream ss; + ss << indent << "> volume: " << name << '\n'; + ss << indent << " extent: "; + ss << extent.toString(indent) << '\n'; + if (not constituentVolumes.empty()) { + ss << indent << " container of " << constituentVolumes.size() + << " constituents. " << '\n'; + ss << indent << " constituent binning:" << '\n'; + for (const auto& cb : constituentBinning) { + ss << cb.toString(indent) << '\n'; + } + ss << indent << " constituents are:" << '\n'; + for (auto cv : constituentVolumes) { + ss << cv.toString(indent + subIndent) << '\n'; + } + } + return ss.str(); +} + +std::string Acts::ProtoDetector::toString(const std::string& indent) const { + std::string subIndent(" "); + std::stringstream ss; + ss << indent << "> detector: " << name << '\n'; + ss << worldVolume.toString(indent + subIndent) << '\n'; + return ss.str(); +} \ No newline at end of file diff --git a/Core/src/Geometry/ProtoLayer.cpp b/Core/src/Geometry/ProtoLayer.cpp index 79ece698cf7..bf3cfa3a45b 100644 --- a/Core/src/Geometry/ProtoLayer.cpp +++ b/Core/src/Geometry/ProtoLayer.cpp @@ -35,7 +35,7 @@ ProtoLayer::ProtoLayer( double ProtoLayer::min(BinningValue bval, bool addenv) const { if (addenv) { - return extent.min(bval) - envelope[bval].first; + return extent.min(bval) - std::abs(envelope[bval].first); } return extent.min(bval); } @@ -57,7 +57,7 @@ double ProtoLayer::range(BinningValue bval, bool addenv) const { std::ostream& ProtoLayer::toStream(std::ostream& sl) const { sl << "ProtoLayer with dimensions (min/max)" << std::endl; - extent.toStream(sl); + sl << extent.toString(); return sl; } diff --git a/Core/src/Surfaces/Surface.cpp b/Core/src/Surfaces/Surface.cpp index 0267abd33fd..f907318237b 100644 --- a/Core/src/Surfaces/Surface.cpp +++ b/Core/src/Surfaces/Surface.cpp @@ -13,6 +13,7 @@ #include #include +#include #include Acts::Surface::Surface(const Transform3& transform) @@ -209,6 +210,12 @@ std::ostream& Acts::Surface::toStream(const GeometryContext& gctx, return sl; } +std::string Acts::Surface::toString(const GeometryContext& gctx) const { + std::stringstream ss; + toStream(gctx, ss); + return ss.str(); +} + bool Acts::Surface::operator!=(const Acts::Surface& sf) const { return !(operator==(sf)); } diff --git a/Tests/UnitTests/Core/Geometry/CMakeLists.txt b/Tests/UnitTests/Core/Geometry/CMakeLists.txt index e9109c4940e..3a96a126e4d 100644 --- a/Tests/UnitTests/Core/Geometry/CMakeLists.txt +++ b/Tests/UnitTests/Core/Geometry/CMakeLists.txt @@ -25,6 +25,7 @@ add_unittest(NavigationStateUpdators NavigationStateUpdatorsTests.cpp) add_unittest(PlaneLayer PlaneLayerTests.cpp) add_unittest(ProtoLayer ProtoLayerTests.cpp) add_unittest(ProtoLayerHelper ProtoLayerHelperTests.cpp) +add_unittest(ProtoDetector ProtoDetectorTests.cpp) add_unittest(Polyhedron PolyhedronTests.cpp) add_unittest(Portal PortalTests.cpp) add_unittest(PortalGenerators PortalGeneratorsTests.cpp) diff --git a/Tests/UnitTests/Core/Geometry/ProtoDetectorTests.cpp b/Tests/UnitTests/Core/Geometry/ProtoDetectorTests.cpp new file mode 100644 index 00000000000..17c570a9589 --- /dev/null +++ b/Tests/UnitTests/Core/Geometry/ProtoDetectorTests.cpp @@ -0,0 +1,203 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2020 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include + +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/ProtoDetector.hpp" +#include "Acts/Tests/CommonHelpers/FloatComparisons.hpp" + +#include +#include + +namespace { + +/// @brief This method creates a world volume with +/// some sub structure, this detector is not yet +/// syncrhonized, it can then be typed into the +/// Detector or the TrackGeometry description +/// +/// @return a proto world volume +Acts::ProtoDetector createProtoDetector() { + // Container + Acts::ProtoVolume detectorVolume; + detectorVolume.name = "detector-container"; + detectorVolume.extent.set(Acts::binZ, -2000., 2000); + + // Beam Pipe volume + Acts::ProtoVolume beamPipe; + beamPipe.name = "beam-pipe"; + beamPipe.extent.set(Acts::binR, 0., 30.); + + // Pixel section + Acts::ProtoVolume pixelContainer; + pixelContainer.name = "pixel-container"; + pixelContainer.extent.set(Acts::binR, 40., 200); + + // Pixel volume sub structure + Acts::ProtoVolume pixelNec; + pixelNec.name = "pixel-nec"; + pixelNec.extent.set(Acts::binZ, -1900., -600); + + Acts::ProtoVolume pixelBarrel; + pixelBarrel.name = "pixel-barrel"; + pixelBarrel.extent.set(Acts::binR, 41., 199.); + pixelBarrel.extent.set(Acts::binZ, -550., 550.); + + Acts::ProtoVolume pixelBarrelL0; + pixelBarrelL0.name = "pixel-barrel-l0"; + pixelBarrelL0.extent.set(Acts::binR, 45., 50.); + pixelBarrelL0.layerType = Acts::Surface::SurfaceType::Cylinder; + + Acts::ProtoVolume pixelBarrelL1; + pixelBarrelL1.name = "pixel-barrel-l1"; + pixelBarrelL1.extent.set(Acts::binR, 70., 80.); + pixelBarrelL1.layerType = Acts::Surface::SurfaceType::Cylinder; + + pixelBarrel.constituentVolumes = {pixelBarrelL0, pixelBarrelL1}; + pixelBarrel.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}; + + Acts::ProtoVolume pixelPec; + pixelPec.name = "pixel-pec"; + pixelPec.extent.set(Acts::binZ, 600., 1900.); + + pixelContainer.constituentVolumes = {pixelNec, pixelBarrel, pixelPec}; + pixelContainer.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; + + detectorVolume.constituentVolumes = {beamPipe, pixelContainer}; + detectorVolume.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binR, {0., 1})}; + + Acts::ProtoDetector detector; + detector.name = "detector"; + detector.worldVolume = detectorVolume; + + return detector; +} + +} // namespace + +namespace Acts { + +namespace Test { + +BOOST_AUTO_TEST_SUITE(Geometry) + +BOOST_AUTO_TEST_CASE(ProtoTrackingGeometryTests) { + // Get the raw proto detector description + auto detector = createProtoDetector(); + detector.harmonize(true); + + // Get the top detector volume + auto& detectorVolume = detector.worldVolume; + + // Check the container is NOT a layer Container + BOOST_CHECK(detectorVolume.layerContainer == false); + + // The detector volume should have received maximum dimensions + CHECK_CLOSE_ABS(detectorVolume.extent.min(Acts::binR), 0, + std::numeric_limits::epsilon()); + + CHECK_CLOSE_ABS(detectorVolume.extent.max(Acts::binR), 200., + std::numeric_limits::epsilon()); + + // The detector cotainer should have binning in R + BOOST_CHECK(detectorVolume.constituentBinning[0].type == Acts::arbitrary); + BOOST_CHECK(detectorVolume.constituentBinning[0].binvalue == Acts::binR); + + const auto& binBoundaries = detectorVolume.constituentBinning[0].boundaries(); + BOOST_CHECK(binBoundaries.size() == 3u); + CHECK_CLOSE_ABS(binBoundaries[0u], 0., + std::numeric_limits::epsilon()); + CHECK_CLOSE_ABS(binBoundaries[1u], 35., + std::numeric_limits::epsilon()); + CHECK_CLOSE_ABS(binBoundaries[2u], 200., + std::numeric_limits::epsilon()); + + // The first volume is the beam pipe, it should have gotten the + // the z dimension + auto& beamPipe = detectorVolume.constituentVolumes[0u]; + + BOOST_CHECK(beamPipe.name == "beam-pipe"); + CHECK_CLOSE_ABS(beamPipe.extent.min(Acts::binZ), -2000., + std::numeric_limits::epsilon()); + + CHECK_CLOSE_ABS(beamPipe.extent.max(Acts::binZ), 2000., + std::numeric_limits::epsilon()); + + // The new beam pipe radius should have been applied + CHECK_CLOSE_ABS(beamPipe.extent.max(Acts::binR), 35., + std::numeric_limits::epsilon()); + + // The second volume is the pixel detector + auto& pixelContainer = detectorVolume.constituentVolumes[1u]; + BOOST_CHECK(pixelContainer.name == "pixel-container"); + BOOST_CHECK(pixelContainer.layerContainer == false); + + // Pixel contaienr should have fitting boundaries + CHECK_CLOSE_ABS(pixelContainer.extent.min(Acts::binR), 35., + std::numeric_limits::epsilon()); + CHECK_CLOSE_ABS(pixelContainer.extent.max(Acts::binR), 200., + std::numeric_limits::epsilon()); + CHECK_CLOSE_ABS(pixelContainer.extent.min(Acts::binZ), -2000., + std::numeric_limits::epsilon()); + CHECK_CLOSE_ABS(pixelContainer.extent.max(Acts::binZ), 2000., + std::numeric_limits::epsilon()); + + // All of the internal containers should now have synchronized + // inner & outer boundaries + for (auto& pv : pixelContainer.constituentVolumes) { + CHECK_CLOSE_ABS(pv.extent.min(Acts::binR), 35., + std::numeric_limits::epsilon()); + + CHECK_CLOSE_ABS(pv.extent.max(Acts::binR), 200., + std::numeric_limits::epsilon()); + } + + // The binning should have been estimated + BOOST_CHECK(pixelContainer.constituentBinning[0].type == Acts::arbitrary); + BOOST_CHECK(pixelContainer.constituentBinning[0].binvalue == Acts::binZ); + + const auto& binBoundariesZ = + pixelContainer.constituentBinning[0].boundaries(); + BOOST_CHECK(binBoundariesZ.size() == 4u); + CHECK_CLOSE_ABS(binBoundariesZ[0u], -2000., + std::numeric_limits::epsilon()); + CHECK_CLOSE_ABS(binBoundariesZ[1u], -575, + std::numeric_limits::epsilon()); + CHECK_CLOSE_ABS(binBoundariesZ[2u], 575., + std::numeric_limits::epsilon()); + CHECK_CLOSE_ABS(binBoundariesZ[3u], 2000., + std::numeric_limits::epsilon()); + + auto& pixelNec = pixelContainer.constituentVolumes[0u]; + BOOST_CHECK(pixelNec.layerContainer == false); + + auto& pixelBarrel = pixelContainer.constituentVolumes[1u]; + BOOST_CHECK(pixelBarrel.layerContainer == true); + + auto& pixelPec = pixelContainer.constituentVolumes[2u]; + BOOST_CHECK(pixelPec.layerContainer == false); +} + +BOOST_AUTO_TEST_CASE(ProtoDetectorTests) { + // Get the raw proto detector description + auto detector = createProtoDetector(); + detector.harmonize(false); + + std::cout << detector.toString() << std::endl; +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace Test + +} // namespace Acts diff --git a/docs/core/geometry.md b/docs/core/geometry.md index ab8edfe0c77..12bab1e73c9 100644 --- a/docs/core/geometry.md +++ b/docs/core/geometry.md @@ -272,3 +272,15 @@ possible, they are *attached*. For cylindrical detector setups, a dedicated `CylinderVolumeBuilder` is provided, which performs a variety of volume building, packing and gluing. + + +## TrackingGeometry building using a KDTree and a Proto Description + +For cylindrical detectors there exist a generic tracking geometry building module, +based on KDTree and a proto description. + +This building procedure uses a `ProtoDetector` description which provides a +high level description of layers and container volumes, together with some +binning and ordering information. +This proto description is then used to assign surfaces that are provided to the +`KDTreeTrackingGeometryBuilder` using an internal query to the KD-tree structure. From b349dd84a420cda60263e3471a7ed1381c80e5c3 Mon Sep 17 00:00:00 2001 From: Andreas Salzburger Date: Fri, 16 Dec 2022 16:19:53 +0100 Subject: [PATCH 02/13] harmonize extent --- .../Acts/Geometry/CuboidVolumeBuilder.hpp | 2 +- Core/include/Acts/Geometry/ProtoDetector.hpp | 1 - Core/include/Acts/Geometry/ProtoLayer.hpp | 3 +- .../KDTreeTrackingGeometryBuilder.cpp | 5 +-- Core/src/Geometry/LayerCreator.cpp | 32 +++++++++---------- Core/src/Geometry/ProtoLayer.cpp | 4 +-- 6 files changed, 21 insertions(+), 26 deletions(-) diff --git a/Core/include/Acts/Geometry/CuboidVolumeBuilder.hpp b/Core/include/Acts/Geometry/CuboidVolumeBuilder.hpp index 37a16f011bc..5507428e7a7 100644 --- a/Core/include/Acts/Geometry/CuboidVolumeBuilder.hpp +++ b/Core/include/Acts/Geometry/CuboidVolumeBuilder.hpp @@ -72,7 +72,7 @@ class CuboidVolumeBuilder : public ITrackingVolumeBuilder { // Bins in Z direction size_t binsZ = 1; // Envelope in X (along layer normal) - std::pair envelopeX{0, 0}; + std::array envelopeX{0, 0}; std::optional rotation{std::nullopt}; }; diff --git a/Core/include/Acts/Geometry/ProtoDetector.hpp b/Core/include/Acts/Geometry/ProtoDetector.hpp index 86dff6f8d9e..aba3a690568 100644 --- a/Core/include/Acts/Geometry/ProtoDetector.hpp +++ b/Core/include/Acts/Geometry/ProtoDetector.hpp @@ -31,7 +31,6 @@ struct ProtoVolume { Acts::Surface::SurfaceType layerType = Acts::Surface::SurfaceType::Other; /// The surface binninng fo the layer std::vector layerSurfaceBinning = {}; - /// Internal structure container std::vector constituentVolumes = {}; /// The constituent binning if this a container diff --git a/Core/include/Acts/Geometry/ProtoLayer.hpp b/Core/include/Acts/Geometry/ProtoLayer.hpp index 15439d5b58a..cad4b6ef1bd 100644 --- a/Core/include/Acts/Geometry/ProtoLayer.hpp +++ b/Core/include/Acts/Geometry/ProtoLayer.hpp @@ -31,8 +31,7 @@ struct ProtoLayer { Extent extent; /// The envelope parameters - using Range = std::pair; - std::vector envelope{(int)binValues, {0., 0.}}; + ExtentEnvelope envelope = zeroEnvelopes; /// Constructor /// diff --git a/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp b/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp index db1bab90755..c2ace77619a 100644 --- a/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp +++ b/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp @@ -185,11 +185,10 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( } Acts::ProtoLayer pLayer(gctx, cLayerSurfaces); + pLayer.envelope = plVolume.extent.envelope(); if (plVolume.layerType == Acts::Surface::SurfaceType::Cylinder) { ACTS_VERBOSE(indent + ">> creating cylinder layer with " << cLayerSurfaces.size() << " surfaces."); - pLayer.envelope[binR] = {1., 1.}; - pLayer.envelope[binZ] = {2., 2.}; // Forced equidistant or auto-binned tLayer = (bins0 * bins1 > 0) ? m_cfg.layerCreator->cylinderLayer(gctx, cLayerSurfaces, @@ -200,8 +199,6 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( } else if (plVolume.layerType == Acts::Surface::SurfaceType::Disc) { ACTS_VERBOSE(indent + ">> creating disc layer with " << cLayerSurfaces.size() << " surfaces."); - pLayer.envelope[binR] = {2., 2.}; - pLayer.envelope[binZ] = {1., 1.}; // Forced equidistant or auto-binned tLayer = (bins0 * bins1 > 0) ? m_cfg.layerCreator->discLayer(gctx, cLayerSurfaces, bins0, diff --git a/Core/src/Geometry/LayerCreator.cpp b/Core/src/Geometry/LayerCreator.cpp index b9cf0e3db06..7492103a9e0 100644 --- a/Core/src/Geometry/LayerCreator.cpp +++ b/Core/src/Geometry/LayerCreator.cpp @@ -64,15 +64,15 @@ Acts::MutableLayerPtr Acts::LayerCreator::cylinderLayer( ACTS_VERBOSE(" - from R min/max = " << protoLayer.min(binR, false) << " / " << protoLayer.max(binR, false)); ACTS_VERBOSE(" - with R thickness = " << layerThickness); - ACTS_VERBOSE(" - incl envelope = " << protoLayer.envelope[binR].first + ACTS_VERBOSE(" - incl envelope = " << protoLayer.envelope[binR][0u] << " / " - << protoLayer.envelope[binR].second); + << protoLayer.envelope[binR][1u]); ACTS_VERBOSE(" - with z min/max = " << protoLayer.min(binZ, false) << " (-" - << protoLayer.envelope[binZ].first << ") / " + << protoLayer.envelope[binZ][0u] << ") / " << protoLayer.max(binZ, false) << " (+" - << protoLayer.envelope[binZ].second << ")"); + << protoLayer.envelope[binZ][1u] << ")"); ACTS_VERBOSE(" - z center = " << layerZ); ACTS_VERBOSE(" - halflength z = " << layerHalfZ); @@ -138,14 +138,14 @@ Acts::MutableLayerPtr Acts::LayerCreator::cylinderLayer( ACTS_VERBOSE(" - from R min/max = " << protoLayer.min(binR, false) << " / " << protoLayer.max(binR, false)); ACTS_VERBOSE(" - with R thickness = " << layerThickness); - ACTS_VERBOSE(" - incl envelope = " << protoLayer.envelope[binR].first + ACTS_VERBOSE(" - incl envelope = " << protoLayer.envelope[binR][0u] << " / " - << protoLayer.envelope[binR].second); + << protoLayer.envelope[binR][1u]); ACTS_VERBOSE(" - with z min/max = " << protoLayer.min(binZ, false) << " (-" - << protoLayer.envelope[binZ].first << ") / " + << protoLayer.envelope[binZ][0u] << ") / " << protoLayer.max(binZ, false) << " (+" - << protoLayer.envelope[binZ].second << ")"); + << protoLayer.envelope[binZ][1u] << ")"); ACTS_VERBOSE(" - z center = " << layerZ); ACTS_VERBOSE(" - halflength z = " << layerHalfZ); @@ -208,14 +208,14 @@ Acts::MutableLayerPtr Acts::LayerCreator::discLayer( ACTS_VERBOSE(" - from Z min/max = " << protoLayer.min(binZ, false) << " / " << protoLayer.max(binZ, false)); ACTS_VERBOSE(" - with Z thickness = " << layerThickness); - ACTS_VERBOSE(" - incl envelope = " << protoLayer.envelope[binZ].first + ACTS_VERBOSE(" - incl envelope = " << protoLayer.envelope[binZ][0u] << " / " - << protoLayer.envelope[binZ].second); + << protoLayer.envelope[binZ][1u]); ACTS_VERBOSE(" - with R min/max = " << protoLayer.min(binR, false) << " (-" - << protoLayer.envelope[binR].first << ") / " + << protoLayer.envelope[binR][0u] << ") / " << protoLayer.max(binR, false) << " (+" - << protoLayer.envelope[binR].second << ")"); + << protoLayer.envelope[binR][1u] << ")"); ACTS_VERBOSE(" - with phi min/max = " << protoLayer.min(binPhi, false) << " / " << protoLayer.max(binPhi, false)); @@ -272,14 +272,14 @@ Acts::MutableLayerPtr Acts::LayerCreator::discLayer( ACTS_VERBOSE(" - from Z min/max = " << protoLayer.min(binZ, false) << " / " << protoLayer.max(binZ, false)); ACTS_VERBOSE(" - with Z thickness = " << layerThickness); - ACTS_VERBOSE(" - incl envelope = " << protoLayer.envelope[binZ].first + ACTS_VERBOSE(" - incl envelope = " << protoLayer.envelope[binZ][0u] << " / " - << protoLayer.envelope[binZ].second); + << protoLayer.envelope[binZ][1u]); ACTS_VERBOSE(" - with R min/max = " << protoLayer.min(binR, false) << " (-" - << protoLayer.envelope[binR].first << ") / " + << protoLayer.envelope[binR][0u] << ") / " << protoLayer.max(binR, false) << " (+" - << protoLayer.envelope[binR].second << ")"); + << protoLayer.envelope[binR][1u] << ")"); ACTS_VERBOSE(" - with phi min/max = " << protoLayer.min(binPhi, false) << " / " << protoLayer.max(binPhi, false)); diff --git a/Core/src/Geometry/ProtoLayer.cpp b/Core/src/Geometry/ProtoLayer.cpp index bf3cfa3a45b..039ef8e62f3 100644 --- a/Core/src/Geometry/ProtoLayer.cpp +++ b/Core/src/Geometry/ProtoLayer.cpp @@ -35,14 +35,14 @@ ProtoLayer::ProtoLayer( double ProtoLayer::min(BinningValue bval, bool addenv) const { if (addenv) { - return extent.min(bval) - std::abs(envelope[bval].first); + return extent.min(bval) - std::abs(envelope[bval][0u]); } return extent.min(bval); } double ProtoLayer::max(BinningValue bval, bool addenv) const { if (addenv) { - return extent.max(bval) + envelope[bval].second; + return extent.max(bval) + envelope[bval][1u]; } return extent.max(bval); } From 2ace2a3b50e41665d5446b122589f91d1c2346ae Mon Sep 17 00:00:00 2001 From: Andreas Salzburger Date: Fri, 16 Dec 2022 16:37:35 +0100 Subject: [PATCH 03/13] proto detector json infrastructure --- Plugins/Json/CMakeLists.txt | 4 +- .../Acts/Plugins/Json/ExtentJsonConverter.hpp | 22 + .../Json/ProtoDetectorJsonConverter.hpp | 27 ++ .../Plugins/Json/UtilitiesJsonConverter.hpp | 13 + Plugins/Json/src/ExtentJsonConverter.cpp | 33 ++ .../Json/src/ProtoDetectorJsonConverter.cpp | 67 +++ Tests/UnitTests/Plugins/Json/CMakeLists.txt | 4 +- .../Plugins/Json/ExtentJsonConverterTests.cpp | 39 ++ .../Json/ProtoDetectorJsonConverterTests.cpp | 410 ++++++++++++++++++ .../Json/UtilitiesJsonConverterTests.cpp | 13 + 10 files changed, 630 insertions(+), 2 deletions(-) create mode 100644 Plugins/Json/include/Acts/Plugins/Json/ExtentJsonConverter.hpp create mode 100644 Plugins/Json/include/Acts/Plugins/Json/ProtoDetectorJsonConverter.hpp create mode 100644 Plugins/Json/src/ExtentJsonConverter.cpp create mode 100644 Plugins/Json/src/ProtoDetectorJsonConverter.cpp create mode 100644 Tests/UnitTests/Plugins/Json/ExtentJsonConverterTests.cpp create mode 100644 Tests/UnitTests/Plugins/Json/ProtoDetectorJsonConverterTests.cpp diff --git a/Plugins/Json/CMakeLists.txt b/Plugins/Json/CMakeLists.txt index 704bf670ef2..75e1cb5990f 100644 --- a/Plugins/Json/CMakeLists.txt +++ b/Plugins/Json/CMakeLists.txt @@ -2,9 +2,11 @@ include(ActsTargetLinkLibrariesSystem) add_library( ActsPluginJson SHARED - src/MaterialMapJsonConverter.cpp src/AlgebraJsonConverter.cpp + src/ExtentJsonConverter.cpp + src/MaterialMapJsonConverter.cpp src/MaterialJsonConverter.cpp + src/ProtoDetectorJsonConverter.cpp src/SurfaceBoundsJsonConverter.cpp src/SurfaceJsonConverter.cpp src/UtilitiesJsonConverter.cpp diff --git a/Plugins/Json/include/Acts/Plugins/Json/ExtentJsonConverter.hpp b/Plugins/Json/include/Acts/Plugins/Json/ExtentJsonConverter.hpp new file mode 100644 index 00000000000..149e7a3472f --- /dev/null +++ b/Plugins/Json/include/Acts/Plugins/Json/ExtentJsonConverter.hpp @@ -0,0 +1,22 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2022 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Geometry/Extent.hpp" +#include "Acts/Plugins/Json/ActsJson.hpp" + +// Custom Json encoder/decoders. Naming is mandated by nlohmann::json and thus +// can not match our naming guidelines. +namespace Acts { + +void to_json(nlohmann::json& j, const Extent& e); + +void from_json(const nlohmann::json& j, Extent& e); + +} // namespace Acts diff --git a/Plugins/Json/include/Acts/Plugins/Json/ProtoDetectorJsonConverter.hpp b/Plugins/Json/include/Acts/Plugins/Json/ProtoDetectorJsonConverter.hpp new file mode 100644 index 00000000000..9f8a3c08072 --- /dev/null +++ b/Plugins/Json/include/Acts/Plugins/Json/ProtoDetectorJsonConverter.hpp @@ -0,0 +1,27 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2022 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Geometry/ProtoDetector.hpp" +#include "Acts/Plugins/Json/UtilitiesJsonConverter.hpp" + +// Custom Json encoder/decoders. Naming is mandated by nlohmann::json and thus +// can not match our naming guidelines. + +namespace Acts { + +void to_json(nlohmann::json& j, const ProtoVolume& pv); + +void from_json(const nlohmann::json& j, ProtoVolume& pv); + +void to_json(nlohmann::json& j, const ProtoDetector& pd); + +void from_json(const nlohmann::json& j, ProtoDetector& pd); + +} // namespace Acts diff --git a/Plugins/Json/include/Acts/Plugins/Json/UtilitiesJsonConverter.hpp b/Plugins/Json/include/Acts/Plugins/Json/UtilitiesJsonConverter.hpp index ba9dddd62dd..31ba21bac6b 100644 --- a/Plugins/Json/include/Acts/Plugins/Json/UtilitiesJsonConverter.hpp +++ b/Plugins/Json/include/Acts/Plugins/Json/UtilitiesJsonConverter.hpp @@ -11,6 +11,7 @@ #include "Acts/Plugins/Json/ActsJson.hpp" #include "Acts/Utilities/BinUtility.hpp" #include "Acts/Utilities/BinningData.hpp" +#include "Acts/Utilities/Range1D.hpp" // Custom Json encoder/decoders. Naming is mandated by nlohmann::json and thus // can not match our naming guidelines. @@ -25,4 +26,16 @@ void to_json(nlohmann::json& j, const BinUtility& bu); void from_json(const nlohmann::json& j, BinUtility& bu); +template +void to_json(nlohmann::json& j, const Range1D& r) { + j["min"] = r.min(); + j["max"] = r.max(); +} + +template +void from_json(const nlohmann::json& j, Range1D& r) { + r.setMin(static_cast(j["min"])); + r.setMax(static_cast(j["max"])); +} + } // namespace Acts diff --git a/Plugins/Json/src/ExtentJsonConverter.cpp b/Plugins/Json/src/ExtentJsonConverter.cpp new file mode 100644 index 00000000000..1ae916e17ed --- /dev/null +++ b/Plugins/Json/src/ExtentJsonConverter.cpp @@ -0,0 +1,33 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2022 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "Acts/Plugins/Json/ExtentJsonConverter.hpp" + +#include "Acts/Plugins/Json/UtilitiesJsonConverter.hpp" +#include "Acts/Utilities/BinningData.hpp" +#include "Acts/Utilities/Enumerate.hpp" + +void Acts::to_json(nlohmann::json& j, const Acts::Extent& e) { + const auto bValueNames = binningValueNames(); + const auto& xrange = e.range(); + for (auto [ib, ibv] : enumerate(s_binningValues)) { + if (e.constrains(ibv)) { + const auto& r = xrange[ib]; + j[bValueNames[ib]] = r; + } + } +} + +void Acts::from_json(const nlohmann::json& j, Acts::Extent& e) { + const auto bValueNames = binningValueNames(); + for (auto [ib, bvn] : enumerate(bValueNames)) { + if (j.find(bvn) != j.end()) { + e.set(static_cast(ib), j[bvn]["min"], j[bvn]["max"]); + } + } +} \ No newline at end of file diff --git a/Plugins/Json/src/ProtoDetectorJsonConverter.cpp b/Plugins/Json/src/ProtoDetectorJsonConverter.cpp new file mode 100644 index 00000000000..6daf030bcd7 --- /dev/null +++ b/Plugins/Json/src/ProtoDetectorJsonConverter.cpp @@ -0,0 +1,67 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2022 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "Acts/Plugins/Json/ProtoDetectorJsonConverter.hpp" + +#include "Acts/Plugins/Json/ExtentJsonConverter.hpp" +#include "Acts/Plugins/Json/UtilitiesJsonConverter.hpp" +#include "Acts/Surfaces/Surface.hpp" + +void Acts::to_json(nlohmann::json& j, const Acts::ProtoVolume& pv) { + j["name"] = pv.name; + j["extent"] = pv.extent; + j["layerContainer"] = pv.layerContainer; + j["layerType"] = static_cast(pv.layerType); + + // Helper m ethod to write binnings + auto writeBinning = [&](const std::vector& binning, + const std::string& key) -> void { + nlohmann::json jbinning; + for (const auto& bd : binning) { + jbinning.push_back(bd); + } + j[key] = jbinning; + }; + writeBinning(pv.layerSurfaceBinning, "layerSurfaceBinning"); + nlohmann::json constituents; + for (const auto& pvc : pv.constituentVolumes) { + constituents.push_back(pvc); + } + j["constituents"] = constituents; + writeBinning(pv.constituentBinning, "constituentBinning"); +} + +void Acts::from_json(const nlohmann::json& j, Acts::ProtoVolume& pv) { + pv.name = j["name"]; + pv.extent = j["extent"]; + pv.layerContainer = j["layerContainer"]; + pv.layerType = static_cast(j["layerType"]); + + // Helper method to read binnings + auto readBinning = [&](std::vector& binning, + const std::string& key) -> void { + for (const auto& jbinning : j[key]) { + binning.push_back(jbinning); + } + }; + readBinning(pv.layerSurfaceBinning, "layerSurfaceBinning"); + for (const auto& jc : j["constituents"]) { + pv.constituentVolumes.push_back(jc); + } + readBinning(pv.constituentBinning, "constituentBinning"); +} + +void Acts::to_json(nlohmann::json& j, const Acts::ProtoDetector& pd) { + j["name"] = pd.name; + j["world"] = pd.worldVolume; +} + +void Acts::from_json(const nlohmann::json& j, Acts::ProtoDetector& pd) { + pd.name = j["name"]; + pd.worldVolume = j["world"]; +} diff --git a/Tests/UnitTests/Plugins/Json/CMakeLists.txt b/Tests/UnitTests/Plugins/Json/CMakeLists.txt index 61a2b344b2d..c59b4fa03e7 100644 --- a/Tests/UnitTests/Plugins/Json/CMakeLists.txt +++ b/Tests/UnitTests/Plugins/Json/CMakeLists.txt @@ -1,8 +1,10 @@ set(unittest_extra_libraries ActsPluginJson) +add_unittest(AlgebraJsonConverter AlgebraJsonConverterTests.cpp) +add_unittest(ExtentJsonConverter ExtentJsonConverterTests.cpp) add_unittest(GeometryHierarchyMapJsonConverter GeometryHierarchyMapJsonConverterTests.cpp) add_unittest(MaterialMapJsonConverter MaterialMapJsonConverterTests.cpp) -add_unittest(AlgebraJsonConverter AlgebraJsonConverterTests.cpp) +add_unittest(ProtoDetectorJsonConverter ProtoDetectorJsonConverterTests.cpp) add_unittest(UtilitiesJsonConverter UtilitiesJsonConverterTests.cpp) add_unittest(SurfaceBoundsJsonConverter SurfaceBoundsJsonConverterTests.cpp) add_unittest(SurfaceJsonConverter SurfaceJsonConverterTests.cpp) diff --git a/Tests/UnitTests/Plugins/Json/ExtentJsonConverterTests.cpp b/Tests/UnitTests/Plugins/Json/ExtentJsonConverterTests.cpp new file mode 100644 index 00000000000..813660424f9 --- /dev/null +++ b/Tests/UnitTests/Plugins/Json/ExtentJsonConverterTests.cpp @@ -0,0 +1,39 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2022 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include "Acts/Geometry/Extent.hpp" +#include "Acts/Plugins/Json/ActsJson.hpp" +#include "Acts/Plugins/Json/ExtentJsonConverter.hpp" +#include "Acts/Tests/CommonHelpers/FloatComparisons.hpp" + +#include +#include + +using namespace Acts; + +BOOST_AUTO_TEST_SUITE(ExtentJsonConverter) + +BOOST_AUTO_TEST_CASE(ExtentRoundtripTests) { + Extent e; + e.set(binR, 0, 200); + e.set(binZ, -50, 50); + + nlohmann::json j; + j["extent"] = e; + + Extent eIn = j["exent"]; + + CHECK_CLOSE_ABS(e.min(binR), 0., 10e-5); + CHECK_CLOSE_ABS(e.max(binR), 200., 10e-5); + CHECK_CLOSE_ABS(e.min(binZ), -50., 10e-5); + CHECK_CLOSE_ABS(e.max(binZ), 50., 10e-5); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/Tests/UnitTests/Plugins/Json/ProtoDetectorJsonConverterTests.cpp b/Tests/UnitTests/Plugins/Json/ProtoDetectorJsonConverterTests.cpp new file mode 100644 index 00000000000..b2b37c8098e --- /dev/null +++ b/Tests/UnitTests/Plugins/Json/ProtoDetectorJsonConverterTests.cpp @@ -0,0 +1,410 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2022 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include "Acts/Geometry/ProtoDetector.hpp" +#include "Acts/Plugins/Json/ActsJson.hpp" +#include "Acts/Plugins/Json/ProtoDetectorJsonConverter.hpp" +#include "Acts/Tests/CommonHelpers/FloatComparisons.hpp" + +#include +#include + +using namespace Acts; + +BOOST_AUTO_TEST_SUITE(ProtoDetectorJsonConverter) + +BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { + Acts::ExtentEnvelope cylinderLayerEnvelope = zeroEnvelopes; + cylinderLayerEnvelope[Acts::binR] = {1., 1.}; + cylinderLayerEnvelope[Acts::binZ] = {2., 2.}; + + Acts::ExtentEnvelope discLayerEnvelope = zeroEnvelopes; + discLayerEnvelope[Acts::binR] = {1., 1.}; + discLayerEnvelope[Acts::binZ] = {1., 1.}; + + // Beam Pipe container + Acts::ProtoVolume beamPipeContainer; + beamPipeContainer.name = "odd-beam-pipe"; + beamPipeContainer.extent.set(Acts::binR, 0., 25); + Acts::ProtoVolume beamPipe; + beamPipe.name = "odd-beam-pipe-l"; + beamPipe.extent.set(Acts::binR, 2., 24.); + beamPipe.layerType = Acts::Surface::SurfaceType::Cylinder; + beamPipeContainer.constituentVolumes = {beamPipe}; + beamPipeContainer.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}; + beamPipeContainer.layerContainer = true; + + // Pixel section + Acts::ProtoVolume pixelContainer; + pixelContainer.name = "odd-pixel"; + pixelContainer.extent.set(Acts::binR, 25., 200); + + Acts::ProtoVolume pixelNec; + pixelNec.name = "odd-pixel-nec"; + pixelNec.extent.set(Acts::binZ, -3100., -580); + + Acts::ProtoVolume pixNecD6; + pixNecD6.name = "odd-pixel-nec-d6"; + pixNecD6.extent.set(Acts::binZ, -1540., -1500); + Acts::ProtoVolume pixNecD5; + pixNecD5.name = "odd-pixel-nec-d5"; + pixNecD5.extent.set(Acts::binZ, -1340., -1300); + Acts::ProtoVolume pixNecD4; + pixNecD4.name = "odd-pixel-nec-d4"; + pixNecD4.extent.set(Acts::binZ, -1140., -1100); + Acts::ProtoVolume pixNecD3; + pixNecD3.name = "odd-pixel-nec-d3"; + pixNecD3.extent.set(Acts::binZ, -1000., -960.); + Acts::ProtoVolume pixNecD2; + pixNecD2.name = "odd-pixel-nec-d2"; + pixNecD2.extent.set(Acts::binZ, -860., -820); + Acts::ProtoVolume pixNecD1; + pixNecD1.name = "odd-pixel-nec-d1"; + pixNecD1.extent.set(Acts::binZ, -740., -700); + Acts::ProtoVolume pixNecD0; + pixNecD0.name = "odd-pixel-nec-d0"; + pixNecD0.extent.set(Acts::binZ, -640., -600); + pixelNec.constituentVolumes = {pixNecD6, pixNecD5, pixNecD4, pixNecD3, + pixNecD2, pixNecD1, pixNecD0}; + + Acts::BinningData pixEcBinningR = + Acts::BinningData(Acts::open, Acts::binR, 2., 0., 1.); + Acts::BinningData pixEcBinningPhi = + Acts::BinningData(Acts::closed, Acts::binPhi, 30., -M_PI, M_PI); + + pixelNec.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binZ, {0., 1.})}; + for (auto& cv : pixelNec.constituentVolumes) { + cv.layerType = Acts::Surface::SurfaceType::Disc; + cv.layerSurfaceBinning = {pixEcBinningR, pixEcBinningPhi}; + cv.extent.setEnvelope(discLayerEnvelope); + } + pixelNec.layerContainer = true; + + Acts::ProtoVolume pixelBarrel; + pixelBarrel.name = "odd-pixel-barrel"; + pixelBarrel.extent.set(Acts::binZ, -580., 580); + + Acts::ProtoVolume pixBarrelL0; + pixBarrelL0.name = "odd-pixel-barrel-l0"; + pixBarrelL0.extent.set(Acts::binR, 28., 48.); + pixBarrelL0.extent.set(Acts::binZ, -580., 580); + Acts::ProtoVolume pixBarrelL1; + pixBarrelL1.name = "odd-pixel-barrel-l1"; + pixBarrelL1.extent.set(Acts::binR, 62., 76); + pixBarrelL1.extent.set(Acts::binZ, -580., 580); + Acts::ProtoVolume pixBarrelL2; + pixBarrelL2.name = "odd-pixel-barrel-l2"; + pixBarrelL2.extent.set(Acts::binR, 100., 120.); + pixBarrelL2.extent.set(Acts::binZ, -580., 580); + Acts::ProtoVolume pixBarrelL3; + pixBarrelL3.name = "odd-pixel-barrel-l3"; + pixBarrelL3.extent.set(Acts::binR, 160., 180.); + pixBarrelL3.extent.set(Acts::binZ, -580., 580); + + pixelBarrel.constituentVolumes = {pixBarrelL0, pixBarrelL1, pixBarrelL2, + pixBarrelL3}; + for (auto& cv : pixelBarrel.constituentVolumes) { + cv.layerType = Acts::Surface::SurfaceType::Cylinder; + cv.extent.setEnvelope(cylinderLayerEnvelope); + } + + pixelBarrel.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binR, {0., 1})}; + pixelBarrel.layerContainer = true; + + Acts::ProtoVolume pixelPec; + pixelPec.name = "odd-pixel-pec"; + pixelPec.extent.set(Acts::binZ, 580., 3100.); + + Acts::ProtoVolume pixPecD0; + pixPecD0.name = "odd-pixel-pec-d0"; + pixPecD0.extent.set(Acts::binZ, 600., 640); + Acts::ProtoVolume pixPecD1; + pixPecD1.name = "odd-pixel-pec-d1"; + pixPecD1.extent.set(Acts::binZ, 700., 740); + Acts::ProtoVolume pixPecD2; + pixPecD2.name = "odd-pixel-pec-d2"; + pixPecD2.extent.set(Acts::binZ, 820., 860.); + Acts::ProtoVolume pixPecD3; + pixPecD3.name = "odd-pixel-pec-d3"; + pixPecD3.extent.set(Acts::binZ, 960., 1000.); + Acts::ProtoVolume pixPecD4; + pixPecD4.name = "odd-pixel-pec-d4"; + pixPecD4.extent.set(Acts::binZ, 1100., 1140); + Acts::ProtoVolume pixPecD5; + pixPecD5.name = "odd-pixel-pec-d5"; + pixPecD5.extent.set(Acts::binZ, 1300., 1340.); + Acts::ProtoVolume pixPecD6; + pixPecD6.name = "odd-pixel-pec-d6"; + pixPecD6.extent.set(Acts::binZ, 1500., 1540.); + + pixelPec.constituentVolumes = {pixPecD0, pixPecD1, pixPecD2, pixPecD3, + pixPecD4, pixPecD5, pixPecD6}; + pixelPec.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; + for (auto& cv : pixelPec.constituentVolumes) { + cv.layerType = Acts::Surface::SurfaceType::Disc; + cv.layerSurfaceBinning = {pixEcBinningR, pixEcBinningPhi}; + cv.extent.setEnvelope(discLayerEnvelope); + } + pixelPec.layerContainer = true; + + pixelContainer.constituentVolumes = {pixelNec, pixelBarrel, pixelPec}; + pixelContainer.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binZ, {-3100., -580., 580., 3100.})}; + + // Short Strip section + Acts::ProtoVolume pstContainer; + pstContainer.name = "odd-pst"; + pstContainer.extent.set(Acts::binR, 200., 210.); + Acts::ProtoVolume pst; + pst.name = "odd-pst-l"; + pst.extent.set(Acts::binR, 201., 209.); + pst.layerType = Acts::Surface::SurfaceType::Cylinder; + pstContainer.constituentVolumes = {pst}; + pstContainer.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}; + pstContainer.layerContainer = true; + + // Short Strip section + Acts::ProtoVolume sstripContainer; + sstripContainer.name = "odd-sstrip"; + sstripContainer.extent.set(Acts::binR, 210., 720); + + Acts::BinningData sstripEcBinningR = + Acts::BinningData(Acts::open, Acts::binR, 3., 0., 1.); + Acts::BinningData sstripEcBinningPhi = + Acts::BinningData(Acts::closed, Acts::binPhi, 42., -M_PI, M_PI); + + Acts::ProtoVolume sstripNec; + sstripNec.name = "odd-sstrip-nec"; + sstripNec.extent.set(Acts::binZ, -3100., -1200); + Acts::ProtoVolume sstripNecD5; + sstripNecD5.name = "odd-sstrip-nec-d5"; + sstripNecD5.extent.set(Acts::binZ, -3000, -2900.); + Acts::ProtoVolume sstripNecD4; + sstripNecD4.name = "odd-sstrip-nec-d4"; + sstripNecD4.extent.set(Acts::binZ, -2600., -2500.); + Acts::ProtoVolume sstripNecD3; + sstripNecD3.name = "odd-sstrip-nec-d3"; + sstripNecD3.extent.set(Acts::binZ, -2250, -2150.); + Acts::ProtoVolume sstripNecD2; + sstripNecD2.name = "odd-sstrip-nec-d2"; + sstripNecD2.extent.set(Acts::binZ, -1900, -1800.); + Acts::ProtoVolume sstripNecD1; + sstripNecD1.name = "odd-sstrip-nec-d1"; + sstripNecD1.extent.set(Acts::binZ, -1600., -1500.); + Acts::ProtoVolume sstripNecD0; + sstripNecD0.name = "odd-sstrip-nec-d0"; + sstripNecD0.extent.set(Acts::binZ, -1350., -1250.); + + sstripNec.constituentVolumes = {sstripNecD5, sstripNecD4, sstripNecD3, + sstripNecD2, sstripNecD1, sstripNecD0}; + sstripNec.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; + for (auto& cv : sstripNec.constituentVolumes) { + cv.layerType = Acts::Surface::SurfaceType::Disc; + cv.layerSurfaceBinning = {sstripEcBinningR, sstripEcBinningPhi}; + cv.extent.setEnvelope(discLayerEnvelope); + } + sstripNec.layerContainer = true; + + Acts::ProtoVolume sstripBarrel; + sstripBarrel.name = "odd-sstrip-barrel"; + sstripBarrel.extent.set(Acts::binZ, -1200., 1200); + + Acts::ProtoVolume sstripBarrelL0; + sstripBarrelL0.name = "odd-sstrip-barrel-l0"; + sstripBarrelL0.extent.set(Acts::binR, 240., 280.); + Acts::ProtoVolume sstripBarrelL1; + sstripBarrelL1.name = "odd-sstrip-barrel-l1"; + sstripBarrelL1.extent.set(Acts::binR, 340., 380.); + Acts::ProtoVolume sstripBarrelL2; + sstripBarrelL2.name = "odd-sstrip-barrel-l2"; + sstripBarrelL2.extent.set(Acts::binR, 480., 520.); + Acts::ProtoVolume sstripBarrelL3; + sstripBarrelL3.name = "odd-sstrip-barrel-l3"; + sstripBarrelL3.extent.set(Acts::binR, 640., 680.); + + sstripBarrel.constituentVolumes = {sstripBarrelL0, sstripBarrelL1, + sstripBarrelL2, sstripBarrelL3}; + for (auto& cv : sstripBarrel.constituentVolumes) { + cv.layerType = Acts::Surface::SurfaceType::Cylinder; + cv.extent.setEnvelope(cylinderLayerEnvelope); + } + + sstripBarrel.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binR, {0., 1})}; + sstripBarrel.layerContainer = true; + + Acts::ProtoVolume sstripPec; + sstripPec.name = "odd-sstrip-pec"; + sstripPec.extent.set(Acts::binZ, 1200., 3100); + + Acts::ProtoVolume sstripPecD0; + sstripPecD0.name = "odd-sstrip-pec-d0"; + sstripPecD0.extent.set(Acts::binZ, 1250., 1350); + Acts::ProtoVolume sstripPecD1; + sstripPecD1.name = "odd-sstrip-pec-d1"; + sstripPecD1.extent.set(Acts::binZ, 1500., 1600.); + Acts::ProtoVolume sstripPecD2; + sstripPecD2.name = "odd-sstrip-pec-d2"; + sstripPecD2.extent.set(Acts::binZ, 1800., 1900.); + Acts::ProtoVolume sstripPecD3; + sstripPecD3.name = "odd-sstrip-pec-d3"; + sstripPecD3.extent.set(Acts::binZ, 2150., 2250.); + Acts::ProtoVolume sstripPecD4; + sstripPecD4.name = "odd-sstrip-pec-d4"; + sstripPecD4.extent.set(Acts::binZ, 2500., 2600.); + Acts::ProtoVolume sstripPecD5; + sstripPecD5.name = "odd-sstrip-pec-d5"; + sstripPecD5.extent.set(Acts::binZ, 2900., 3000.); + + sstripPec.constituentVolumes = {sstripPecD0, sstripPecD1, sstripPecD2, + sstripPecD3, sstripPecD4, sstripPecD5}; + sstripPec.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; + for (auto& cv : sstripPec.constituentVolumes) { + cv.layerType = Acts::Surface::SurfaceType::Disc; + cv.layerSurfaceBinning = {sstripEcBinningR, sstripEcBinningPhi}; + cv.extent.setEnvelope(discLayerEnvelope); + } + sstripPec.layerContainer = true; + + sstripContainer.constituentBinning = {Acts::BinningData( + Acts::open, Acts::binZ, {-3100., -1200., 1200., 3100.})}; + sstripContainer.constituentVolumes = {sstripNec, sstripBarrel, sstripPec}; + + // Long Strip section + Acts::ProtoVolume lstripContainer; + lstripContainer.name = "odd-lstrip"; + lstripContainer.extent.set(Acts::binR, 720, 1100.); + + Acts::ProtoVolume lstripNec; + lstripNec.name = "odd-lstrip-nec"; + lstripNec.extent.set(Acts::binZ, -3100., -1200); + Acts::ProtoVolume lstripNecD5; + lstripNecD5.name = "odd-lstrip-nec-d5"; + lstripNecD5.extent.set(Acts::binZ, -3050, -2900.); + Acts::ProtoVolume lstripNecD4; + lstripNecD4.name = "odd-lstrip-nec-d4"; + lstripNecD4.extent.set(Acts::binZ, -2650., -2500.); + Acts::ProtoVolume lstripNecD3; + lstripNecD3.name = "odd-lstrip-nec-d3"; + lstripNecD3.extent.set(Acts::binZ, -2300, -2150.); + Acts::ProtoVolume lstripNecD2; + lstripNecD2.name = "odd-lstrip-nec-d2"; + lstripNecD2.extent.set(Acts::binZ, -1950, -1800.); + Acts::ProtoVolume lstripNecD1; + lstripNecD1.name = "odd-lstrip-nec-d1"; + lstripNecD1.extent.set(Acts::binZ, -1650., -1500.); + Acts::ProtoVolume lstripNecD0; + lstripNecD0.name = "odd-lstrip-nec-d0"; + lstripNecD0.extent.set(Acts::binZ, -1400., -1250.); + + lstripNec.constituentVolumes = {lstripNecD5, lstripNecD4, lstripNecD3, + lstripNecD2, lstripNecD1, lstripNecD0}; + lstripNec.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; + for (auto& cv : lstripNec.constituentVolumes) { + cv.layerType = Acts::Surface::SurfaceType::Disc; + cv.extent.setEnvelope(discLayerEnvelope); + } + lstripNec.layerContainer = true; + + Acts::ProtoVolume lstripBarrel; + lstripBarrel.name = "odd-lstrip-barrel"; + lstripBarrel.extent.set(Acts::binZ, -1200., 1200); + + Acts::ProtoVolume lstripBarrelL0; + lstripBarrelL0.name = "odd-lstrip-barrel-l0"; + lstripBarrelL0.extent.set(Acts::binR, 800., 840.); + Acts::ProtoVolume lstripBarrelL1; + lstripBarrelL1.name = "odd-lstrip-barrel-l1"; + lstripBarrelL1.extent.set(Acts::binR, 1000., 1050.); + + lstripBarrel.constituentVolumes = {lstripBarrelL0, lstripBarrelL1}; + for (auto& cv : lstripBarrel.constituentVolumes) { + cv.layerType = Acts::Surface::SurfaceType::Cylinder; + cv.extent.setEnvelope(cylinderLayerEnvelope); + } + + lstripBarrel.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binR, {0., 1})}; + lstripBarrel.layerContainer = true; + + Acts::ProtoVolume lstripPec; + lstripPec.name = "odd-lstrip-pec"; + lstripPec.extent.set(Acts::binZ, 1200., 3100); + + Acts::ProtoVolume lstripPecD0; + lstripPecD0.name = "odd-lstrip-pec-d0"; + lstripPecD0.extent.set(Acts::binZ, 1250., 1400); + Acts::ProtoVolume lstripPecD1; + lstripPecD1.name = "odd-lstrip-pec-d1"; + lstripPecD1.extent.set(Acts::binZ, 1500., 1650.); + Acts::ProtoVolume lstripPecD2; + lstripPecD2.name = "odd-lstrip-pec-d2"; + lstripPecD2.extent.set(Acts::binZ, 1800., 1950.); + Acts::ProtoVolume lstripPecD3; + lstripPecD3.name = "odd-lstrip-pec-d3"; + lstripPecD3.extent.set(Acts::binZ, 2150., 2300.); + Acts::ProtoVolume lstripPecD4; + lstripPecD4.name = "odd-lstrip-pec-d4"; + lstripPecD4.extent.set(Acts::binZ, 2500., 2650.); + Acts::ProtoVolume lstripPecD5; + lstripPecD5.name = "odd-lstrip-pec-d5"; + lstripPecD5.extent.set(Acts::binZ, 2900., 3050.); + + lstripPec.constituentVolumes = {lstripPecD0, lstripPecD1, lstripPecD2, + lstripPecD3, lstripPecD4, lstripPecD5}; + lstripPec.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; + for (auto& cv : lstripPec.constituentVolumes) { + cv.layerType = Acts::Surface::SurfaceType::Disc; + cv.extent.setEnvelope(discLayerEnvelope); + } + lstripPec.layerContainer = true; + + lstripContainer.constituentVolumes = {lstripNec, lstripBarrel, lstripPec}; + lstripContainer.constituentBinning = {Acts::BinningData( + Acts::open, Acts::binZ, {-3100., -1200., 1200., 3100.})}; + + // The overall container + Acts::ProtoVolume detectorContainer; + detectorContainer.name = "odd-light-world"; + detectorContainer.extent.set(Acts::binR, 0., 1100.); + detectorContainer.extent.set(Acts::binZ, -3100., 3100.); + detectorContainer.constituentVolumes = {beamPipeContainer, pixelContainer, + pstContainer, sstripContainer, + lstripContainer}; + detectorContainer.constituentBinning = {Acts::BinningData( + Acts::open, Acts::binR, {0., 25., 200., 210., 720., 1100.})}; + + // ---------------------------------------------------------- + Acts::ProtoDetector detector; + detector.name = "odd-light"; + detector.worldVolume = detectorContainer; + + // Transform into json + nlohmann::json jdet; + jdet["detector"] = detector; + + std::ofstream out; + out.open("odd-proto-detector.json"); + out << jdet.dump(4); + out.close(); + + Acts::ProtoDetector detectorIn = jdet["detector"]; +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/Tests/UnitTests/Plugins/Json/UtilitiesJsonConverterTests.cpp b/Tests/UnitTests/Plugins/Json/UtilitiesJsonConverterTests.cpp index 20ba6631272..cdde0f55058 100644 --- a/Tests/UnitTests/Plugins/Json/UtilitiesJsonConverterTests.cpp +++ b/Tests/UnitTests/Plugins/Json/UtilitiesJsonConverterTests.cpp @@ -11,6 +11,7 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/Plugins/Json/ActsJson.hpp" #include "Acts/Plugins/Json/UtilitiesJsonConverter.hpp" +#include "Acts/Tests/CommonHelpers/FloatComparisons.hpp" #include "Acts/Utilities/BinUtility.hpp" #include "Acts/Utilities/BinningData.hpp" @@ -168,4 +169,16 @@ BOOST_AUTO_TEST_CASE(BinUtilityRoundTripTests) { BOOST_CHECK(isEqual(reference, test, 0.0001)); } +BOOST_AUTO_TEST_CASE(Range1DRoundTrip) { + Range1D r(-10., 100.); + + nlohmann::json jrange; + jrange["range"] = r; + + Range1D rIn = jrange["range"]; + + CHECK_CLOSE_ABS(rIn.min(), -10., 10e-5); + CHECK_CLOSE_ABS(rIn.max(), 100., 10e-5); +} + BOOST_AUTO_TEST_SUITE_END() From b82e1db0a133e6d814ac06a7b1da48e834c9f12d Mon Sep 17 00:00:00 2001 From: Andreas Salzburger Date: Fri, 16 Dec 2022 17:36:19 +0100 Subject: [PATCH 04/13] clang-tidyness' --- .../Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp | 4 ++-- Core/include/Acts/Geometry/ProtoDetector.hpp | 12 ++++++------ Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp | 2 +- Core/src/Geometry/ProtoDetector.cpp | 13 +++++++------ 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Core/include/Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp b/Core/include/Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp index 95139999416..b3f32dd9ab2 100644 --- a/Core/include/Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp +++ b/Core/include/Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp @@ -54,10 +54,10 @@ class KDTreeTrackingGeometryBuilder : public ITrackingGeometryBuilder { /// Constructor /// - /// @param [in] cgbConfig is the configuration struct for this builder + /// @param [in] cfg is the configuration struct for this builder /// @param [in] logger logging instance KDTreeTrackingGeometryBuilder( - const Config& cgbConfig, + const Config& cfg, std::unique_ptr logger = getDefaultLogger("KDTreeTrackingGeometryBuilder", Logging::INFO)); diff --git a/Core/include/Acts/Geometry/ProtoDetector.hpp b/Core/include/Acts/Geometry/ProtoDetector.hpp index aba3a690568..c527094008f 100644 --- a/Core/include/Acts/Geometry/ProtoDetector.hpp +++ b/Core/include/Acts/Geometry/ProtoDetector.hpp @@ -38,8 +38,8 @@ struct ProtoVolume { /// Define an operator== /// - /// @param pv the proto volume to be checked - bool operator==(const ProtoVolume& pv) const; + /// @param ptVolume the proto volume to be checked + bool operator==(const ProtoVolume& ptVolume) const; /// Harmonize the detector information, this can run in two /// modes, steered by the @param legacy boolean @@ -51,8 +51,8 @@ struct ProtoVolume { /// Extend the tracking volume with the its own constituents, /// upwards here means that extens are promoted to the mother /// - /// @param pVolume the protoVolume - void extendUp(ProtoVolume& pVolume); + /// @param ptVolume the protoVolume + void extendUp(ProtoVolume& ptVolume); /// Extend the tracking volume with the its own constituents /// @param bValue the binning value that is propagated @@ -64,9 +64,9 @@ struct ProtoVolume { /// Constrain the daughter volumes with this volume /// - /// @param pVolume is the proto volume from which the constrain + /// @param ptVolume is the proto volume from which the constrain /// is taken - void constrainDown(const ProtoVolume& pVolume); + void constrainDown(const ProtoVolume& ptVolume); /// Write the tracking volume to screen /// @param indent the current indentation diff --git a/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp b/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp index c2ace77619a..96b1b0a60c2 100644 --- a/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp +++ b/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp @@ -170,7 +170,7 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( std::size_t bins0 = 0; std::size_t bins1 = 0; // In case explicit binning is given - if (plVolume.layerSurfaceBinning.size()) { + if (plVolume.layerSurfaceBinning.size() == 2u) { bType0 = plVolume.layerSurfaceBinning[0u].type; bType1 = plVolume.layerSurfaceBinning[1u].type; // In case explicit bin numbers are given in addition diff --git a/Core/src/Geometry/ProtoDetector.cpp b/Core/src/Geometry/ProtoDetector.cpp index 630c6112778..9e3beb45af7 100644 --- a/Core/src/Geometry/ProtoDetector.cpp +++ b/Core/src/Geometry/ProtoDetector.cpp @@ -163,17 +163,18 @@ void Acts::ProtoVolume::harmonize(bool legacy) { } } -bool Acts::ProtoVolume::operator==(const Acts::ProtoVolume& pv) const { +bool Acts::ProtoVolume::operator==(const Acts::ProtoVolume& ptVolume) const { // Simple checks - if (name != pv.name or extent != pv.extent or - layerContainer != pv.layerContainer or layerType != pv.layerType) { + if (name != ptVolume.name or extent != ptVolume.extent or + layerContainer != ptVolume.layerContainer or + layerType != ptVolume.layerType) { return false; } - if (layerSurfaceBinning != pv.layerSurfaceBinning) { + if (layerSurfaceBinning != ptVolume.layerSurfaceBinning) { return false; } - if (constituentVolumes != pv.constituentVolumes or - constituentBinning != pv.constituentBinning) { + if (constituentVolumes != ptVolume.constituentVolumes or + constituentBinning != ptVolume.constituentBinning) { return false; } return true; From 983695614eeb6ebb72e75f897be7b2a41876ce36 Mon Sep 17 00:00:00 2001 From: Andreas Salzburger Date: Fri, 16 Dec 2022 21:55:38 +0100 Subject: [PATCH 05/13] add KDTreeTrackingGeometryBuilder test --- Core/include/Acts/Geometry/Extent.hpp | 2 +- Core/src/Geometry/ProtoDetector.cpp | 2 +- Tests/UnitTests/Core/Geometry/CMakeLists.txt | 1 + Tests/UnitTests/Core/Geometry/ExtentTests.cpp | 13 +- .../KDTreeTrackingGeometryBuilderTests.cpp | 244 ++++++++++++++++++ 5 files changed, 259 insertions(+), 3 deletions(-) create mode 100644 Tests/UnitTests/Core/Geometry/KDTreeTrackingGeometryBuilderTests.cpp diff --git a/Core/include/Acts/Geometry/Extent.hpp b/Core/include/Acts/Geometry/Extent.hpp index e7e086f4147..165405814ec 100644 --- a/Core/include/Acts/Geometry/Extent.hpp +++ b/Core/include/Acts/Geometry/Extent.hpp @@ -100,8 +100,8 @@ class Extent { /// - values not constrained by @param rhs are not touched /// - values that are constrained by the external one, but not /// by the current one, are touched - /// @param envelope an envelope applied to the constrained value /// + /// @param envelope an envelope applied to the constrained value void addConstrain(const Extent& rhs, const ExtentEnvelope& envelope = zeroEnvelopes); diff --git a/Core/src/Geometry/ProtoDetector.cpp b/Core/src/Geometry/ProtoDetector.cpp index 9e3beb45af7..07fd70e9aa3 100644 --- a/Core/src/Geometry/ProtoDetector.cpp +++ b/Core/src/Geometry/ProtoDetector.cpp @@ -194,7 +194,7 @@ std::string Acts::ProtoVolume::toString(const std::string& indent) const { ss << cb.toString(indent) << '\n'; } ss << indent << " constituents are:" << '\n'; - for (auto cv : constituentVolumes) { + for (const auto& cv : constituentVolumes) { ss << cv.toString(indent + subIndent) << '\n'; } } diff --git a/Tests/UnitTests/Core/Geometry/CMakeLists.txt b/Tests/UnitTests/Core/Geometry/CMakeLists.txt index 3a96a126e4d..f13dc21bb43 100644 --- a/Tests/UnitTests/Core/Geometry/CMakeLists.txt +++ b/Tests/UnitTests/Core/Geometry/CMakeLists.txt @@ -17,6 +17,7 @@ add_unittest(GenericApproachDescriptor GenericApproachDescriptorTests.cpp) add_unittest(GenericCuboidVolumeBounds GenericCuboidVolumeBoundsTests.cpp) add_unittest(GeometryHierarchyMap GeometryHierarchyMapTests.cpp) add_unittest(GeometryIdentifier GeometryIdentifierTests.cpp) +add_unittest(KDTreeTrackingGeometryBuilder KDTreeTrackingGeometryBuilderTests.cpp) add_unittest(LayerCreator LayerCreatorTests.cpp) add_unittest(Layer LayerTests.cpp) add_unittest(NavigationLayer NavigationLayerTests.cpp) diff --git a/Tests/UnitTests/Core/Geometry/ExtentTests.cpp b/Tests/UnitTests/Core/Geometry/ExtentTests.cpp index c129f5c9a0f..c3477c3fac4 100644 --- a/Tests/UnitTests/Core/Geometry/ExtentTests.cpp +++ b/Tests/UnitTests/Core/Geometry/ExtentTests.cpp @@ -23,7 +23,7 @@ using namespace UnitLiterals; namespace Test { -BOOST_AUTO_TEST_SUITE(Core) +BOOST_AUTO_TEST_SUITE(Geometry) /// Unit tests for Polyderon construction & operator += BOOST_AUTO_TEST_CASE(ExtentTest) { @@ -136,6 +136,17 @@ BOOST_AUTO_TEST_CASE(ExtentTest) { gExt.set(binR, -2_mm, 18_mm); CHECK_CLOSE_ABS(gExt.min(binR), 0_mm, 1e-6); CHECK_CLOSE_ABS(gExt.max(binR), 18_mm, 1e-6); + + // Take an Extent and add an xonstrain + Extent gExtConst; + gExtConst.set(binR, 0., 5.); + Extent gExtNonConst; + BOOST_CHECK(not gExtNonConst.constrains(binR)); + gExtNonConst.addConstrain(gExtConst); + BOOST_CHECK(gExtNonConst.constrains(binR)); + + std::string tString = gExtConst.toString(); + BOOST_CHECK(not tString.empty()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/Tests/UnitTests/Core/Geometry/KDTreeTrackingGeometryBuilderTests.cpp b/Tests/UnitTests/Core/Geometry/KDTreeTrackingGeometryBuilderTests.cpp new file mode 100644 index 00000000000..ab2d49b1314 --- /dev/null +++ b/Tests/UnitTests/Core/Geometry/KDTreeTrackingGeometryBuilderTests.cpp @@ -0,0 +1,244 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2022 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Geometry/CylinderVolumeHelper.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp" +#include "Acts/Geometry/LayerArrayCreator.hpp" +#include "Acts/Geometry/LayerCreator.hpp" +#include "Acts/Geometry/ProtoDetector.hpp" +#include "Acts/Geometry/SurfaceArrayCreator.hpp" +#include "Acts/Geometry/TrackingVolumeArrayCreator.hpp" +#include "Acts/Surfaces/CylinderSurface.hpp" +#include "Acts/Tests/CommonHelpers/CylindricalTrackingGeometry.hpp" +#include "Acts/Utilities/Logger.hpp" + +namespace Acts { + +using namespace UnitLiterals; + +namespace Test { + +BOOST_AUTO_TEST_SUITE(Geometry) + +BOOST_AUTO_TEST_CASE(KDTreeTrackingGeometryBuilder_simple) { + GeometryContext tContext; + CylindricalTrackingGeometry ctGeometry(tContext); + CylindricalTrackingGeometry::DetectorStore detectorStore; + + // The collected surfaces + std::vector> layerSurfacePtrs; + + // Add a beam pipe + auto hTransform = Transform3::Identity(); + layerSurfacePtrs.push_back( + Surface::makeShared(hTransform, 15., 800.)); + + // Pixel Surfaces + std::vector pLayerRadii = {32., 72., 116., 172.}; + std::vector> pLayerBinning = { + {16, 14}, {32, 14}, {52, 14}, {78, 14}}; + std::vector pModuleTiltPhi = {0.145, 0.145, 0.145, 0.145}; + std::vector pModuleHalfX = {8.4, 8.4, 8.4, 8.4}; + std::vector pModuleHalfY = {36., 36., 36., 36.}; + std::vector pModuleThickness = {0.15, 0.15, 0.15, 0.15}; + + // Fill surfaces from cylinder layers + for (size_t ilp = 0; ilp < pLayerRadii.size(); ++ilp) { + std::vector layerSurfaces = ctGeometry.surfacesCylinder( + detectorStore, pModuleHalfX[ilp], pModuleHalfY[ilp], + pModuleThickness[ilp], pModuleTiltPhi[ilp], pLayerRadii[ilp], 2_mm, + 5_mm, pLayerBinning[ilp]); + + // Make a shared version out of it + for (auto& sf : layerSurfaces) { + Surface* mutableSf = const_cast(sf); + layerSurfacePtrs.push_back(mutableSf->getSharedPtr()); + } + } + + // Fill surfaces for disc layers + std::vector discZ = {-700., -600., 600., 700.}; + std::vector discRadii = {60., 60., 60., 60.}; + std::vector discModules = {22, 22, 22, 22}; + + std::vector dModuleHalfXMinY = {6.4, 6.4, 6.4, 6.4}; + std::vector dModuleHalfXMaxY = {12.4, 12.4, 12.4, 12.4}; + std::vector dModuleHalfY = {36., 36., 36., 36.}; + std::vector dModuleTilt = {0.075, 0.075, 0.075, 0.075}; + std::vector dModuleThickness = {0.15, 0.15, 0.15, 0.15}; + + for (size_t ilp = 0; ilp < discZ.size(); ++ilp) { + std::vector layerSurfaces = ctGeometry.surfacesRing( + detectorStore, dModuleHalfXMinY[ilp], dModuleHalfXMaxY[ilp], + dModuleHalfY[ilp], dModuleThickness[ilp], dModuleTilt[ilp], + discRadii[ilp], discZ[ilp], 2., discModules[ilp]); + for (auto& sf : layerSurfaces) { + Surface* mutableSf = const_cast(sf); + layerSurfacePtrs.push_back(mutableSf->getSharedPtr()); + } + } + + // Make a proto detectpr description + Acts::ProtoVolume beamPipeContainer; + beamPipeContainer.name = "odd-beam-pipe"; + beamPipeContainer.extent.set(Acts::binR, 0., 17); + Acts::ProtoVolume beamPipe; + beamPipe.name = "odd-beam-pipe-l"; + beamPipe.extent.set(Acts::binR, 2., 16.); + beamPipe.layerType = Acts::Surface::SurfaceType::Cylinder; + beamPipeContainer.constituentVolumes = {beamPipe}; + beamPipeContainer.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}; + beamPipeContainer.layerContainer = true; + + // Pixel section + Acts::ProtoVolume pixelContainer; + pixelContainer.name = "odd-pixel"; + pixelContainer.extent.set(Acts::binR, 18., 200); + + Acts::ProtoVolume pixelNec; + pixelNec.name = "odd-pixel-nec"; + pixelNec.extent.set(Acts::binZ, -1000., -580); + + Acts::ProtoVolume pixNecD1; + pixNecD1.name = "odd-pixel-nec-d1"; + pixNecD1.extent.set(Acts::binZ, -720., -680); + Acts::ProtoVolume pixNecD0; + pixNecD0.name = "odd-pixel-nec-d0"; + pixNecD0.extent.set(Acts::binZ, -620., -580); + pixelNec.constituentVolumes = {pixNecD1, pixNecD0}; + + pixelNec.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binZ, {0., 1.})}; + for (auto& cv : pixelNec.constituentVolumes) { + cv.layerType = Acts::Surface::SurfaceType::Disc; + } + pixelNec.layerContainer = true; + + Acts::ProtoVolume pixelBarrel; + pixelBarrel.name = "odd-pixel-barrel"; + pixelBarrel.extent.set(Acts::binZ, -580., 580); + + Acts::ProtoVolume pixBarrelL0; + pixBarrelL0.name = "odd-pixel-barrel-l0"; + pixBarrelL0.extent.set(Acts::binR, 28., 48.); + pixBarrelL0.extent.set(Acts::binZ, -580., 580); + pixBarrelL0.layerType = Acts::Surface::SurfaceType::Cylinder; + Acts::ProtoVolume pixBarrelL1; + pixBarrelL1.name = "odd-pixel-barrel-l1"; + pixBarrelL1.extent.set(Acts::binR, 62., 76); + pixBarrelL1.extent.set(Acts::binZ, -580., 580); + pixBarrelL1.layerType = Acts::Surface::SurfaceType::Cylinder; + Acts::ProtoVolume pixBarrelL2; + pixBarrelL2.name = "odd-pixel-barrel-l2"; + pixBarrelL2.extent.set(Acts::binR, 100., 120.); + pixBarrelL2.extent.set(Acts::binZ, -580., 580); + pixBarrelL2.layerType = Acts::Surface::SurfaceType::Cylinder; + Acts::ProtoVolume pixBarrelL3; + pixBarrelL3.name = "odd-pixel-barrel-l3"; + pixBarrelL3.extent.set(Acts::binR, 160., 180.); + pixBarrelL3.extent.set(Acts::binZ, -580., 580); + pixBarrelL3.layerType = Acts::Surface::SurfaceType::Cylinder; + + pixelBarrel.constituentVolumes = {pixBarrelL0, pixBarrelL1, pixBarrelL2, + pixBarrelL3}; + pixelBarrel.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binR, {0., 1})}; + pixelBarrel.layerContainer = true; + + Acts::ProtoVolume pixelPec; + pixelPec.name = "odd-pixel-pec"; + pixelPec.extent.set(Acts::binZ, 580., 1000.); + + Acts::ProtoVolume pixPecD0; + pixPecD0.name = "odd-pixel-pec-d0"; + pixPecD0.extent.set(Acts::binZ, 580., 620); + Acts::ProtoVolume pixPecD1; + pixPecD1.name = "odd-pixel-pec-d1"; + pixPecD1.extent.set(Acts::binZ, 680., 720); + + pixelPec.constituentVolumes = {pixPecD0, pixPecD1}; + pixelPec.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; + for (auto& cv : pixelPec.constituentVolumes) { + cv.layerType = Acts::Surface::SurfaceType::Disc; + } + pixelPec.layerContainer = true; + + pixelContainer.constituentVolumes = {pixelNec, pixelBarrel, pixelPec}; + pixelContainer.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binZ, {-1000., -580., 580., 1000.})}; + + Acts::ProtoVolume detectorContainer; + detectorContainer.name = "odd-detector"; + detectorContainer.extent.set(Acts::binR, 0., 200); + detectorContainer.constituentVolumes = {beamPipeContainer, pixelContainer}; + detectorContainer.constituentBinning = { + Acts::BinningData(Acts::open, Acts::binR, {0., 17.5, 200.})}; + + Acts::ProtoDetector detector; + detector.name = "odd"; + detector.worldVolume = detectorContainer; + + // Surface array creatorr + auto surfaceArrayCreator = std::make_shared( + Acts::SurfaceArrayCreator::Config(), + Acts::getDefaultLogger("SurfaceArrayCreator", Acts::Logging::INFO)); + // Layer Creator + Acts::LayerCreator::Config lcConfig; + lcConfig.surfaceArrayCreator = surfaceArrayCreator; + auto layerCreator = std::make_shared( + lcConfig, Acts::getDefaultLogger("LayerCreator", Acts::Logging::INFO)); + // Layer array creator + Acts::LayerArrayCreator::Config lacConfig; + auto layerArrayCreator = std::make_shared( + lacConfig, + Acts::getDefaultLogger("LayerArrayCreator", Acts::Logging::INFO)); + // Tracking volume array creator + Acts::TrackingVolumeArrayCreator::Config tvacConfig; + auto tVolumeArrayCreator = + std::make_shared( + tvacConfig, Acts::getDefaultLogger("TrackingVolumeArrayCreator", + Acts::Logging::INFO)); + // configure the cylinder volume helper + Acts::CylinderVolumeHelper::Config cvhConfig; + cvhConfig.layerArrayCreator = layerArrayCreator; + cvhConfig.trackingVolumeArrayCreator = tVolumeArrayCreator; + auto cylinderVolumeHelper = + std::make_shared( + cvhConfig, + Acts::getDefaultLogger("CylinderVolumeHelper", Acts::Logging::INFO)); + + // The KDT tracking geometry builder + Acts::KDTreeTrackingGeometryBuilder::Config kdtgConfig; + kdtgConfig.layerCreator = layerCreator; + kdtgConfig.trackingVolumeHelper = cylinderVolumeHelper; + // Reserve the right amount of surfaces + kdtgConfig.surfaces = layerSurfacePtrs; + + // Assign the proto detector + kdtgConfig.protoDetector = detector; + + // Make the builder + auto kdtTrackingGeometryBuilder = Acts::KDTreeTrackingGeometryBuilder( + kdtgConfig, Acts::getDefaultLogger("KDTreeTrackingGeometryBuilder", + Acts::Logging::INFO)); + + auto trackingGeometry = kdtTrackingGeometryBuilder.trackingGeometry(tContext); + BOOST_CHECK(trackingGeometry != nullptr); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace Test +} // namespace Acts From cc0efa8fcf684c7e45c4ecf1bb24d2471d232fa9 Mon Sep 17 00:00:00 2001 From: Andreas Salzburger Date: Tue, 20 Dec 2022 07:39:59 +0100 Subject: [PATCH 06/13] addressing PR comments --- Core/include/Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp | 3 --- Core/src/Geometry/ProtoDetector.cpp | 4 ++-- Core/src/Geometry/ProtoLayer.cpp | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Core/include/Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp b/Core/include/Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp index b3f32dd9ab2..dceb9dfe759 100644 --- a/Core/include/Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp +++ b/Core/include/Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp @@ -61,9 +61,6 @@ class KDTreeTrackingGeometryBuilder : public ITrackingGeometryBuilder { std::unique_ptr logger = getDefaultLogger("KDTreeTrackingGeometryBuilder", Logging::INFO)); - /// Destructor - ~KDTreeTrackingGeometryBuilder() override = default; - /// TrackingGeometry Interface method /// /// @param gctx geometry context of that building call diff --git a/Core/src/Geometry/ProtoDetector.cpp b/Core/src/Geometry/ProtoDetector.cpp index 07fd70e9aa3..5ce22fb7ee1 100644 --- a/Core/src/Geometry/ProtoDetector.cpp +++ b/Core/src/Geometry/ProtoDetector.cpp @@ -68,7 +68,7 @@ void Acts::ProtoVolume::harmonize(bool legacy) { layerContainer = layersPresent; auto binValue = constituentBinning[0].binvalue; // Set the first last - auto& fVolume = *constituentVolumes.begin(); + auto& fVolume = constituentVolumes.front(); auto& lVolume = constituentVolumes.back(); std::vector borders = {}; @@ -207,4 +207,4 @@ std::string Acts::ProtoDetector::toString(const std::string& indent) const { ss << indent << "> detector: " << name << '\n'; ss << worldVolume.toString(indent + subIndent) << '\n'; return ss.str(); -} \ No newline at end of file +} diff --git a/Core/src/Geometry/ProtoLayer.cpp b/Core/src/Geometry/ProtoLayer.cpp index 039ef8e62f3..6384a2f663f 100644 --- a/Core/src/Geometry/ProtoLayer.cpp +++ b/Core/src/Geometry/ProtoLayer.cpp @@ -35,7 +35,7 @@ ProtoLayer::ProtoLayer( double ProtoLayer::min(BinningValue bval, bool addenv) const { if (addenv) { - return extent.min(bval) - std::abs(envelope[bval][0u]); + return extent.min(bval) - envelope[bval][0u]; } return extent.min(bval); } From 78dba5052a58a51da11a7d30c6fd74373236a9a3 Mon Sep 17 00:00:00 2001 From: Andreas Salzburger Date: Tue, 20 Dec 2022 08:25:41 +0100 Subject: [PATCH 07/13] fix clash --- Core/include/Acts/Geometry/CuboidVolumeBuilder.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/include/Acts/Geometry/CuboidVolumeBuilder.hpp b/Core/include/Acts/Geometry/CuboidVolumeBuilder.hpp index 8d0fd48d62b..c3f3a0fc79e 100644 --- a/Core/include/Acts/Geometry/CuboidVolumeBuilder.hpp +++ b/Core/include/Acts/Geometry/CuboidVolumeBuilder.hpp @@ -77,6 +77,7 @@ class CuboidVolumeBuilder : public ITrackingVolumeBuilder { std::array envelopeY{0, 0}; // Envelope in Z std::array envelopeZ{0, 0}; + // An optional rotation fo this std::optional rotation{std::nullopt}; }; From 66743c4bea9121326428f97700342e99fcd48f28 Mon Sep 17 00:00:00 2001 From: Andreas Salzburger Date: Thu, 5 Jan 2023 15:15:04 +0100 Subject: [PATCH 08/13] addressing PR comments --- Core/include/Acts/Geometry/ProtoDetector.hpp | 24 +++++++++-------- .../KDTreeTrackingGeometryBuilder.cpp | 27 ++++++++++--------- Core/src/Geometry/ProtoDetector.cpp | 23 ++++++++-------- .../KDTreeTrackingGeometryBuilderTests.cpp | 18 +++++-------- .../Core/Geometry/ProtoDetectorTests.cpp | 17 ++---------- 5 files changed, 47 insertions(+), 62 deletions(-) diff --git a/Core/include/Acts/Geometry/ProtoDetector.hpp b/Core/include/Acts/Geometry/ProtoDetector.hpp index c527094008f..c349a5eed99 100644 --- a/Core/include/Acts/Geometry/ProtoDetector.hpp +++ b/Core/include/Acts/Geometry/ProtoDetector.hpp @@ -13,7 +13,9 @@ #include "Acts/Surfaces/Surface.hpp" #include "Acts/Utilities/BinningData.hpp" +#include #include +#include namespace Acts { @@ -22,15 +24,15 @@ namespace Acts { struct ProtoVolume { /// Name of the proto volume std::string name = ""; - /// The extent of this layer + /// The extent of this volume Extent extent; - /// Boolean to indicate this is a container, needed for legacy - bool layerContainer = false; - /// Set the layer type to indicate the layer volume - Acts::Surface::SurfaceType layerType = Acts::Surface::SurfaceType::Other; - /// The surface binninng fo the layer - std::vector layerSurfaceBinning = {}; + /// Information for legacy type building + Acts::Surface::SurfaceType legacyLayerType = + Acts::Surface::SurfaceType::Other; + + /// The surface binninng for internal surfaces (optional) + std::vector surfaceBinning = {}; /// Internal structure container std::vector constituentVolumes = {}; /// The constituent binning if this a container @@ -48,17 +50,17 @@ struct ProtoVolume { /// if off it creates a description for `Acts::Detector`. void harmonize(bool legacy = true); - /// Extend the tracking volume with the its own constituents, - /// upwards here means that extens are promoted to the mother + /// Extend the tracking volume with its own constituents, + /// upwards here means that extents are promoted to the mother /// /// @param ptVolume the protoVolume void extendUp(ProtoVolume& ptVolume); - /// Extend the tracking volume with the its own constituents + /// Extend the tracking volume with its own constituents /// @param bValue the binning value that is propagated void propagateMinDown(BinningValue bValue); - /// Extend the tracking volume with the its own constituents + /// Extend the tracking volume with its own constituents /// @param bValue the binning value that is propagated void propagateMaxDown(BinningValue bValue); diff --git a/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp b/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp index 96b1b0a60c2..ae4e876b776 100644 --- a/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp +++ b/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp @@ -68,7 +68,8 @@ Acts::KDTreeTrackingGeometryBuilder::translateVolume( ACTS_DEBUG(indent << "Processing ProtoVolume: " << ptVolume.name); std::vector> translatedVolumes = {}; - if (not ptVolume.constituentVolumes.empty() and not ptVolume.layerContainer) { + if (not ptVolume.constituentVolumes.empty() and + ptVolume.legacyLayerType == Surface::SurfaceType::Other) { ACTS_VERBOSE(indent << "> container volume with " << ptVolume.constituentVolumes.size() << " constituents."); @@ -131,7 +132,7 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( if (layerSurfaces.size() == 1u) { auto surface = layerSurfaces[0u].second; const auto& transform = surface->transform(gctx); - if (plVolume.layerType == Acts::Surface::SurfaceType::Cylinder) { + if (plVolume.legacyLayerType == Acts::Surface::SurfaceType::Cylinder) { ACTS_VERBOSE(indent + ">> creating cylinder layer from a single surface."); // Get the bounds @@ -143,7 +144,7 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( CylinderLayer::create(transform, cylinderBoundsClone, nullptr, 1.); cylinderLayer->assignSurfaceMaterial(surface->surfaceMaterialSharedPtr()); tLayer = cylinderLayer; - } else if (plVolume.layerType == Acts::Surface::SurfaceType::Disc) { + } else if (plVolume.legacyLayerType == Acts::Surface::SurfaceType::Disc) { ACTS_VERBOSE(indent + ">> creating cylinder layer from a single surface."); // Get the bounds @@ -170,15 +171,15 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( std::size_t bins0 = 0; std::size_t bins1 = 0; // In case explicit binning is given - if (plVolume.layerSurfaceBinning.size() == 2u) { - bType0 = plVolume.layerSurfaceBinning[0u].type; - bType1 = plVolume.layerSurfaceBinning[1u].type; + if (plVolume.surfaceBinning.size() == 2u) { + bType0 = plVolume.surfaceBinning[0u].type; + bType1 = plVolume.surfaceBinning[1u].type; // In case explicit bin numbers are given in addition if (bType0 == Acts::equidistant and bType1 == Acts::equidistant and - plVolume.layerSurfaceBinning[0u].bins() > 1u and - plVolume.layerSurfaceBinning[1u].bins() > 1u) { - bins0 = plVolume.layerSurfaceBinning[0u].bins(); - bins1 = plVolume.layerSurfaceBinning[1u].bins(); + plVolume.surfaceBinning[0u].bins() > 1u and + plVolume.surfaceBinning[1u].bins() > 1u) { + bins0 = plVolume.surfaceBinning[0u].bins(); + bins1 = plVolume.surfaceBinning[1u].bins(); ACTS_VERBOSE(indent + ">> binning provided externally to be " << bins0 << " x " << bins1 << "."); } @@ -186,7 +187,7 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( Acts::ProtoLayer pLayer(gctx, cLayerSurfaces); pLayer.envelope = plVolume.extent.envelope(); - if (plVolume.layerType == Acts::Surface::SurfaceType::Cylinder) { + if (plVolume.legacyLayerType == Acts::Surface::SurfaceType::Cylinder) { ACTS_VERBOSE(indent + ">> creating cylinder layer with " << cLayerSurfaces.size() << " surfaces."); // Forced equidistant or auto-binned @@ -196,7 +197,7 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( : m_cfg.layerCreator->cylinderLayer(gctx, cLayerSurfaces, bType0, bType1, pLayer); - } else if (plVolume.layerType == Acts::Surface::SurfaceType::Disc) { + } else if (plVolume.legacyLayerType == Acts::Surface::SurfaceType::Disc) { ACTS_VERBOSE(indent + ">> creating disc layer with " << cLayerSurfaces.size() << " surfaces."); // Forced equidistant or auto-binned @@ -214,4 +215,4 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( } return tLayer; -} \ No newline at end of file +} diff --git a/Core/src/Geometry/ProtoDetector.cpp b/Core/src/Geometry/ProtoDetector.cpp index 5ce22fb7ee1..8012d865057 100644 --- a/Core/src/Geometry/ProtoDetector.cpp +++ b/Core/src/Geometry/ProtoDetector.cpp @@ -55,17 +55,16 @@ void Acts::ProtoVolume::harmonize(bool legacy) { } // For legacy volumes, check if layers are present - bool layersPresent = layerContainer; + bool layersPresent = legacyLayerType != Surface::SurfaceType::Other; for (const auto& cv : constituentVolumes) { layersPresent = - layersPresent or cv.layerType != Surface::SurfaceType::Other; + layersPresent or cv.legacyLayerType != Surface::SurfaceType::Other; if (layersPresent) { break; } } // If layers are present, it can't be a container in the legacy style - layerContainer = layersPresent; auto binValue = constituentBinning[0].binvalue; // Set the first last auto& fVolume = constituentVolumes.front(); @@ -80,8 +79,8 @@ void Acts::ProtoVolume::harmonize(bool legacy) { } } - // Legacy conversion - layers are kept untouched - if (not layerContainer) { + // Legacy conversion - layers are kept untouched + if (not layersPresent) { // Set the outer boundaries fVolume.extent.set(binValue, extent.min(binValue), fVolume.extent.max(binValue)); @@ -104,7 +103,7 @@ void Acts::ProtoVolume::harmonize(bool legacy) { } borders.push_back(constituentVolumes.back().extent.max(binValue)); - } else if (layerContainer and not legacy) { + } else if (layersPresent and not legacy) { // Count the gaps std::size_t gaps = 0; std::vector boundaries = {}; @@ -149,7 +148,7 @@ void Acts::ProtoVolume::harmonize(bool legacy) { borders.push_back(static_cast(containerMax)); } constituentVolumes = updatedConstituents; - } else if (legacy and layerContainer) { + } else if (legacy and layersPresent) { borders = {0., 1.}; } constituentBinning = { @@ -164,13 +163,13 @@ void Acts::ProtoVolume::harmonize(bool legacy) { } bool Acts::ProtoVolume::operator==(const Acts::ProtoVolume& ptVolume) const { - // Simple checks - if (name != ptVolume.name or extent != ptVolume.extent or - layerContainer != ptVolume.layerContainer or - layerType != ptVolume.layerType) { + if (name != ptVolume.name or extent != ptVolume.extent) { return false; } - if (layerSurfaceBinning != ptVolume.layerSurfaceBinning) { + if (legacyLayerType != ptVolume.legacyLayerType) { + return false; + } + if (surfaceBinning != ptVolume.surfaceBinning) { return false; } if (constituentVolumes != ptVolume.constituentVolumes or diff --git a/Tests/UnitTests/Core/Geometry/KDTreeTrackingGeometryBuilderTests.cpp b/Tests/UnitTests/Core/Geometry/KDTreeTrackingGeometryBuilderTests.cpp index ab2d49b1314..e41f3e40999 100644 --- a/Tests/UnitTests/Core/Geometry/KDTreeTrackingGeometryBuilderTests.cpp +++ b/Tests/UnitTests/Core/Geometry/KDTreeTrackingGeometryBuilderTests.cpp @@ -95,11 +95,10 @@ BOOST_AUTO_TEST_CASE(KDTreeTrackingGeometryBuilder_simple) { Acts::ProtoVolume beamPipe; beamPipe.name = "odd-beam-pipe-l"; beamPipe.extent.set(Acts::binR, 2., 16.); - beamPipe.layerType = Acts::Surface::SurfaceType::Cylinder; + beamPipe.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; beamPipeContainer.constituentVolumes = {beamPipe}; beamPipeContainer.constituentBinning = { Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}; - beamPipeContainer.layerContainer = true; // Pixel section Acts::ProtoVolume pixelContainer; @@ -121,9 +120,8 @@ BOOST_AUTO_TEST_CASE(KDTreeTrackingGeometryBuilder_simple) { pixelNec.constituentBinning = { Acts::BinningData(Acts::open, Acts::binZ, {0., 1.})}; for (auto& cv : pixelNec.constituentVolumes) { - cv.layerType = Acts::Surface::SurfaceType::Disc; + cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; } - pixelNec.layerContainer = true; Acts::ProtoVolume pixelBarrel; pixelBarrel.name = "odd-pixel-barrel"; @@ -133,28 +131,27 @@ BOOST_AUTO_TEST_CASE(KDTreeTrackingGeometryBuilder_simple) { pixBarrelL0.name = "odd-pixel-barrel-l0"; pixBarrelL0.extent.set(Acts::binR, 28., 48.); pixBarrelL0.extent.set(Acts::binZ, -580., 580); - pixBarrelL0.layerType = Acts::Surface::SurfaceType::Cylinder; + pixBarrelL0.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; Acts::ProtoVolume pixBarrelL1; pixBarrelL1.name = "odd-pixel-barrel-l1"; pixBarrelL1.extent.set(Acts::binR, 62., 76); pixBarrelL1.extent.set(Acts::binZ, -580., 580); - pixBarrelL1.layerType = Acts::Surface::SurfaceType::Cylinder; + pixBarrelL1.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; Acts::ProtoVolume pixBarrelL2; pixBarrelL2.name = "odd-pixel-barrel-l2"; pixBarrelL2.extent.set(Acts::binR, 100., 120.); pixBarrelL2.extent.set(Acts::binZ, -580., 580); - pixBarrelL2.layerType = Acts::Surface::SurfaceType::Cylinder; + pixBarrelL2.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; Acts::ProtoVolume pixBarrelL3; pixBarrelL3.name = "odd-pixel-barrel-l3"; pixBarrelL3.extent.set(Acts::binR, 160., 180.); pixBarrelL3.extent.set(Acts::binZ, -580., 580); - pixBarrelL3.layerType = Acts::Surface::SurfaceType::Cylinder; + pixBarrelL3.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; pixelBarrel.constituentVolumes = {pixBarrelL0, pixBarrelL1, pixBarrelL2, pixBarrelL3}; pixelBarrel.constituentBinning = { Acts::BinningData(Acts::open, Acts::binR, {0., 1})}; - pixelBarrel.layerContainer = true; Acts::ProtoVolume pixelPec; pixelPec.name = "odd-pixel-pec"; @@ -171,9 +168,8 @@ BOOST_AUTO_TEST_CASE(KDTreeTrackingGeometryBuilder_simple) { pixelPec.constituentBinning = { Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; for (auto& cv : pixelPec.constituentVolumes) { - cv.layerType = Acts::Surface::SurfaceType::Disc; + cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; } - pixelPec.layerContainer = true; pixelContainer.constituentVolumes = {pixelNec, pixelBarrel, pixelPec}; pixelContainer.constituentBinning = { diff --git a/Tests/UnitTests/Core/Geometry/ProtoDetectorTests.cpp b/Tests/UnitTests/Core/Geometry/ProtoDetectorTests.cpp index 17c570a9589..87dfa1c3482 100644 --- a/Tests/UnitTests/Core/Geometry/ProtoDetectorTests.cpp +++ b/Tests/UnitTests/Core/Geometry/ProtoDetectorTests.cpp @@ -53,12 +53,12 @@ Acts::ProtoDetector createProtoDetector() { Acts::ProtoVolume pixelBarrelL0; pixelBarrelL0.name = "pixel-barrel-l0"; pixelBarrelL0.extent.set(Acts::binR, 45., 50.); - pixelBarrelL0.layerType = Acts::Surface::SurfaceType::Cylinder; + pixelBarrelL0.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; Acts::ProtoVolume pixelBarrelL1; pixelBarrelL1.name = "pixel-barrel-l1"; pixelBarrelL1.extent.set(Acts::binR, 70., 80.); - pixelBarrelL1.layerType = Acts::Surface::SurfaceType::Cylinder; + pixelBarrelL1.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; pixelBarrel.constituentVolumes = {pixelBarrelL0, pixelBarrelL1}; pixelBarrel.constituentBinning = { @@ -99,9 +99,6 @@ BOOST_AUTO_TEST_CASE(ProtoTrackingGeometryTests) { // Get the top detector volume auto& detectorVolume = detector.worldVolume; - // Check the container is NOT a layer Container - BOOST_CHECK(detectorVolume.layerContainer == false); - // The detector volume should have received maximum dimensions CHECK_CLOSE_ABS(detectorVolume.extent.min(Acts::binR), 0, std::numeric_limits::epsilon()); @@ -140,7 +137,6 @@ BOOST_AUTO_TEST_CASE(ProtoTrackingGeometryTests) { // The second volume is the pixel detector auto& pixelContainer = detectorVolume.constituentVolumes[1u]; BOOST_CHECK(pixelContainer.name == "pixel-container"); - BOOST_CHECK(pixelContainer.layerContainer == false); // Pixel contaienr should have fitting boundaries CHECK_CLOSE_ABS(pixelContainer.extent.min(Acts::binR), 35., @@ -177,15 +173,6 @@ BOOST_AUTO_TEST_CASE(ProtoTrackingGeometryTests) { std::numeric_limits::epsilon()); CHECK_CLOSE_ABS(binBoundariesZ[3u], 2000., std::numeric_limits::epsilon()); - - auto& pixelNec = pixelContainer.constituentVolumes[0u]; - BOOST_CHECK(pixelNec.layerContainer == false); - - auto& pixelBarrel = pixelContainer.constituentVolumes[1u]; - BOOST_CHECK(pixelBarrel.layerContainer == true); - - auto& pixelPec = pixelContainer.constituentVolumes[2u]; - BOOST_CHECK(pixelPec.layerContainer == false); } BOOST_AUTO_TEST_CASE(ProtoDetectorTests) { From ffde08de49a36c03f0357ea8042d23a9fb33dbb4 Mon Sep 17 00:00:00 2001 From: Andreas Salzburger Date: Thu, 5 Jan 2023 15:39:24 +0100 Subject: [PATCH 09/13] adding PR comments from PR, part1 --- .../Json/src/ProtoDetectorJsonConverter.cpp | 14 ++++--- .../Json/ProtoDetectorJsonConverterTests.cpp | 42 +++++++------------ 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/Plugins/Json/src/ProtoDetectorJsonConverter.cpp b/Plugins/Json/src/ProtoDetectorJsonConverter.cpp index 6daf030bcd7..971783b4968 100644 --- a/Plugins/Json/src/ProtoDetectorJsonConverter.cpp +++ b/Plugins/Json/src/ProtoDetectorJsonConverter.cpp @@ -15,8 +15,9 @@ void Acts::to_json(nlohmann::json& j, const Acts::ProtoVolume& pv) { j["name"] = pv.name; j["extent"] = pv.extent; - j["layerContainer"] = pv.layerContainer; - j["layerType"] = static_cast(pv.layerType); + if (pv.legacyLayerType != Surface::SurfaceType::Other) { + j["layerType"] = static_cast(pv.legacyLayerType); + } // Helper m ethod to write binnings auto writeBinning = [&](const std::vector& binning, @@ -27,7 +28,7 @@ void Acts::to_json(nlohmann::json& j, const Acts::ProtoVolume& pv) { } j[key] = jbinning; }; - writeBinning(pv.layerSurfaceBinning, "layerSurfaceBinning"); + writeBinning(pv.surfaceBinning, "surfaceBinning"); nlohmann::json constituents; for (const auto& pvc : pv.constituentVolumes) { constituents.push_back(pvc); @@ -39,8 +40,9 @@ void Acts::to_json(nlohmann::json& j, const Acts::ProtoVolume& pv) { void Acts::from_json(const nlohmann::json& j, Acts::ProtoVolume& pv) { pv.name = j["name"]; pv.extent = j["extent"]; - pv.layerContainer = j["layerContainer"]; - pv.layerType = static_cast(j["layerType"]); + if (j.find("layerType") != j.end()) { + pv.legacyLayerType = static_cast(j["layerType"]); + } // Helper method to read binnings auto readBinning = [&](std::vector& binning, @@ -49,7 +51,7 @@ void Acts::from_json(const nlohmann::json& j, Acts::ProtoVolume& pv) { binning.push_back(jbinning); } }; - readBinning(pv.layerSurfaceBinning, "layerSurfaceBinning"); + readBinning(pv.surfaceBinning, "surfaceBinning"); for (const auto& jc : j["constituents"]) { pv.constituentVolumes.push_back(jc); } diff --git a/Tests/UnitTests/Plugins/Json/ProtoDetectorJsonConverterTests.cpp b/Tests/UnitTests/Plugins/Json/ProtoDetectorJsonConverterTests.cpp index b2b37c8098e..00f21316c27 100644 --- a/Tests/UnitTests/Plugins/Json/ProtoDetectorJsonConverterTests.cpp +++ b/Tests/UnitTests/Plugins/Json/ProtoDetectorJsonConverterTests.cpp @@ -36,11 +36,10 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { Acts::ProtoVolume beamPipe; beamPipe.name = "odd-beam-pipe-l"; beamPipe.extent.set(Acts::binR, 2., 24.); - beamPipe.layerType = Acts::Surface::SurfaceType::Cylinder; + beamPipe.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; beamPipeContainer.constituentVolumes = {beamPipe}; beamPipeContainer.constituentBinning = { Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}; - beamPipeContainer.layerContainer = true; // Pixel section Acts::ProtoVolume pixelContainer; @@ -83,11 +82,10 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { pixelNec.constituentBinning = { Acts::BinningData(Acts::open, Acts::binZ, {0., 1.})}; for (auto& cv : pixelNec.constituentVolumes) { - cv.layerType = Acts::Surface::SurfaceType::Disc; - cv.layerSurfaceBinning = {pixEcBinningR, pixEcBinningPhi}; + cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; + cv.surfaceBinning = {pixEcBinningR, pixEcBinningPhi}; cv.extent.setEnvelope(discLayerEnvelope); } - pixelNec.layerContainer = true; Acts::ProtoVolume pixelBarrel; pixelBarrel.name = "odd-pixel-barrel"; @@ -113,13 +111,12 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { pixelBarrel.constituentVolumes = {pixBarrelL0, pixBarrelL1, pixBarrelL2, pixBarrelL3}; for (auto& cv : pixelBarrel.constituentVolumes) { - cv.layerType = Acts::Surface::SurfaceType::Cylinder; + cv.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; cv.extent.setEnvelope(cylinderLayerEnvelope); } pixelBarrel.constituentBinning = { Acts::BinningData(Acts::open, Acts::binR, {0., 1})}; - pixelBarrel.layerContainer = true; Acts::ProtoVolume pixelPec; pixelPec.name = "odd-pixel-pec"; @@ -152,11 +149,10 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { pixelPec.constituentBinning = { Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; for (auto& cv : pixelPec.constituentVolumes) { - cv.layerType = Acts::Surface::SurfaceType::Disc; - cv.layerSurfaceBinning = {pixEcBinningR, pixEcBinningPhi}; + cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; + cv.surfaceBinning = {pixEcBinningR, pixEcBinningPhi}; cv.extent.setEnvelope(discLayerEnvelope); } - pixelPec.layerContainer = true; pixelContainer.constituentVolumes = {pixelNec, pixelBarrel, pixelPec}; pixelContainer.constituentBinning = { @@ -169,11 +165,10 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { Acts::ProtoVolume pst; pst.name = "odd-pst-l"; pst.extent.set(Acts::binR, 201., 209.); - pst.layerType = Acts::Surface::SurfaceType::Cylinder; + pst.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; pstContainer.constituentVolumes = {pst}; pstContainer.constituentBinning = { Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}; - pstContainer.layerContainer = true; // Short Strip section Acts::ProtoVolume sstripContainer; @@ -212,11 +207,10 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { sstripNec.constituentBinning = { Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; for (auto& cv : sstripNec.constituentVolumes) { - cv.layerType = Acts::Surface::SurfaceType::Disc; - cv.layerSurfaceBinning = {sstripEcBinningR, sstripEcBinningPhi}; + cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; + cv.surfaceBinning = {sstripEcBinningR, sstripEcBinningPhi}; cv.extent.setEnvelope(discLayerEnvelope); } - sstripNec.layerContainer = true; Acts::ProtoVolume sstripBarrel; sstripBarrel.name = "odd-sstrip-barrel"; @@ -238,13 +232,12 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { sstripBarrel.constituentVolumes = {sstripBarrelL0, sstripBarrelL1, sstripBarrelL2, sstripBarrelL3}; for (auto& cv : sstripBarrel.constituentVolumes) { - cv.layerType = Acts::Surface::SurfaceType::Cylinder; + cv.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; cv.extent.setEnvelope(cylinderLayerEnvelope); } sstripBarrel.constituentBinning = { Acts::BinningData(Acts::open, Acts::binR, {0., 1})}; - sstripBarrel.layerContainer = true; Acts::ProtoVolume sstripPec; sstripPec.name = "odd-sstrip-pec"; @@ -274,11 +267,10 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { sstripPec.constituentBinning = { Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; for (auto& cv : sstripPec.constituentVolumes) { - cv.layerType = Acts::Surface::SurfaceType::Disc; - cv.layerSurfaceBinning = {sstripEcBinningR, sstripEcBinningPhi}; + cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; + cv.surfaceBinning = {sstripEcBinningR, sstripEcBinningPhi}; cv.extent.setEnvelope(discLayerEnvelope); } - sstripPec.layerContainer = true; sstripContainer.constituentBinning = {Acts::BinningData( Acts::open, Acts::binZ, {-3100., -1200., 1200., 3100.})}; @@ -316,10 +308,9 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { lstripNec.constituentBinning = { Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; for (auto& cv : lstripNec.constituentVolumes) { - cv.layerType = Acts::Surface::SurfaceType::Disc; + cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; cv.extent.setEnvelope(discLayerEnvelope); } - lstripNec.layerContainer = true; Acts::ProtoVolume lstripBarrel; lstripBarrel.name = "odd-lstrip-barrel"; @@ -334,13 +325,12 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { lstripBarrel.constituentVolumes = {lstripBarrelL0, lstripBarrelL1}; for (auto& cv : lstripBarrel.constituentVolumes) { - cv.layerType = Acts::Surface::SurfaceType::Cylinder; + cv.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; cv.extent.setEnvelope(cylinderLayerEnvelope); } lstripBarrel.constituentBinning = { Acts::BinningData(Acts::open, Acts::binR, {0., 1})}; - lstripBarrel.layerContainer = true; Acts::ProtoVolume lstripPec; lstripPec.name = "odd-lstrip-pec"; @@ -370,11 +360,9 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { lstripPec.constituentBinning = { Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; for (auto& cv : lstripPec.constituentVolumes) { - cv.layerType = Acts::Surface::SurfaceType::Disc; + cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; cv.extent.setEnvelope(discLayerEnvelope); } - lstripPec.layerContainer = true; - lstripContainer.constituentVolumes = {lstripNec, lstripBarrel, lstripPec}; lstripContainer.constituentBinning = {Acts::BinningData( Acts::open, Acts::binZ, {-3100., -1200., 1200., 3100.})}; From 9fb23f1265b873546127aa7079483cfd7b2d00bc Mon Sep 17 00:00:00 2001 From: Andreas Salzburger Date: Fri, 6 Jan 2023 11:52:03 +0100 Subject: [PATCH 10/13] introducing (optional) Internal/Container structs --- Core/include/Acts/Geometry/ProtoDetector.hpp | 38 +++--- .../KDTreeTrackingGeometryBuilder.cpp | 128 ++++++++++++------ Core/src/Geometry/ProtoDetector.cpp | 125 ++++++++--------- .../KDTreeTrackingGeometryBuilderTests.cpp | 86 ++++++------ .../Core/Geometry/ProtoDetectorTests.cpp | 69 +++++++--- 5 files changed, 259 insertions(+), 187 deletions(-) diff --git a/Core/include/Acts/Geometry/ProtoDetector.hpp b/Core/include/Acts/Geometry/ProtoDetector.hpp index c349a5eed99..238e6403be9 100644 --- a/Core/include/Acts/Geometry/ProtoDetector.hpp +++ b/Core/include/Acts/Geometry/ProtoDetector.hpp @@ -22,21 +22,34 @@ namespace Acts { /// A proto volume description being used to define an overall /// structure of either a TrackingVolume or Experimental::DetectorVolume struct ProtoVolume { + // Internal structure information + struct InternalStructure { + /// Possibility to provide a layer type information + Surface::SurfaceType layerType = Surface::SurfaceType::Other; + /// Possibility to provide a surface binning + std::vector surfaceBinning = {}; + }; + + // Container structure information + struct ContainerStructure { + /// Internal structure container + std::vector constituentVolumes = {}; + /// The constituent binning if this a container + std::vector constituentBinning = {}; + /// Layer container flag + bool layerContainer = false; + }; + /// Name of the proto volume std::string name = ""; /// The extent of this volume Extent extent; - /// Information for legacy type building - Acts::Surface::SurfaceType legacyLayerType = - Acts::Surface::SurfaceType::Other; + /// Information about internal structure + std::optional internal = std::nullopt; - /// The surface binninng for internal surfaces (optional) - std::vector surfaceBinning = {}; - /// Internal structure container - std::vector constituentVolumes = {}; - /// The constituent binning if this a container - std::vector constituentBinning = {}; + /// Information about container structure + std::optional container = std::nullopt; /// Define an operator== /// @@ -93,13 +106,6 @@ struct ProtoDetector { worldVolume.harmonize(legacy); } - /// Define an operator== - /// - /// @param pd the proto detector to be checked - bool operator==(const ProtoDetector& pd) const { - return (name == pd.name and worldVolume == pd.worldVolume); - } - /// Write the tracking volume to screen /// @param indent the current indentation std::string toString(const std::string& indent = "") const; diff --git a/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp b/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp index ae4e876b776..b31b9cbee65 100644 --- a/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp +++ b/Core/src/Geometry/KDTreeTrackingGeometryBuilder.cpp @@ -68,45 +68,68 @@ Acts::KDTreeTrackingGeometryBuilder::translateVolume( ACTS_DEBUG(indent << "Processing ProtoVolume: " << ptVolume.name); std::vector> translatedVolumes = {}; - if (not ptVolume.constituentVolumes.empty() and - ptVolume.legacyLayerType == Surface::SurfaceType::Other) { - ACTS_VERBOSE(indent << "> container volume with " - << ptVolume.constituentVolumes.size() - << " constituents."); - for (auto& cVolume : ptVolume.constituentVolumes) { - auto dtVolume = translateVolume(cCache, gctx, kdt, cVolume, - indent + m_cfg.hierarchyIndent); - translatedVolumes.push_back(dtVolume); - } - // Make a container volume - auto tVolume = m_cfg.trackingVolumeHelper->createContainerTrackingVolume( - gctx, translatedVolumes); - ACTS_DEBUG(indent << "> translated into container volume bounds: " + // Volume extent + auto rangeR = ptVolume.extent.range(Acts::binR); + auto rangeZ = ptVolume.extent.range(Acts::binZ); + + // Simple gap volume + if (not ptVolume.container.has_value()) { + ACTS_VERBOSE(indent << "> empty volume to be built"); + MutableTrackingVolumeVector mtv = {}; + auto tVolume = m_cfg.trackingVolumeHelper->createGapTrackingVolume( + gctx, mtv, nullptr, rangeR.min(), rangeR.max(), rangeZ.min(), + rangeZ.max(), 0, false, ptVolume.name); + ACTS_DEBUG(indent << "> translated into gap volume bounds: " << tVolume->volumeBounds()); return tVolume; - } + } else { + // Get the container information + auto& cts = ptVolume.container.value(); - std::vector> layers = {}; - if (not ptVolume.constituentVolumes.empty()) { - ACTS_VERBOSE(indent << "> layer volume with " - << ptVolume.constituentVolumes.size() - << " layer volumes."); - for (auto& plVolume : ptVolume.constituentVolumes) { - layers.push_back(translateLayer(cCache, gctx, kdt, plVolume, - indent + m_cfg.hierarchyIndent)); + // Container information must be present + if (cts.constituentVolumes.empty()) { + throw std::invalid_argument( + "KDTreeTrackingGeometryBuilder: no consituents given."); + } + + // This volume is a volume container + if (not cts.layerContainer) { + ACTS_VERBOSE(indent << "> volume container with " + << cts.constituentVolumes.size() << " constituents."); + for (auto& cVolume : cts.constituentVolumes) { + auto dtVolume = translateVolume(cCache, gctx, kdt, cVolume, + indent + m_cfg.hierarchyIndent); + translatedVolumes.push_back(dtVolume); + } + auto tVolume = m_cfg.trackingVolumeHelper->createContainerTrackingVolume( + gctx, translatedVolumes); + ACTS_DEBUG(indent << "> translated into container volume bounds: " + << tVolume->volumeBounds()); + return tVolume; + } else { + // This volume is a layer container + std::vector> layers = {}; + ACTS_VERBOSE(indent << "> layer container with " + << cts.constituentVolumes.size() << " layers."); + for (auto& plVolume : cts.constituentVolumes) { + if (plVolume.internal.has_value()) { + layers.push_back(translateLayer(cCache, gctx, kdt, plVolume, + indent + m_cfg.hierarchyIndent)); + } else { + ACTS_WARNING(indent << "> layer type volume has no internal " + "description, layer not built."); + } + } + // Create a new tracking volume with those layers + auto tVolume = m_cfg.trackingVolumeHelper->createTrackingVolume( + gctx, layers, {}, nullptr, rangeR.min(), rangeR.max(), rangeZ.min(), + rangeZ.max(), ptVolume.name); + ACTS_DEBUG(indent << "> translated into bounds: " + << tVolume->volumeBounds()); + return tVolume; } - ACTS_VERBOSE("> translated into " << layers.size() << " layers."); - // Create a volume - auto rangeR = ptVolume.extent.range(Acts::binR); - auto rangeZ = ptVolume.extent.range(Acts::binZ); - // Create a new tracking volume with those layers - auto tVolume = m_cfg.trackingVolumeHelper->createTrackingVolume( - gctx, layers, {}, nullptr, rangeR.min(), rangeR.max(), rangeZ.min(), - rangeZ.max(), ptVolume.name); - ACTS_DEBUG(indent << "> translated into bounds: " - << tVolume->volumeBounds()); - return tVolume; } + return nullptr; } @@ -116,6 +139,10 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( Cache& cCache, const GeometryContext& gctx, const SurfaceKDT& kdt, const ProtoVolume& plVolume, const std::string& indent) const { ACTS_DEBUG(indent + "Processing ProtoVolume: " << plVolume.name); + + // This is only called if the volume has internal structure + auto& its = plVolume.internal.value(); + // Try to pull from the kd tree RangeXD<2u, ActsScalar> zrRange; zrRange[0u] = plVolume.extent.range(Acts::binZ); @@ -132,7 +159,7 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( if (layerSurfaces.size() == 1u) { auto surface = layerSurfaces[0u].second; const auto& transform = surface->transform(gctx); - if (plVolume.legacyLayerType == Acts::Surface::SurfaceType::Cylinder) { + if (its.layerType == Acts::Surface::SurfaceType::Cylinder) { ACTS_VERBOSE(indent + ">> creating cylinder layer from a single surface."); // Get the bounds @@ -144,7 +171,7 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( CylinderLayer::create(transform, cylinderBoundsClone, nullptr, 1.); cylinderLayer->assignSurfaceMaterial(surface->surfaceMaterialSharedPtr()); tLayer = cylinderLayer; - } else if (plVolume.legacyLayerType == Acts::Surface::SurfaceType::Disc) { + } else if (its.layerType == Acts::Surface::SurfaceType::Disc) { ACTS_VERBOSE(indent + ">> creating cylinder layer from a single surface."); // Get the bounds @@ -156,6 +183,10 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( DiscLayer::create(transform, radialBoundsClone, nullptr, 1.); discLayer->assignSurfaceMaterial(surface->surfaceMaterialSharedPtr()); tLayer = discLayer; + } else { + throw std::invalid_argument( + "KDTreeTrackingGeometryBuilder: layer type is neither cylinder nor " + "disk."); } } else if (layerSurfaces.size() > 1u) { @@ -171,15 +202,15 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( std::size_t bins0 = 0; std::size_t bins1 = 0; // In case explicit binning is given - if (plVolume.surfaceBinning.size() == 2u) { - bType0 = plVolume.surfaceBinning[0u].type; - bType1 = plVolume.surfaceBinning[1u].type; + if (its.surfaceBinning.size() == 2u) { + bType0 = its.surfaceBinning[0u].type; + bType1 = its.surfaceBinning[1u].type; // In case explicit bin numbers are given in addition if (bType0 == Acts::equidistant and bType1 == Acts::equidistant and - plVolume.surfaceBinning[0u].bins() > 1u and - plVolume.surfaceBinning[1u].bins() > 1u) { - bins0 = plVolume.surfaceBinning[0u].bins(); - bins1 = plVolume.surfaceBinning[1u].bins(); + its.surfaceBinning[0u].bins() > 1u and + its.surfaceBinning[1u].bins() > 1u) { + bins0 = its.surfaceBinning[0u].bins(); + bins1 = its.surfaceBinning[1u].bins(); ACTS_VERBOSE(indent + ">> binning provided externally to be " << bins0 << " x " << bins1 << "."); } @@ -187,7 +218,7 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( Acts::ProtoLayer pLayer(gctx, cLayerSurfaces); pLayer.envelope = plVolume.extent.envelope(); - if (plVolume.legacyLayerType == Acts::Surface::SurfaceType::Cylinder) { + if (its.layerType == Acts::Surface::SurfaceType::Cylinder) { ACTS_VERBOSE(indent + ">> creating cylinder layer with " << cLayerSurfaces.size() << " surfaces."); // Forced equidistant or auto-binned @@ -197,7 +228,7 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( : m_cfg.layerCreator->cylinderLayer(gctx, cLayerSurfaces, bType0, bType1, pLayer); - } else if (plVolume.legacyLayerType == Acts::Surface::SurfaceType::Disc) { + } else if (its.layerType == Acts::Surface::SurfaceType::Disc) { ACTS_VERBOSE(indent + ">> creating disc layer with " << cLayerSurfaces.size() << " surfaces."); // Forced equidistant or auto-binned @@ -207,11 +238,18 @@ Acts::KDTreeTrackingGeometryBuilder::translateLayer( : m_cfg.layerCreator->discLayer(gctx, cLayerSurfaces, bType0, bType1, pLayer); + } else { + throw std::invalid_argument( + "KDTreeTrackingGeometryBuilder: layer type is neither cylinder nor " + "disk."); } } if (tLayer != nullptr and tLayer->representingVolume() != nullptr) { ACTS_DEBUG(indent << "> translated into layer bounds: " << tLayer->representingVolume()->volumeBounds()); + } else { + throw std::runtime_error( + "KDTreeTrackingGeometryBuilder: layer was not built."); } return tLayer; diff --git a/Core/src/Geometry/ProtoDetector.cpp b/Core/src/Geometry/ProtoDetector.cpp index 8012d865057..55a7bb5d529 100644 --- a/Core/src/Geometry/ProtoDetector.cpp +++ b/Core/src/Geometry/ProtoDetector.cpp @@ -15,31 +15,38 @@ void Acts::ProtoVolume::extendUp(Acts::ProtoVolume& ptVolume) { ptVolume.extent.extend(extent); - - for (auto& cv : constituentVolumes) { - ptVolume.extent.extend(cv.extent); - cv.extendUp(ptVolume); + if (container.has_value()) { + for (auto& cv : container.value().constituentVolumes) { + ptVolume.extent.extend(cv.extent); + cv.extendUp(ptVolume); + } } } void Acts::ProtoVolume::propagateMinDown(BinningValue bValue) { - for (auto& cv : constituentVolumes) { - cv.extent.set(bValue, extent.min(bValue), cv.extent.max(bValue)); - cv.propagateMinDown(bValue); + if (container.has_value()) { + for (auto& cv : container.value().constituentVolumes) { + cv.extent.set(bValue, extent.min(bValue), cv.extent.max(bValue)); + cv.propagateMinDown(bValue); + } } } void Acts::ProtoVolume::propagateMaxDown(BinningValue bValue) { - for (auto& cv : constituentVolumes) { - cv.extent.set(bValue, cv.extent.min(bValue), extent.max(bValue)); - cv.propagateMaxDown(bValue); + if (container.has_value()) { + for (auto& cv : container.value().constituentVolumes) { + cv.extent.set(bValue, cv.extent.min(bValue), extent.max(bValue)); + cv.propagateMaxDown(bValue); + } } } void Acts::ProtoVolume::constrainDown(const Acts::ProtoVolume& ptVolume) { extent.addConstrain(ptVolume.extent); - for (auto& cv : constituentVolumes) { - cv.extent.addConstrain(extent); + if (container.has_value()) { + for (auto& cv : container.value().constituentVolumes) { + cv.extent.addConstrain(extent); + } } } @@ -47,28 +54,30 @@ void Acts::ProtoVolume::harmonize(bool legacy) { std::vector otherConstrains; // Deal with the constituents - if (not constituentVolumes.empty()) { - if (constituentBinning.empty()) { + if (container.has_value() and + not container.value().constituentVolumes.empty()) { + auto& cts = container.value(); + + if (cts.constituentBinning.empty()) { std::string errorMsg = std::string("ProtoVolume '") + name + std::string("' with constituents, but no binning"); throw std::runtime_error(errorMsg); } - // For legacy volumes, check if layers are present - bool layersPresent = legacyLayerType != Surface::SurfaceType::Other; - for (const auto& cv : constituentVolumes) { - layersPresent = - layersPresent or cv.legacyLayerType != Surface::SurfaceType::Other; - if (layersPresent) { + // Check if there are any layers present + bool layersPresent = false; + for (const auto& cv : cts.constituentVolumes) { + if (cv.internal.has_value()) { + layersPresent = true; break; } } // If layers are present, it can't be a container in the legacy style - auto binValue = constituentBinning[0].binvalue; + auto binValue = cts.constituentBinning[0].binvalue; // Set the first last - auto& fVolume = constituentVolumes.front(); - auto& lVolume = constituentVolumes.back(); + auto& fVolume = cts.constituentVolumes.front(); + auto& lVolume = cts.constituentVolumes.back(); std::vector borders = {}; @@ -88,12 +97,12 @@ void Acts::ProtoVolume::harmonize(bool legacy) { extent.max(binValue)); // Align the containers borders.push_back(static_cast(fVolume.extent.min(binValue))); - for (unsigned int iv = 1; iv < constituentVolumes.size(); ++iv) { - auto& lv = constituentVolumes[iv - 1u]; + for (unsigned int iv = 1; iv < cts.constituentVolumes.size(); ++iv) { + auto& lv = cts.constituentVolumes[iv - 1u]; ActsScalar zero = lv.extent.min(binValue); ActsScalar low = lv.extent.max(binValue); - auto& hv = constituentVolumes[iv]; + auto& hv = cts.constituentVolumes[iv]; ActsScalar high = hv.extent.min(binValue); ActsScalar mid = 0.5 * (low + high); ActsScalar max = hv.extent.max(binValue); @@ -101,7 +110,7 @@ void Acts::ProtoVolume::harmonize(bool legacy) { hv.extent.set(binValue, mid, max); borders.push_back(mid); } - borders.push_back(constituentVolumes.back().extent.max(binValue)); + borders.push_back(cts.constituentVolumes.back().extent.max(binValue)); } else if (layersPresent and not legacy) { // Count the gaps @@ -118,14 +127,14 @@ void Acts::ProtoVolume::harmonize(bool legacy) { borders.push_back(static_cast(containerMin)); } // Fill the gaps - for (unsigned int iv = 1; iv < constituentVolumes.size(); ++iv) { - auto& lv = constituentVolumes[iv - 1u]; + for (unsigned int iv = 1; iv < cts.constituentVolumes.size(); ++iv) { + auto& lv = cts.constituentVolumes[iv - 1u]; // This volume is one to save updatedConstituents.push_back(lv); borders.push_back(static_cast(lv.extent.min(binValue))); // check if a gap to the next is needed ActsScalar low = lv.extent.max(binValue); - auto& hv = constituentVolumes[iv]; + auto& hv = cts.constituentVolumes[iv]; ActsScalar high = hv.extent.min(binValue); if (high > low) { ProtoVolume gap; @@ -147,36 +156,19 @@ void Acts::ProtoVolume::harmonize(bool legacy) { updatedConstituents.push_back(gap); borders.push_back(static_cast(containerMax)); } - constituentVolumes = updatedConstituents; + cts.constituentVolumes = updatedConstituents; } else if (legacy and layersPresent) { borders = {0., 1.}; } - constituentBinning = { - BinningData(constituentBinning[0].option, binValue, borders)}; - } + cts.constituentBinning = { + BinningData(cts.constituentBinning[0].option, binValue, borders)}; - // Harmonize downwards - for (auto& cv : constituentVolumes) { - cv.extent.extend(extent, otherConstrains); - cv.harmonize(legacy); - } -} - -bool Acts::ProtoVolume::operator==(const Acts::ProtoVolume& ptVolume) const { - if (name != ptVolume.name or extent != ptVolume.extent) { - return false; - } - if (legacyLayerType != ptVolume.legacyLayerType) { - return false; - } - if (surfaceBinning != ptVolume.surfaceBinning) { - return false; - } - if (constituentVolumes != ptVolume.constituentVolumes or - constituentBinning != ptVolume.constituentBinning) { - return false; + // Harmonize downwards + for (auto& cv : cts.constituentVolumes) { + cv.extent.extend(extent, otherConstrains); + cv.harmonize(legacy); + } } - return true; } std::string Acts::ProtoVolume::toString(const std::string& indent) const { @@ -185,16 +177,19 @@ std::string Acts::ProtoVolume::toString(const std::string& indent) const { ss << indent << "> volume: " << name << '\n'; ss << indent << " extent: "; ss << extent.toString(indent) << '\n'; - if (not constituentVolumes.empty()) { - ss << indent << " container of " << constituentVolumes.size() - << " constituents. " << '\n'; - ss << indent << " constituent binning:" << '\n'; - for (const auto& cb : constituentBinning) { - ss << cb.toString(indent) << '\n'; - } - ss << indent << " constituents are:" << '\n'; - for (const auto& cv : constituentVolumes) { - ss << cv.toString(indent + subIndent) << '\n'; + if (container.has_value()) { + auto& cts = container.value(); + if (not cts.constituentVolumes.empty()) { + ss << indent << " container of " << cts.constituentVolumes.size() + << " constituents. " << '\n'; + ss << indent << " constituent binning:" << '\n'; + for (const auto& cb : cts.constituentBinning) { + ss << cb.toString(indent) << '\n'; + } + ss << indent << " constituents are:" << '\n'; + for (const auto& cv : cts.constituentVolumes) { + ss << cv.toString(indent + subIndent) << '\n'; + } } } return ss.str(); diff --git a/Tests/UnitTests/Core/Geometry/KDTreeTrackingGeometryBuilderTests.cpp b/Tests/UnitTests/Core/Geometry/KDTreeTrackingGeometryBuilderTests.cpp index e41f3e40999..c98e3e97409 100644 --- a/Tests/UnitTests/Core/Geometry/KDTreeTrackingGeometryBuilderTests.cpp +++ b/Tests/UnitTests/Core/Geometry/KDTreeTrackingGeometryBuilderTests.cpp @@ -95,10 +95,10 @@ BOOST_AUTO_TEST_CASE(KDTreeTrackingGeometryBuilder_simple) { Acts::ProtoVolume beamPipe; beamPipe.name = "odd-beam-pipe-l"; beamPipe.extent.set(Acts::binR, 2., 16.); - beamPipe.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; - beamPipeContainer.constituentVolumes = {beamPipe}; - beamPipeContainer.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}; + beamPipe.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Cylinder}; + beamPipeContainer.container = Acts::ProtoVolume::ContainerStructure{ + {beamPipe}, {Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}, true}; // Pixel section Acts::ProtoVolume pixelContainer; @@ -115,12 +115,13 @@ BOOST_AUTO_TEST_CASE(KDTreeTrackingGeometryBuilder_simple) { Acts::ProtoVolume pixNecD0; pixNecD0.name = "odd-pixel-nec-d0"; pixNecD0.extent.set(Acts::binZ, -620., -580); - pixelNec.constituentVolumes = {pixNecD1, pixNecD0}; - - pixelNec.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binZ, {0., 1.})}; - for (auto& cv : pixelNec.constituentVolumes) { - cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; + pixelNec.container = Acts::ProtoVolume::ContainerStructure{ + {pixNecD1, pixNecD0}, + {Acts::BinningData(Acts::open, Acts::binZ, {0., 1.})}, + true}; + for (auto& cv : pixelNec.container.value().constituentVolumes) { + cv.internal = + Acts::ProtoVolume::InternalStructure{Acts::Surface::SurfaceType::Disc}; } Acts::ProtoVolume pixelBarrel; @@ -131,27 +132,31 @@ BOOST_AUTO_TEST_CASE(KDTreeTrackingGeometryBuilder_simple) { pixBarrelL0.name = "odd-pixel-barrel-l0"; pixBarrelL0.extent.set(Acts::binR, 28., 48.); pixBarrelL0.extent.set(Acts::binZ, -580., 580); - pixBarrelL0.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; + pixBarrelL0.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Cylinder}; Acts::ProtoVolume pixBarrelL1; pixBarrelL1.name = "odd-pixel-barrel-l1"; pixBarrelL1.extent.set(Acts::binR, 62., 76); pixBarrelL1.extent.set(Acts::binZ, -580., 580); - pixBarrelL1.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; + pixBarrelL1.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Cylinder}; Acts::ProtoVolume pixBarrelL2; pixBarrelL2.name = "odd-pixel-barrel-l2"; pixBarrelL2.extent.set(Acts::binR, 100., 120.); pixBarrelL2.extent.set(Acts::binZ, -580., 580); - pixBarrelL2.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; + pixBarrelL2.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Cylinder}; Acts::ProtoVolume pixBarrelL3; pixBarrelL3.name = "odd-pixel-barrel-l3"; pixBarrelL3.extent.set(Acts::binR, 160., 180.); pixBarrelL3.extent.set(Acts::binZ, -580., 580); - pixBarrelL3.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; + pixBarrelL3.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Cylinder}; - pixelBarrel.constituentVolumes = {pixBarrelL0, pixBarrelL1, pixBarrelL2, - pixBarrelL3}; - pixelBarrel.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binR, {0., 1})}; + pixelBarrel.container = Acts::ProtoVolume::ContainerStructure{ + {pixBarrelL0, pixBarrelL1, pixBarrelL2, pixBarrelL3}, + {Acts::BinningData(Acts::open, Acts::binR, {0., 1})}, + true}; Acts::ProtoVolume pixelPec; pixelPec.name = "odd-pixel-pec"; @@ -164,56 +169,59 @@ BOOST_AUTO_TEST_CASE(KDTreeTrackingGeometryBuilder_simple) { pixPecD1.name = "odd-pixel-pec-d1"; pixPecD1.extent.set(Acts::binZ, 680., 720); - pixelPec.constituentVolumes = {pixPecD0, pixPecD1}; - pixelPec.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; - for (auto& cv : pixelPec.constituentVolumes) { - cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; + pixelPec.container = Acts::ProtoVolume::ContainerStructure{ + {pixPecD0, pixPecD1}, + {Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}, + true}; + for (auto& cv : pixelPec.container.value().constituentVolumes) { + cv.internal = + Acts::ProtoVolume::InternalStructure{Acts::Surface::SurfaceType::Disc}; } - pixelContainer.constituentVolumes = {pixelNec, pixelBarrel, pixelPec}; - pixelContainer.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binZ, {-1000., -580., 580., 1000.})}; + pixelContainer.container = Acts::ProtoVolume::ContainerStructure{ + {pixelNec, pixelBarrel, pixelPec}, + {Acts::BinningData(Acts::open, Acts::binZ, + {-1000., -580., 580., 1000.})}}; Acts::ProtoVolume detectorContainer; detectorContainer.name = "odd-detector"; detectorContainer.extent.set(Acts::binR, 0., 200); - detectorContainer.constituentVolumes = {beamPipeContainer, pixelContainer}; - detectorContainer.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binR, {0., 17.5, 200.})}; + detectorContainer.container = Acts::ProtoVolume::ContainerStructure{ + {beamPipeContainer, pixelContainer}, + {Acts::BinningData(Acts::open, Acts::binR, {0., 17.5, 200.})}}; Acts::ProtoDetector detector; detector.name = "odd"; detector.worldVolume = detectorContainer; + auto logLevel = Acts::Logging::VERBOSE; + // Surface array creatorr auto surfaceArrayCreator = std::make_shared( Acts::SurfaceArrayCreator::Config(), - Acts::getDefaultLogger("SurfaceArrayCreator", Acts::Logging::INFO)); + Acts::getDefaultLogger("SurfaceArrayCreator", logLevel)); // Layer Creator Acts::LayerCreator::Config lcConfig; lcConfig.surfaceArrayCreator = surfaceArrayCreator; auto layerCreator = std::make_shared( - lcConfig, Acts::getDefaultLogger("LayerCreator", Acts::Logging::INFO)); + lcConfig, Acts::getDefaultLogger("LayerCreator", logLevel)); // Layer array creator Acts::LayerArrayCreator::Config lacConfig; auto layerArrayCreator = std::make_shared( - lacConfig, - Acts::getDefaultLogger("LayerArrayCreator", Acts::Logging::INFO)); + lacConfig, Acts::getDefaultLogger("LayerArrayCreator", logLevel)); // Tracking volume array creator Acts::TrackingVolumeArrayCreator::Config tvacConfig; auto tVolumeArrayCreator = std::make_shared( - tvacConfig, Acts::getDefaultLogger("TrackingVolumeArrayCreator", - Acts::Logging::INFO)); + tvacConfig, + Acts::getDefaultLogger("TrackingVolumeArrayCreator", logLevel)); // configure the cylinder volume helper Acts::CylinderVolumeHelper::Config cvhConfig; cvhConfig.layerArrayCreator = layerArrayCreator; cvhConfig.trackingVolumeArrayCreator = tVolumeArrayCreator; auto cylinderVolumeHelper = std::make_shared( - cvhConfig, - Acts::getDefaultLogger("CylinderVolumeHelper", Acts::Logging::INFO)); + cvhConfig, Acts::getDefaultLogger("CylinderVolumeHelper", logLevel)); // The KDT tracking geometry builder Acts::KDTreeTrackingGeometryBuilder::Config kdtgConfig; @@ -227,8 +235,8 @@ BOOST_AUTO_TEST_CASE(KDTreeTrackingGeometryBuilder_simple) { // Make the builder auto kdtTrackingGeometryBuilder = Acts::KDTreeTrackingGeometryBuilder( - kdtgConfig, Acts::getDefaultLogger("KDTreeTrackingGeometryBuilder", - Acts::Logging::INFO)); + kdtgConfig, + Acts::getDefaultLogger("KDTreeTrackingGeometryBuilder", logLevel)); auto trackingGeometry = kdtTrackingGeometryBuilder.trackingGeometry(tContext); BOOST_CHECK(trackingGeometry != nullptr); diff --git a/Tests/UnitTests/Core/Geometry/ProtoDetectorTests.cpp b/Tests/UnitTests/Core/Geometry/ProtoDetectorTests.cpp index 87dfa1c3482..7aa3fa5003c 100644 --- a/Tests/UnitTests/Core/Geometry/ProtoDetectorTests.cpp +++ b/Tests/UnitTests/Core/Geometry/ProtoDetectorTests.cpp @@ -53,28 +53,31 @@ Acts::ProtoDetector createProtoDetector() { Acts::ProtoVolume pixelBarrelL0; pixelBarrelL0.name = "pixel-barrel-l0"; pixelBarrelL0.extent.set(Acts::binR, 45., 50.); - pixelBarrelL0.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; + pixelBarrelL0.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Cylinder}; Acts::ProtoVolume pixelBarrelL1; pixelBarrelL1.name = "pixel-barrel-l1"; pixelBarrelL1.extent.set(Acts::binR, 70., 80.); - pixelBarrelL1.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; + pixelBarrelL1.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Cylinder}; - pixelBarrel.constituentVolumes = {pixelBarrelL0, pixelBarrelL1}; - pixelBarrel.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}; + pixelBarrel.container = Acts::ProtoVolume::ContainerStructure{ + {pixelBarrelL0, pixelBarrelL1}, + {Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}, + true}; Acts::ProtoVolume pixelPec; pixelPec.name = "pixel-pec"; pixelPec.extent.set(Acts::binZ, 600., 1900.); - pixelContainer.constituentVolumes = {pixelNec, pixelBarrel, pixelPec}; - pixelContainer.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; + pixelContainer.container = Acts::ProtoVolume::ContainerStructure{ + {pixelNec, pixelBarrel, pixelPec}, + {Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}}; - detectorVolume.constituentVolumes = {beamPipe, pixelContainer}; - detectorVolume.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binR, {0., 1})}; + detectorVolume.container = Acts::ProtoVolume::ContainerStructure{ + {beamPipe, pixelContainer}, + {Acts::BinningData(Acts::open, Acts::binR, {0., 1})}}; Acts::ProtoDetector detector; detector.name = "detector"; @@ -107,10 +110,16 @@ BOOST_AUTO_TEST_CASE(ProtoTrackingGeometryTests) { std::numeric_limits::epsilon()); // The detector cotainer should have binning in R - BOOST_CHECK(detectorVolume.constituentBinning[0].type == Acts::arbitrary); - BOOST_CHECK(detectorVolume.constituentBinning[0].binvalue == Acts::binR); + BOOST_CHECK(detectorVolume.container.has_value()); + BOOST_CHECK(not detectorVolume.internal.has_value()); - const auto& binBoundaries = detectorVolume.constituentBinning[0].boundaries(); + auto& cts = detectorVolume.container.value(); + + BOOST_CHECK(cts.constituentBinning.size() == 1u); + BOOST_CHECK(cts.constituentBinning[0].type == Acts::arbitrary); + BOOST_CHECK(cts.constituentBinning[0].binvalue == Acts::binR); + + const auto& binBoundaries = cts.constituentBinning[0].boundaries(); BOOST_CHECK(binBoundaries.size() == 3u); CHECK_CLOSE_ABS(binBoundaries[0u], 0., std::numeric_limits::epsilon()); @@ -121,7 +130,7 @@ BOOST_AUTO_TEST_CASE(ProtoTrackingGeometryTests) { // The first volume is the beam pipe, it should have gotten the // the z dimension - auto& beamPipe = detectorVolume.constituentVolumes[0u]; + auto& beamPipe = cts.constituentVolumes[0u]; BOOST_CHECK(beamPipe.name == "beam-pipe"); CHECK_CLOSE_ABS(beamPipe.extent.min(Acts::binZ), -2000., @@ -135,7 +144,7 @@ BOOST_AUTO_TEST_CASE(ProtoTrackingGeometryTests) { std::numeric_limits::epsilon()); // The second volume is the pixel detector - auto& pixelContainer = detectorVolume.constituentVolumes[1u]; + auto& pixelContainer = cts.constituentVolumes[1u]; BOOST_CHECK(pixelContainer.name == "pixel-container"); // Pixel contaienr should have fitting boundaries @@ -148,9 +157,13 @@ BOOST_AUTO_TEST_CASE(ProtoTrackingGeometryTests) { CHECK_CLOSE_ABS(pixelContainer.extent.max(Acts::binZ), 2000., std::numeric_limits::epsilon()); + // The Pixel container has constituents + BOOST_CHECK(pixelContainer.container.has_value()); + auto& cts1 = pixelContainer.container.value(); + // All of the internal containers should now have synchronized // inner & outer boundaries - for (auto& pv : pixelContainer.constituentVolumes) { + for (auto& pv : cts1.constituentVolumes) { CHECK_CLOSE_ABS(pv.extent.min(Acts::binR), 35., std::numeric_limits::epsilon()); @@ -159,11 +172,11 @@ BOOST_AUTO_TEST_CASE(ProtoTrackingGeometryTests) { } // The binning should have been estimated - BOOST_CHECK(pixelContainer.constituentBinning[0].type == Acts::arbitrary); - BOOST_CHECK(pixelContainer.constituentBinning[0].binvalue == Acts::binZ); + BOOST_CHECK(cts1.constituentBinning.size() == 1u); + BOOST_CHECK(cts1.constituentBinning[0].type == Acts::arbitrary); + BOOST_CHECK(cts1.constituentBinning[0].binvalue == Acts::binZ); - const auto& binBoundariesZ = - pixelContainer.constituentBinning[0].boundaries(); + const auto& binBoundariesZ = cts1.constituentBinning[0].boundaries(); BOOST_CHECK(binBoundariesZ.size() == 4u); CHECK_CLOSE_ABS(binBoundariesZ[0u], -2000., std::numeric_limits::epsilon()); @@ -173,13 +186,25 @@ BOOST_AUTO_TEST_CASE(ProtoTrackingGeometryTests) { std::numeric_limits::epsilon()); CHECK_CLOSE_ABS(binBoundariesZ[3u], 2000., std::numeric_limits::epsilon()); + + // The second volume is the pixel barrel + auto& pixelBarrel = cts1.constituentVolumes[1u]; + BOOST_CHECK(pixelBarrel.name == "pixel-barrel"); + + // It is a container volume value + BOOST_CHECK(pixelBarrel.container.has_value()); + auto& cts2 = pixelBarrel.container.value(); + // It is, however, a layer container + BOOST_CHECK(cts2.layerContainer); + for (auto& lVolume : cts2.constituentVolumes) { + BOOST_CHECK(lVolume.internal.has_value()); + } } BOOST_AUTO_TEST_CASE(ProtoDetectorTests) { // Get the raw proto detector description auto detector = createProtoDetector(); detector.harmonize(false); - std::cout << detector.toString() << std::endl; } From dbcd3b34b90c5efbe3a1102e3bec7e78352ec2a7 Mon Sep 17 00:00:00 2001 From: Andreas Salzburger Date: Fri, 6 Jan 2023 15:45:39 +0100 Subject: [PATCH 11/13] adding ProtoDetectorJsonConverter actual roundtrip testing --- .../Json/src/ProtoDetectorJsonConverter.cpp | 94 ++++-- Plugins/Json/src/UtilitiesJsonConverter.cpp | 2 +- .../Plugins/Json/EqualityHelpers.hpp | 109 +++++++ .../Json/ProtoDetectorJsonConverterTests.cpp | 274 ++++++++++++------ .../Json/UtilitiesJsonConverterTests.cpp | 56 +--- 5 files changed, 376 insertions(+), 159 deletions(-) create mode 100644 Tests/UnitTests/Plugins/Json/EqualityHelpers.hpp diff --git a/Plugins/Json/src/ProtoDetectorJsonConverter.cpp b/Plugins/Json/src/ProtoDetectorJsonConverter.cpp index 971783b4968..9a0613913b1 100644 --- a/Plugins/Json/src/ProtoDetectorJsonConverter.cpp +++ b/Plugins/Json/src/ProtoDetectorJsonConverter.cpp @@ -15,47 +15,97 @@ void Acts::to_json(nlohmann::json& j, const Acts::ProtoVolume& pv) { j["name"] = pv.name; j["extent"] = pv.extent; - if (pv.legacyLayerType != Surface::SurfaceType::Other) { - j["layerType"] = static_cast(pv.legacyLayerType); - } - // Helper m ethod to write binnings - auto writeBinning = [&](const std::vector& binning, + /// Helper m ethod to write binnings + /// + /// @param root the json root into which this is written + /// @param binning the vector of binning data + /// @param key the key for the root writing + auto writeBinning = [&](nlohmann::json& root, + const std::vector& binning, const std::string& key) -> void { nlohmann::json jbinning; for (const auto& bd : binning) { jbinning.push_back(bd); } - j[key] = jbinning; + root[key] = jbinning; }; - writeBinning(pv.surfaceBinning, "surfaceBinning"); - nlohmann::json constituents; - for (const auto& pvc : pv.constituentVolumes) { - constituents.push_back(pvc); + + // The internal structure + if (pv.internal.has_value()) { + auto& its = pv.internal.value(); + nlohmann::json jinternal; + if (its.layerType != Surface::SurfaceType::Other) { + jinternal["layerType"] = static_cast(its.layerType); + } + if (not its.surfaceBinning.empty()) { + writeBinning(jinternal, its.surfaceBinning, "surfaceBinning"); + } + j["internalStructure"] = jinternal; + } + + // The container structure + if (pv.container.has_value()) { + auto& cts = pv.container.value(); + nlohmann::json jcontainer; + nlohmann::json jconstituents; + for (const auto& pvc : cts.constituentVolumes) { + jconstituents.push_back(pvc); + } + jcontainer["constituents"] = jconstituents; + writeBinning(jcontainer, cts.constituentBinning, "constituentBinning"); + jcontainer["layerContainer"] = cts.layerContainer; + j["containerStructure"] = jcontainer; } - j["constituents"] = constituents; - writeBinning(pv.constituentBinning, "constituentBinning"); } void Acts::from_json(const nlohmann::json& j, Acts::ProtoVolume& pv) { pv.name = j["name"]; pv.extent = j["extent"]; - if (j.find("layerType") != j.end()) { - pv.legacyLayerType = static_cast(j["layerType"]); - } - // Helper method to read binnings - auto readBinning = [&](std::vector& binning, + /// Helper method to read binnings + /// + /// @param root is the json root + /// @param binning is the vector of binning data to be filled + /// @param key is the lookup key + auto readBinning = [&](const nlohmann::json& root, + std::vector& binning, const std::string& key) -> void { - for (const auto& jbinning : j[key]) { + // return if no surface binning in json + if (root.find(key) == root.end() or root[key].is_null()) { + return; + } + + for (const auto& jbinning : root[key]) { binning.push_back(jbinning); } }; - readBinning(pv.surfaceBinning, "surfaceBinning"); - for (const auto& jc : j["constituents"]) { - pv.constituentVolumes.push_back(jc); + + // The internal structure + if (j.find("internalStructure") != j.end() and + not j["internalStructure"].is_null()) { + auto& jinternal = j["internalStructure"]; + Surface::SurfaceType layerType = + static_cast(jinternal["layerType"]); + std::vector surfaceBinning; + readBinning(jinternal, surfaceBinning, "surfaceBinning"); + pv.internal = ProtoVolume::InternalStructure{layerType, surfaceBinning}; + } + + // The container structure + if (j.find("containerStructure") != j.end() and + not j["containerStructure"].is_null()) { + std::vector constituentVolumes; + auto& jcontainer = j["containerStructure"]; + for (const auto& jc : jcontainer["constituents"]) { + constituentVolumes.push_back(jc); + } + std::vector constituentBinning; + readBinning(jcontainer, constituentBinning, "constituentBinning"); + bool layerContainer = jcontainer["layerContainer"]; + pv.container = ProtoVolume::ContainerStructure{ + constituentVolumes, constituentBinning, layerContainer}; } - readBinning(pv.constituentBinning, "constituentBinning"); } void Acts::to_json(nlohmann::json& j, const Acts::ProtoDetector& pd) { diff --git a/Plugins/Json/src/UtilitiesJsonConverter.cpp b/Plugins/Json/src/UtilitiesJsonConverter.cpp index 509d027e682..e82f0326444 100644 --- a/Plugins/Json/src/UtilitiesJsonConverter.cpp +++ b/Plugins/Json/src/UtilitiesJsonConverter.cpp @@ -50,7 +50,7 @@ void Acts::from_json(const nlohmann::json& j, Acts::BinningData& bd) { Acts::binningValueNames().end(), valueName); Acts::BinningValue bValue = static_cast( valueIter - Acts::binningValueNames().begin()); - if (bins == 1) { + if (bins == 1 and not(j["type"] == "arbitrary")) { bd = Acts::BinningData(bValue, min, max); return; } diff --git a/Tests/UnitTests/Plugins/Json/EqualityHelpers.hpp b/Tests/UnitTests/Plugins/Json/EqualityHelpers.hpp new file mode 100644 index 00000000000..cdf2e300aae --- /dev/null +++ b/Tests/UnitTests/Plugins/Json/EqualityHelpers.hpp @@ -0,0 +1,109 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2022 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include "Acts/Geometry/Extent.hpp" +#include "Acts/Tests/CommonHelpers/FloatComparisons.hpp" +#include "Acts/Utilities/BinUtility.hpp" +#include "Acts/Utilities/BinningData.hpp" + +#include + +namespace Acts { + +/// Check whether the BinningData objects are equal +/// +/// @param ba The first BinningData object +/// @param bb The second BinningData object +/// @param tolerance a tolerance parameter +/// +/// @return a boolean +inline static bool isEqual(const BinningData& ba, const BinningData& bb, + float tolerance) { + bool equalBool = (ba.type == bb.type) and (ba.option == bb.option) and + (ba.binvalue == bb.binvalue) and (ba.zdim == bb.zdim) and + (ba.subBinningAdditive == bb.subBinningAdditive); + + BOOST_CHECK(equalBool); + bool equalRange = (std::abs(ba.min - bb.min) < tolerance) and + (std::abs(ba.max - bb.max) < tolerance) and + (std::abs(ba.step - bb.step) < tolerance); + + BOOST_CHECK(equalRange); + bool euqalStructure = + (ba.subBinningData != nullptr) + ? isEqual(*ba.subBinningData, *bb.subBinningData, tolerance) + : (bb.subBinningData == nullptr); + + BOOST_CHECK(euqalStructure); + + bool equalBoundaries = (ba.boundaries().size() == bb.boundaries().size()); + if (equalBoundaries) { + for (size_t ib = 0; ib < ba.boundaries().size(); ++ib) { + equalBoundaries = + (std::abs(ba.boundaries()[ib] - bb.boundaries()[ib]) < tolerance); + if (not equalBoundaries) { + break; + } + } + } + BOOST_CHECK(equalBoundaries); + + return equalBool and equalRange and euqalStructure; +} + +/// Check whether the BinUtility objects are equal +/// +/// @param ba The first BinUtility object +/// @param bb the second BinUtility object +/// @param tolerance a tolerance parameter +/// +/// @return a bollean if equal +inline static bool isEqual(const BinUtility& ba, const BinUtility& bb, + float tolerance) { + bool equal = (ba.binningData().size() == bb.binningData().size()); + BOOST_CHECK(equal); + if (equal) { + for (size_t ib = 0; ib < ba.binningData().size(); ++ib) { + equal = isEqual(ba.binningData()[ib], bb.binningData()[ib], tolerance); + BOOST_CHECK(equal); + } + } + return equal; +} + +/// check whether Extnet objects are equal - with tolerance +/// +/// @param ea the first extent object +/// @param eb the second extent object +/// @param tolerance the tolerance parameter +/// +/// @return bool for euqal +inline static bool isEqual(const Acts::Extent& ea, const Acts::Extent& eb, + Acts::ActsScalar tolerance = 0.) { + bool equalConstrains = true; + bool equalRange = true; + for (auto& bVal : s_binningValues) { + equalConstrains = + equalConstrains and (ea.constrains(bVal) == eb.constrains(bVal)); + BOOST_CHECK(equalConstrains); + if (ea.constrains(bVal) and eb.constrains(bVal)) { + equalRange = + equalRange and std::abs(ea.min(bVal) - eb.min(bVal)) < tolerance; + equalRange = + equalRange and std::abs(ea.max(bVal) - eb.max(bVal)) < tolerance; + BOOST_CHECK(equalRange); + } + } + BOOST_CHECK(equalConstrains); + BOOST_CHECK(equalRange); + return equalRange and equalConstrains; +} + +} // namespace Acts \ No newline at end of file diff --git a/Tests/UnitTests/Plugins/Json/ProtoDetectorJsonConverterTests.cpp b/Tests/UnitTests/Plugins/Json/ProtoDetectorJsonConverterTests.cpp index 00f21316c27..9d80ef4e54d 100644 --- a/Tests/UnitTests/Plugins/Json/ProtoDetectorJsonConverterTests.cpp +++ b/Tests/UnitTests/Plugins/Json/ProtoDetectorJsonConverterTests.cpp @@ -12,12 +12,96 @@ #include "Acts/Plugins/Json/ActsJson.hpp" #include "Acts/Plugins/Json/ProtoDetectorJsonConverter.hpp" #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp" +#include "Acts/Utilities/BinningData.hpp" +#include "Acts/Utilities/Enumerate.hpp" #include #include +#include "EqualityHelpers.hpp" + using namespace Acts; +namespace { + +/// @brief Helper method to compare proto volumes +/// @param one the first volume object +/// @param two the second volume object +/// @param tolerance the tolerance +/// @return a boolean to see if they are equal +bool isEqual(const Acts::ProtoVolume& one, const Acts::ProtoVolume& two, + const Acts::ActsScalar tolerance = 0.) { + bool nameEq = (one.name == two.name); + // Name + BOOST_CHECK(nameEq); + // Extent + bool extentEq = isEqual(one.extent, two.extent, tolerance); + BOOST_CHECK(extentEq); + + // Check internal structure + bool internalValueEq = (one.internal.has_value() == two.internal.has_value()); + BOOST_CHECK(internalValueEq); + bool internalEq = internalValueEq; + if (one.internal.has_value() and two.internal.has_value()) { + // Check consistency of the internal structure + const auto& itsOne = one.internal.value(); + const auto& itsTwo = two.internal.value(); + bool layerTypeEq = (itsOne.layerType == itsTwo.layerType); + BOOST_CHECK(layerTypeEq); + internalEq = layerTypeEq; + bool sBinningSizeEq = + (itsOne.surfaceBinning.size() == itsTwo.surfaceBinning.size()); + BOOST_CHECK(sBinningSizeEq); + internalEq = internalEq and sBinningSizeEq; + for (auto [isb, sb] : Acts::enumerate(itsOne.surfaceBinning)) { + bool sBinningEq = isEqual(sb, itsTwo.surfaceBinning[isb], tolerance); + BOOST_CHECK(sBinningEq); + internalEq = internalEq and sBinningEq; + } + } + BOOST_CHECK(internalEq); + + // Check container structure + bool containerValueEq = + (one.container.has_value() == two.container.has_value()); + BOOST_CHECK(containerValueEq); + bool containerEq = containerValueEq; + if (one.container.has_value() and two.container.has_value()) { + // Check consistency of the container structure + const auto& ctsOne = one.container.value(); + const auto& ctsTwo = two.container.value(); + bool layerContainerEq = (ctsOne.layerContainer == ctsTwo.layerContainer); + BOOST_CHECK(layerContainerEq); + containerEq = layerContainerEq; + bool cBinningSizeEq = + ctsOne.constituentBinning.size() == ctsTwo.constituentBinning.size(); + containerEq = containerEq and cBinningSizeEq; + BOOST_CHECK(cBinningSizeEq); + for (auto [icb, cb] : Acts::enumerate(ctsOne.constituentBinning)) { + bool cBinningEq = isEqual(cb, ctsTwo.constituentBinning[icb], tolerance); + BOOST_CHECK(cBinningEq); + containerEq = containerEq and cBinningEq; + } + // Recursively walk down + bool cSizeEq = + (ctsOne.constituentVolumes.size() == ctsTwo.constituentVolumes.size()); + BOOST_CHECK(cSizeEq); + containerEq = cSizeEq; + for (auto [ic, cOne] : Acts::enumerate(ctsOne.constituentVolumes)) { + const auto& cTwo = ctsTwo.constituentVolumes[ic]; + bool cEq = isEqual(cOne, cTwo, tolerance); + BOOST_CHECK(cEq); + containerEq = containerEq and cEq; + } + } + BOOST_CHECK(containerEq); + + // Give the overall judgement + return nameEq and extentEq and internalEq and containerEq; +} + +} // namespace + BOOST_AUTO_TEST_SUITE(ProtoDetectorJsonConverter) BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { @@ -36,10 +120,10 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { Acts::ProtoVolume beamPipe; beamPipe.name = "odd-beam-pipe-l"; beamPipe.extent.set(Acts::binR, 2., 24.); - beamPipe.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; - beamPipeContainer.constituentVolumes = {beamPipe}; - beamPipeContainer.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}; + beamPipe.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Cylinder}; + beamPipeContainer.container = Acts::ProtoVolume::ContainerStructure{ + {beamPipe}, {Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}, true}; // Pixel section Acts::ProtoVolume pixelContainer; @@ -71,20 +155,20 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { Acts::ProtoVolume pixNecD0; pixNecD0.name = "odd-pixel-nec-d0"; pixNecD0.extent.set(Acts::binZ, -640., -600); - pixelNec.constituentVolumes = {pixNecD6, pixNecD5, pixNecD4, pixNecD3, - pixNecD2, pixNecD1, pixNecD0}; + pixelNec.container = Acts::ProtoVolume::ContainerStructure{ + {pixNecD6, pixNecD5, pixNecD4, pixNecD3, pixNecD2, pixNecD1, pixNecD0}, + {Acts::BinningData(Acts::open, Acts::binZ, {0., 1.})}, + true}; Acts::BinningData pixEcBinningR = Acts::BinningData(Acts::open, Acts::binR, 2., 0., 1.); Acts::BinningData pixEcBinningPhi = Acts::BinningData(Acts::closed, Acts::binPhi, 30., -M_PI, M_PI); - pixelNec.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binZ, {0., 1.})}; - for (auto& cv : pixelNec.constituentVolumes) { - cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; - cv.surfaceBinning = {pixEcBinningR, pixEcBinningPhi}; + for (auto& cv : pixelNec.container.value().constituentVolumes) { cv.extent.setEnvelope(discLayerEnvelope); + cv.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Disc, {pixEcBinningR, pixEcBinningPhi}}; } Acts::ProtoVolume pixelBarrel; @@ -108,16 +192,17 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { pixBarrelL3.extent.set(Acts::binR, 160., 180.); pixBarrelL3.extent.set(Acts::binZ, -580., 580); - pixelBarrel.constituentVolumes = {pixBarrelL0, pixBarrelL1, pixBarrelL2, - pixBarrelL3}; - for (auto& cv : pixelBarrel.constituentVolumes) { - cv.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; + pixelBarrel.container = Acts::ProtoVolume::ContainerStructure{ + {pixBarrelL0, pixBarrelL1, pixBarrelL2, pixBarrelL3}, + {Acts::BinningData(Acts::open, Acts::binR, {0., 1})}, + true}; + + for (auto& cv : pixelBarrel.container.value().constituentVolumes) { cv.extent.setEnvelope(cylinderLayerEnvelope); + cv.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Cylinder}; } - pixelBarrel.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binR, {0., 1})}; - Acts::ProtoVolume pixelPec; pixelPec.name = "odd-pixel-pec"; pixelPec.extent.set(Acts::binZ, 580., 3100.); @@ -144,19 +229,21 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { pixPecD6.name = "odd-pixel-pec-d6"; pixPecD6.extent.set(Acts::binZ, 1500., 1540.); - pixelPec.constituentVolumes = {pixPecD0, pixPecD1, pixPecD2, pixPecD3, - pixPecD4, pixPecD5, pixPecD6}; - pixelPec.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; - for (auto& cv : pixelPec.constituentVolumes) { - cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; - cv.surfaceBinning = {pixEcBinningR, pixEcBinningPhi}; + pixelPec.container = Acts::ProtoVolume::ContainerStructure{ + {pixPecD0, pixPecD1, pixPecD2, pixPecD3, pixPecD4, pixPecD5, pixPecD6}, + {Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}, + true}; + + for (auto& cv : pixelPec.container.value().constituentVolumes) { cv.extent.setEnvelope(discLayerEnvelope); + cv.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Disc, {pixEcBinningR, pixEcBinningPhi}}; } - pixelContainer.constituentVolumes = {pixelNec, pixelBarrel, pixelPec}; - pixelContainer.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binZ, {-3100., -580., 580., 3100.})}; + pixelContainer.container = Acts::ProtoVolume::ContainerStructure{ + {pixelNec, pixelBarrel, pixelPec}, + {Acts::BinningData(Acts::open, Acts::binZ, + {-3100., -580., 580., 3100.})}}; // Short Strip section Acts::ProtoVolume pstContainer; @@ -165,10 +252,10 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { Acts::ProtoVolume pst; pst.name = "odd-pst-l"; pst.extent.set(Acts::binR, 201., 209.); - pst.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; - pstContainer.constituentVolumes = {pst}; - pstContainer.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}; + pst.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Cylinder}; + pstContainer.container = Acts::ProtoVolume::ContainerStructure{ + {pst}, {Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}, true}; // Short Strip section Acts::ProtoVolume sstripContainer; @@ -202,14 +289,17 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { sstripNecD0.name = "odd-sstrip-nec-d0"; sstripNecD0.extent.set(Acts::binZ, -1350., -1250.); - sstripNec.constituentVolumes = {sstripNecD5, sstripNecD4, sstripNecD3, - sstripNecD2, sstripNecD1, sstripNecD0}; - sstripNec.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; - for (auto& cv : sstripNec.constituentVolumes) { - cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; - cv.surfaceBinning = {sstripEcBinningR, sstripEcBinningPhi}; + sstripNec.container = Acts::ProtoVolume::ContainerStructure{ + {sstripNecD5, sstripNecD4, sstripNecD3, sstripNecD2, sstripNecD1, + sstripNecD0}, + {Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}, + true}; + + for (auto& cv : sstripNec.container.value().constituentVolumes) { cv.extent.setEnvelope(discLayerEnvelope); + cv.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Disc, + {sstripEcBinningR, sstripEcBinningPhi}}; } Acts::ProtoVolume sstripBarrel; @@ -229,16 +319,17 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { sstripBarrelL3.name = "odd-sstrip-barrel-l3"; sstripBarrelL3.extent.set(Acts::binR, 640., 680.); - sstripBarrel.constituentVolumes = {sstripBarrelL0, sstripBarrelL1, - sstripBarrelL2, sstripBarrelL3}; - for (auto& cv : sstripBarrel.constituentVolumes) { - cv.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; + sstripBarrel.container = Acts::ProtoVolume::ContainerStructure{ + {sstripBarrelL0, sstripBarrelL1, sstripBarrelL2, sstripBarrelL3}, + {Acts::BinningData(Acts::open, Acts::binR, {0., 1})}, + true}; + + for (auto& cv : sstripBarrel.container.value().constituentVolumes) { cv.extent.setEnvelope(cylinderLayerEnvelope); + cv.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Cylinder}; } - sstripBarrel.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binR, {0., 1})}; - Acts::ProtoVolume sstripPec; sstripPec.name = "odd-sstrip-pec"; sstripPec.extent.set(Acts::binZ, 1200., 3100); @@ -262,19 +353,22 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { sstripPecD5.name = "odd-sstrip-pec-d5"; sstripPecD5.extent.set(Acts::binZ, 2900., 3000.); - sstripPec.constituentVolumes = {sstripPecD0, sstripPecD1, sstripPecD2, - sstripPecD3, sstripPecD4, sstripPecD5}; - sstripPec.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; - for (auto& cv : sstripPec.constituentVolumes) { - cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; - cv.surfaceBinning = {sstripEcBinningR, sstripEcBinningPhi}; + sstripPec.container = Acts::ProtoVolume::ContainerStructure{ + {sstripPecD0, sstripPecD1, sstripPecD2, sstripPecD3, sstripPecD4, + sstripPecD5}, + {Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}, + true}; + for (auto& cv : sstripPec.container.value().constituentVolumes) { cv.extent.setEnvelope(discLayerEnvelope); + cv.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Disc, + {sstripEcBinningR, sstripEcBinningPhi}}; } - sstripContainer.constituentBinning = {Acts::BinningData( - Acts::open, Acts::binZ, {-3100., -1200., 1200., 3100.})}; - sstripContainer.constituentVolumes = {sstripNec, sstripBarrel, sstripPec}; + sstripContainer.container = Acts::ProtoVolume::ContainerStructure{ + {sstripNec, sstripBarrel, sstripPec}, + {Acts::BinningData(Acts::open, Acts::binZ, + {-3100., -1200., 1200., 3100.})}}; // Long Strip section Acts::ProtoVolume lstripContainer; @@ -303,13 +397,16 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { lstripNecD0.name = "odd-lstrip-nec-d0"; lstripNecD0.extent.set(Acts::binZ, -1400., -1250.); - lstripNec.constituentVolumes = {lstripNecD5, lstripNecD4, lstripNecD3, - lstripNecD2, lstripNecD1, lstripNecD0}; - lstripNec.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; - for (auto& cv : lstripNec.constituentVolumes) { - cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; + lstripNec.container = Acts::ProtoVolume::ContainerStructure{ + {lstripNecD5, lstripNecD4, lstripNecD3, lstripNecD2, lstripNecD1, + lstripNecD0}, + {Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}, + true}; + + for (auto& cv : lstripNec.container.value().constituentVolumes) { cv.extent.setEnvelope(discLayerEnvelope); + cv.internal = + Acts::ProtoVolume::InternalStructure{Acts::Surface::SurfaceType::Disc}; } Acts::ProtoVolume lstripBarrel; @@ -323,15 +420,17 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { lstripBarrelL1.name = "odd-lstrip-barrel-l1"; lstripBarrelL1.extent.set(Acts::binR, 1000., 1050.); - lstripBarrel.constituentVolumes = {lstripBarrelL0, lstripBarrelL1}; - for (auto& cv : lstripBarrel.constituentVolumes) { - cv.legacyLayerType = Acts::Surface::SurfaceType::Cylinder; + lstripBarrel.container = Acts::ProtoVolume::ContainerStructure{ + {lstripBarrelL0, lstripBarrelL1}, + {Acts::BinningData(Acts::open, Acts::binR, {0., 1})}, + true}; + + for (auto& cv : lstripBarrel.container.value().constituentVolumes) { cv.extent.setEnvelope(cylinderLayerEnvelope); + cv.internal = Acts::ProtoVolume::InternalStructure{ + Acts::Surface::SurfaceType::Cylinder}; } - lstripBarrel.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binR, {0., 1})}; - Acts::ProtoVolume lstripPec; lstripPec.name = "odd-lstrip-pec"; lstripPec.extent.set(Acts::binZ, 1200., 3100); @@ -355,28 +454,31 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { lstripPecD5.name = "odd-lstrip-pec-d5"; lstripPecD5.extent.set(Acts::binZ, 2900., 3050.); - lstripPec.constituentVolumes = {lstripPecD0, lstripPecD1, lstripPecD2, - lstripPecD3, lstripPecD4, lstripPecD5}; - lstripPec.constituentBinning = { - Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}; - for (auto& cv : lstripPec.constituentVolumes) { - cv.legacyLayerType = Acts::Surface::SurfaceType::Disc; + lstripPec.container = Acts::ProtoVolume::ContainerStructure{ + {lstripPecD0, lstripPecD1, lstripPecD2, lstripPecD3, lstripPecD4, + lstripPecD5}, + {Acts::BinningData(Acts::open, Acts::binZ, {0., 1})}, + true}; + for (auto& cv : lstripPec.container.value().constituentVolumes) { + cv.internal = + Acts::ProtoVolume::InternalStructure{Acts::Surface::SurfaceType::Disc}; cv.extent.setEnvelope(discLayerEnvelope); } - lstripContainer.constituentVolumes = {lstripNec, lstripBarrel, lstripPec}; - lstripContainer.constituentBinning = {Acts::BinningData( - Acts::open, Acts::binZ, {-3100., -1200., 1200., 3100.})}; + lstripContainer.container = Acts::ProtoVolume::ContainerStructure{ + {lstripNec, lstripBarrel, lstripPec}, + {Acts::BinningData(Acts::open, Acts::binZ, + {-3100., -1200., 1200., 3100.})}}; // The overall container Acts::ProtoVolume detectorContainer; detectorContainer.name = "odd-light-world"; detectorContainer.extent.set(Acts::binR, 0., 1100.); detectorContainer.extent.set(Acts::binZ, -3100., 3100.); - detectorContainer.constituentVolumes = {beamPipeContainer, pixelContainer, - pstContainer, sstripContainer, - lstripContainer}; - detectorContainer.constituentBinning = {Acts::BinningData( - Acts::open, Acts::binR, {0., 25., 200., 210., 720., 1100.})}; + detectorContainer.container = Acts::ProtoVolume::ContainerStructure{ + {beamPipeContainer, pixelContainer, pstContainer, sstripContainer, + lstripContainer}, + {Acts::BinningData(Acts::open, Acts::binR, + {0., 25., 200., 210., 720., 1100.})}}; // ---------------------------------------------------------- Acts::ProtoDetector detector; @@ -393,6 +495,14 @@ BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) { out.close(); Acts::ProtoDetector detectorIn = jdet["detector"]; + + // Let's compare + BOOST_CHECK(detector.name == detectorIn.name); + + const auto& world = detector.worldVolume; + const auto& worldIn = detectorIn.worldVolume; + + BOOST_CHECK(isEqual(world, worldIn, 0.1)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/Tests/UnitTests/Plugins/Json/UtilitiesJsonConverterTests.cpp b/Tests/UnitTests/Plugins/Json/UtilitiesJsonConverterTests.cpp index cdde0f55058..f1ceb82609a 100644 --- a/Tests/UnitTests/Plugins/Json/UtilitiesJsonConverterTests.cpp +++ b/Tests/UnitTests/Plugins/Json/UtilitiesJsonConverterTests.cpp @@ -18,64 +18,12 @@ #include #include +#include "EqualityHelpers.hpp" + using namespace Acts; BOOST_AUTO_TEST_SUITE(UtilitiesJsonConverter) -namespace { -/// Check whether the BinningData objects are equal -/// -/// @param ba The first BinningData object -/// @param bb The second BinningData object -/// @param tolerance a tolerance parameter -/// -/// @return a boolean -bool isEqual(const BinningData& ba, const BinningData& bb, float tolerance) { - bool equalBool = (ba.type == bb.type) and (ba.option == bb.option) and - (ba.binvalue == bb.binvalue) and (ba.zdim == bb.zdim) and - (ba.subBinningAdditive == bb.subBinningAdditive); - - bool equalRange = (std::abs(ba.min - bb.min) < tolerance) and - (std::abs(ba.max - bb.max) < tolerance) and - (std::abs(ba.step - bb.step) < tolerance); - - bool euqalStructure = - (ba.subBinningData != nullptr) - ? isEqual(*ba.subBinningData, *bb.subBinningData, tolerance) - : (bb.subBinningData == nullptr); - - bool equalBoundaries = (ba.boundaries().size() == bb.boundaries().size()); - if (equalBoundaries) { - for (size_t ib = 0; ib < ba.boundaries().size(); ++ib) { - equalBoundaries = - (std::abs(ba.boundaries()[ib] - bb.boundaries()[ib]) < tolerance); - if (not equalBoundaries) { - break; - } - } - } - return equalBool and equalRange and euqalStructure; -} - -/// Check whether the BinUtility ojbects are equal -/// -/// @param ba The first BinUtility object -/// @param bb the second BinUtility object -/// @param tolerance a tolerance parameter -/// -/// @return a bollean if equal -bool isEqual(const BinUtility& ba, const BinUtility& bb, float tolerance) { - bool equal = (ba.binningData().size() == bb.binningData().size()); - if (equal) { - for (size_t ib = 0; ib < ba.binningData().size(); ++ib) { - equal = isEqual(ba.binningData()[ib], bb.binningData()[ib], tolerance); - } - } - return equal; -} - -} // namespace - BOOST_AUTO_TEST_CASE(BinUtilityRoundTripTests) { BinUtility reference(2, 0., 4., open, binR); From eec0b5b30fbb2a91cab7a3f7c7dac2ea8c00d698 Mon Sep 17 00:00:00 2001 From: Andreas Salzburger Date: Mon, 9 Jan 2023 09:49:41 +0100 Subject: [PATCH 12/13] adressing PR2 specific comments --- Plugins/Json/src/ExtentJsonConverter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Json/src/ExtentJsonConverter.cpp b/Plugins/Json/src/ExtentJsonConverter.cpp index 1ae916e17ed..e6b4dac4f07 100644 --- a/Plugins/Json/src/ExtentJsonConverter.cpp +++ b/Plugins/Json/src/ExtentJsonConverter.cpp @@ -27,7 +27,7 @@ void Acts::from_json(const nlohmann::json& j, Acts::Extent& e) { const auto bValueNames = binningValueNames(); for (auto [ib, bvn] : enumerate(bValueNames)) { if (j.find(bvn) != j.end()) { - e.set(static_cast(ib), j[bvn]["min"], j[bvn]["max"]); + e.range(static_cast(ib)) = j[bvn]; } } -} \ No newline at end of file +} From 9c40df661d2fc5bd36d992b0c1d032f70b8e6346 Mon Sep 17 00:00:00 2001 From: Andreas Salzburger Date: Mon, 9 Jan 2023 10:21:22 +0100 Subject: [PATCH 13/13] undo PR change --- Plugins/Json/src/ExtentJsonConverter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Json/src/ExtentJsonConverter.cpp b/Plugins/Json/src/ExtentJsonConverter.cpp index e6b4dac4f07..00977c2e7ba 100644 --- a/Plugins/Json/src/ExtentJsonConverter.cpp +++ b/Plugins/Json/src/ExtentJsonConverter.cpp @@ -27,7 +27,7 @@ void Acts::from_json(const nlohmann::json& j, Acts::Extent& e) { const auto bValueNames = binningValueNames(); for (auto [ib, bvn] : enumerate(bValueNames)) { if (j.find(bvn) != j.end()) { - e.range(static_cast(ib)) = j[bvn]; + e.set(static_cast(ib), j[bvn]["min"], j[bvn]["max"]); } } }