diff --git a/Examples/Io/Json/CMakeLists.txt b/Examples/Io/Json/CMakeLists.txt index 255d862881f..5461f5dd98d 100644 --- a/Examples/Io/Json/CMakeLists.txt +++ b/Examples/Io/Json/CMakeLists.txt @@ -4,7 +4,6 @@ add_library( src/JsonGeometryList.cpp src/JsonMaterialWriter.cpp src/JsonSurfacesWriter.cpp - src/JsonSurfacesReader.cpp src/JsonDigitizationConfig.cpp ) target_include_directories( diff --git a/Examples/Python/src/Detector.cpp b/Examples/Python/src/Detector.cpp index 6b9ef68f927..7c1cfde18cb 100644 --- a/Examples/Python/src/Detector.cpp +++ b/Examples/Python/src/Detector.cpp @@ -222,6 +222,12 @@ void addDetector(Context& ctx) { patchKwargsConstructor(c); } + + { + py::class_>( + mex, "DetectorElementBase"); + } } } // namespace Acts::Python diff --git a/Examples/Python/src/Json.cpp b/Examples/Python/src/Json.cpp index be367612ac2..5b980fd8fe2 100644 --- a/Examples/Python/src/Json.cpp +++ b/Examples/Python/src/Json.cpp @@ -11,13 +11,13 @@ #include "Acts/Detector/ProtoDetector.hpp" #include "Acts/Plugins/Json/DetectorJsonConverter.hpp" #include "Acts/Plugins/Json/JsonMaterialDecorator.hpp" +#include "Acts/Plugins/Json/JsonSurfacesReader.hpp" #include "Acts/Plugins/Json/MaterialMapJsonConverter.hpp" #include "Acts/Plugins/Json/ProtoDetectorJsonConverter.hpp" #include "Acts/Plugins/Python/Utilities.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/Framework/ProcessCode.hpp" #include "ActsExamples/Io/Json/JsonMaterialWriter.hpp" -#include "ActsExamples/Io/Json/JsonSurfacesReader.hpp" #include "ActsExamples/Io/Json/JsonSurfacesWriter.hpp" #include @@ -153,21 +153,29 @@ void addJson(Context& ctx) { } { - auto sjOptions = py::class_( - mex, "SurfaceJsonOptions") - .def(py::init<>()); + auto sjOptions = + py::class_(m, "SurfaceJsonOptions") + .def(py::init<>()); - ACTS_PYTHON_STRUCT_BEGIN(sjOptions, - ActsExamples::JsonSurfacesReader::Options); + ACTS_PYTHON_STRUCT_BEGIN(sjOptions, Acts::JsonSurfacesReader::Options); ACTS_PYTHON_MEMBER(inputFile); ACTS_PYTHON_MEMBER(jsonEntryPath); ACTS_PYTHON_STRUCT_END(); - mex.def("readSurfaceHierarchyMapFromJson", - ActsExamples::JsonSurfacesReader::readHierarchyMap); + m.def("readSurfaceHierarchyMapFromJson", + Acts::JsonSurfacesReader::readHierarchyMap); - mex.def("readSurfaceVectorFromJson", - ActsExamples::JsonSurfacesReader::readVector); + m.def("readSurfaceVectorFromJson", Acts::JsonSurfacesReader::readVector); + + py::class_>( + m, "JsonDetectorElement") + .def("surface", [](Acts::JsonDetectorElement& self) { + return self.surface().getSharedPtr(); + }); + + m.def("readDetectorElementsFromJson", + Acts::JsonSurfacesReader::readDetectorElements); } { diff --git a/Plugins/Json/CMakeLists.txt b/Plugins/Json/CMakeLists.txt index 0d3ff9875ee..20634d2bfe5 100644 --- a/Plugins/Json/CMakeLists.txt +++ b/Plugins/Json/CMakeLists.txt @@ -22,6 +22,8 @@ add_library( src/VolumeJsonConverter.cpp src/AmbiguityConfigJsonConverter.cpp src/DetrayJsonHelper.cpp + src/JsonDetectorElement.cpp + src/JsonSurfacesReader.cpp ) target_include_directories( ActsPluginJson diff --git a/Plugins/Json/include/Acts/Plugins/Json/JsonDetectorElement.hpp b/Plugins/Json/include/Acts/Plugins/Json/JsonDetectorElement.hpp new file mode 100644 index 00000000000..34c5a5b173a --- /dev/null +++ b/Plugins/Json/include/Acts/Plugins/Json/JsonDetectorElement.hpp @@ -0,0 +1,38 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/. +#pragma once + +#include "Acts/Geometry/DetectorElementBase.hpp" + +#include + +namespace Acts { + +/// A implementation of a detector element, that is constructed from a +/// JSON description of a surface. The idea behind this is that it helps +/// importing whole tracking geometries from JSON files. In some parts of +/// the codebase, the existence of a detector element associated to a surface +/// has a specific meaning (e.g., flags surfaces as sensitive). +class JsonDetectorElement : public DetectorElementBase { + public: + JsonDetectorElement(const nlohmann::json &jSurface, double thickness); + + Surface &surface() override; + const Surface &surface() const override; + + double thickness() const override; + + const Transform3 &transform(const GeometryContext &gctx) const override; + + private: + std::shared_ptr m_surface; + Transform3 m_transform{}; + double m_thickness{}; +}; + +} // namespace Acts diff --git a/Examples/Io/Json/include/ActsExamples/Io/Json/JsonSurfacesReader.hpp b/Plugins/Json/include/Acts/Plugins/Json/JsonSurfacesReader.hpp similarity index 58% rename from Examples/Io/Json/include/ActsExamples/Io/Json/JsonSurfacesReader.hpp rename to Plugins/Json/include/Acts/Plugins/Json/JsonSurfacesReader.hpp index 50bbf15d35f..17822c24401 100644 --- a/Examples/Io/Json/include/ActsExamples/Io/Json/JsonSurfacesReader.hpp +++ b/Plugins/Json/include/Acts/Plugins/Json/JsonSurfacesReader.hpp @@ -9,6 +9,7 @@ #pragma once #include "Acts/Geometry/GeometryHierarchyMap.hpp" +#include "Acts/Plugins/Json/JsonDetectorElement.hpp" #include #include @@ -18,9 +19,11 @@ namespace Acts { class Surface; } -namespace ActsExamples::JsonSurfacesReader { +namespace Acts::JsonSurfacesReader { /// @brief Options specification for surface reading +/// The file should contain an array of json surfaces +/// as produced by the SurfaceJsonConverter tools struct Options { /// @brief Which input file to read from std::string inputFile = ""; @@ -29,6 +32,7 @@ struct Options { }; /// @brief Read the surfaces from the input file +/// For details on the file format see the options struct /// /// @param options specifies which file and what to read /// @@ -37,10 +41,22 @@ Acts::GeometryHierarchyMap> readHierarchyMap( const Options& options); /// @brief Read the flat surfaces from the input file +/// For details on the file format see the options struct /// -/// @param inputFile is the input file to read from +/// @param options options for surface reading /// /// @return a vector of surfaces std::vector> readVector(const Options& options); -} // namespace ActsExamples::JsonSurfacesReader +/// @brief Read the surfaces from the input file and create +/// detector elements +/// For details on the file format see the options struct +/// +/// @param options options for surface reading +/// @param thickness the thickness used to construct the detector element +/// +/// @return a vector of surfaces +std::vector> readDetectorElements( + const Options& options, double thickness); + +} // namespace Acts::JsonSurfacesReader diff --git a/Plugins/Json/src/JsonDetectorElement.cpp b/Plugins/Json/src/JsonDetectorElement.cpp new file mode 100644 index 00000000000..5c1b4568ca5 --- /dev/null +++ b/Plugins/Json/src/JsonDetectorElement.cpp @@ -0,0 +1,41 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/. + +#include "Acts/Plugins/Json/JsonDetectorElement.hpp" + +#include "Acts/Plugins/Json/AlgebraJsonConverter.hpp" +#include "Acts/Plugins/Json/SurfaceJsonConverter.hpp" + +namespace Acts { + +JsonDetectorElement::JsonDetectorElement(const nlohmann::json &jSurface, + double thickness) + : m_thickness(thickness) { + m_surface = Acts::SurfaceJsonConverter::fromJson(jSurface); + m_transform = Transform3JsonConverter::fromJson(jSurface["transform"]); + m_surface->assignDetectorElement(*this); +} + +const Surface &JsonDetectorElement::surface() const { + return *m_surface; +} + +Surface &JsonDetectorElement::surface() { + return *m_surface; +} + +const Transform3 &JsonDetectorElement::transform( + const GeometryContext & /*gctx*/) const { + return m_transform; +} + +double JsonDetectorElement::thickness() const { + return m_thickness; +} + +} // namespace Acts diff --git a/Examples/Io/Json/src/JsonSurfacesReader.cpp b/Plugins/Json/src/JsonSurfacesReader.cpp similarity index 75% rename from Examples/Io/Json/src/JsonSurfacesReader.cpp rename to Plugins/Json/src/JsonSurfacesReader.cpp index 469c9828d46..fcee0ee7b86 100644 --- a/Examples/Io/Json/src/JsonSurfacesReader.cpp +++ b/Plugins/Json/src/JsonSurfacesReader.cpp @@ -6,7 +6,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -#include "ActsExamples/Io/Json/JsonSurfacesReader.hpp" +#include "Acts/Plugins/Json/JsonSurfacesReader.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" #include "Acts/Plugins/Json/ActsJson.hpp" @@ -17,7 +17,7 @@ #include #include -namespace ActsExamples { +namespace Acts { Acts::GeometryHierarchyMap> JsonSurfacesReader::readHierarchyMap( @@ -73,4 +73,27 @@ std::vector> JsonSurfacesReader::readVector( return surfaces; } -} // namespace ActsExamples +std::vector> +JsonSurfacesReader::readDetectorElements(const Options& options, + double thickness = 0.0) { + nlohmann::json j; + { + std::ifstream in(options.inputFile); + in >> j; + } + + // Walk down the path to the surface entries + nlohmann::json jSurfaces = j; + for (const auto& jep : options.jsonEntryPath) { + jSurfaces = jSurfaces[jep]; + } + + std::vector> elements; + for (const auto& jSurface : jSurfaces) { + elements.emplace_back( + std::make_shared(jSurface, thickness)); + } + return elements; +} + +} // namespace Acts diff --git a/Tests/UnitTests/Plugins/Json/CMakeLists.txt b/Tests/UnitTests/Plugins/Json/CMakeLists.txt index 141f86fb3fe..82ad95611ed 100644 --- a/Tests/UnitTests/Plugins/Json/CMakeLists.txt +++ b/Tests/UnitTests/Plugins/Json/CMakeLists.txt @@ -16,3 +16,4 @@ add_unittest(SurfaceBoundsJsonConverter SurfaceBoundsJsonConverterTests.cpp) add_unittest(SurfaceJsonConverter SurfaceJsonConverterTests.cpp) add_unittest(VolumeBoundsJsonConverter VolumeBoundsJsonConverterTests.cpp) add_unittest(TrackParametersJsonConverter TrackParametersJsonConverterTests.cpp) +add_unittest(JsonSurfacesReader JsonSurfacesReaderTests.cpp) diff --git a/Tests/UnitTests/Plugins/Json/JsonSurfacesReaderTests.cpp b/Tests/UnitTests/Plugins/Json/JsonSurfacesReaderTests.cpp new file mode 100644 index 00000000000..e70bad6c7bf --- /dev/null +++ b/Tests/UnitTests/Plugins/Json/JsonSurfacesReaderTests.cpp @@ -0,0 +1,98 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/. + +#include +#include + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Plugins/Json/JsonSurfacesReader.hpp" +#include "Acts/Plugins/Json/SurfaceJsonConverter.hpp" +#include "Acts/Surfaces/PlaneSurface.hpp" +#include "Acts/Surfaces/RectangleBounds.hpp" +#include "Acts/Utilities/Zip.hpp" + +#include +#include +#include + +#include +#include + +const std::vector> surfaces = []() { + std::vector> v; + + for (int i = 0; i < 3; ++i) { + auto bounds = std::make_shared(1.0, 1.0); + Acts::Transform3 transform = Acts::Transform3::Identity(); + transform.translate(Acts::Vector3::Random()); + Acts::Vector3 randomAngles = Acts::Vector3::Random(); + Acts::SquareMatrix3 rotMatrix; + rotMatrix = Eigen::AngleAxis(randomAngles[0], Acts::Vector3::UnitX()) * + Eigen::AngleAxis(randomAngles[1], Acts::Vector3::UnitY()) * + Eigen::AngleAxis(randomAngles[2], Acts::Vector3::UnitZ()); + transform.rotate(rotMatrix); + v.push_back( + Acts::Surface::makeShared(transform, bounds)); + } + + return v; +}(); + +const std::string filename = "json_surfaces_reader_tests.json"; + +struct FileFixture { + FileFixture() { + nlohmann::json js = nlohmann::json::array(); + + for (const auto &s : surfaces) { + js.push_back(Acts::SurfaceJsonConverter::toJson({}, *s)); + } + + nlohmann::json j; + j["foo"] = js; + + std::ofstream f(filename); + f << j.dump(2); + } + + ~FileFixture() { std::filesystem::remove(filename); } +}; + +FileFixture fileFixture; + +BOOST_AUTO_TEST_CASE(surface_reading_test) { + auto readBackSurfaces = + Acts::JsonSurfacesReader::readVector({filename, {"foo"}}); + + BOOST_REQUIRE_EQUAL(surfaces.size(), readBackSurfaces.size()); + for (auto [refSurface, surface] : Acts::zip(surfaces, readBackSurfaces)) { + BOOST_CHECK( + refSurface->transform({}).isApprox(surface->transform({}), 1.e-4)); + BOOST_CHECK(refSurface->center({}).isApprox(surface->center({}), 1.e-4)); + BOOST_CHECK_EQUAL(refSurface->type(), surface->type()); + BOOST_CHECK_EQUAL(refSurface->bounds().type(), surface->bounds().type()); + } +} + +BOOST_AUTO_TEST_CASE(json_detelement_reading_test) { + auto readBackDetElements = + Acts::JsonSurfacesReader::readDetectorElements({filename, {"foo"}}, 1.0); + + BOOST_REQUIRE_EQUAL(surfaces.size(), readBackDetElements.size()); + for (auto [refSurface, detElement] : + Acts::zip(surfaces, readBackDetElements)) { + auto surface = &detElement->surface(); + BOOST_CHECK( + refSurface->transform({}).isApprox(surface->transform({}), 1.e-4)); + BOOST_CHECK(refSurface->center({}).isApprox(surface->center({}), 1.e-4)); + BOOST_CHECK_EQUAL(refSurface->type(), surface->type()); + BOOST_CHECK_EQUAL(refSurface->bounds().type(), surface->bounds().type()); + } +}