Skip to content

Commit

Permalink
feat: Add JSON detector element (#3851)
Browse files Browse the repository at this point in the history
Add a json detector element, which is explicitly constructed from a `nlohmann::json` object in order to ensure consistency. Move json surface reading utilities from examples to Plugins.
  • Loading branch information
benjaminhuth authored Nov 27, 2024
1 parent 98acf90 commit 0c5aacc
Show file tree
Hide file tree
Showing 11 changed files with 250 additions and 17 deletions.
1 change: 0 additions & 1 deletion Examples/Io/Json/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ add_library(
src/JsonGeometryList.cpp
src/JsonMaterialWriter.cpp
src/JsonSurfacesWriter.cpp
src/JsonSurfacesReader.cpp
src/JsonDigitizationConfig.cpp
)
target_include_directories(
Expand Down
6 changes: 6 additions & 0 deletions Examples/Python/src/Detector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,12 @@ void addDetector(Context& ctx) {

patchKwargsConstructor(c);
}

{
py::class_<Acts::DetectorElementBase,
std::shared_ptr<Acts::DetectorElementBase>>(
mex, "DetectorElementBase");
}
}

} // namespace Acts::Python
28 changes: 18 additions & 10 deletions Examples/Python/src/Json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 "ActsExamples/Io/Json/JsonTrackParamsLookupReader.hpp"
#include "ActsExamples/Io/Json/JsonTrackParamsLookupWriter.hpp"
Expand Down Expand Up @@ -204,21 +204,29 @@ void addJson(Context& ctx) {
}

{
auto sjOptions = py::class_<ActsExamples::JsonSurfacesReader::Options>(
mex, "SurfaceJsonOptions")
.def(py::init<>());
auto sjOptions =
py::class_<Acts::JsonSurfacesReader::Options>(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_<Acts::JsonDetectorElement, Acts::DetectorElementBase,
std::shared_ptr<Acts::JsonDetectorElement>>(
m, "JsonDetectorElement")
.def("surface", [](Acts::JsonDetectorElement& self) {
return self.surface().getSharedPtr();
});

m.def("readDetectorElementsFromJson",
Acts::JsonSurfacesReader::readDetectorElements);
}

{
Expand Down
2 changes: 2 additions & 0 deletions Plugins/Json/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
38 changes: 38 additions & 0 deletions Plugins/Json/include/Acts/Plugins/Json/JsonDetectorElement.hpp
Original file line number Diff line number Diff line change
@@ -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 <nlohmann/json.hpp>

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<Surface> m_surface;
Transform3 m_transform{};
double m_thickness{};
};

} // namespace Acts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#pragma once

#include "Acts/Geometry/GeometryHierarchyMap.hpp"
#include "Acts/Plugins/Json/JsonDetectorElement.hpp"

#include <memory>
#include <string>
Expand All @@ -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 = "";
Expand All @@ -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
///
Expand All @@ -37,10 +41,22 @@ Acts::GeometryHierarchyMap<std::shared_ptr<Acts::Surface>> 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<std::shared_ptr<Acts::Surface>> 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<std::shared_ptr<Acts::JsonDetectorElement>> readDetectorElements(
const Options& options, double thickness);

} // namespace Acts::JsonSurfacesReader
41 changes: 41 additions & 0 deletions Plugins/Json/src/JsonDetectorElement.cpp
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -17,7 +17,7 @@
#include <fstream>
#include <iostream>

namespace ActsExamples {
namespace Acts {

Acts::GeometryHierarchyMap<std::shared_ptr<Acts::Surface>>
JsonSurfacesReader::readHierarchyMap(
Expand Down Expand Up @@ -73,4 +73,27 @@ std::vector<std::shared_ptr<Acts::Surface>> JsonSurfacesReader::readVector(
return surfaces;
}

} // namespace ActsExamples
std::vector<std::shared_ptr<Acts::JsonDetectorElement>>
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<std::shared_ptr<Acts::JsonDetectorElement>> elements;
for (const auto& jSurface : jSurfaces) {
elements.emplace_back(
std::make_shared<Acts::JsonDetectorElement>(jSurface, thickness));
}
return elements;
}

} // namespace Acts
1 change: 1 addition & 0 deletions Tests/UnitTests/Plugins/Json/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
98 changes: 98 additions & 0 deletions Tests/UnitTests/Plugins/Json/JsonSurfacesReaderTests.cpp
Original file line number Diff line number Diff line change
@@ -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 <boost/test/unit_test.hpp>
#include <boost/test/unit_test_suite.hpp>

#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 <filesystem>
#include <fstream>
#include <memory>

#include <Eigen/Geometry>
#include <nlohmann/json.hpp>

const std::vector<std::shared_ptr<Acts::Surface>> surfaces = []() {
std::vector<std::shared_ptr<Acts::Surface>> v;

for (int i = 0; i < 3; ++i) {
auto bounds = std::make_shared<Acts::RectangleBounds>(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<Acts::PlaneSurface>(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());
}
}
1 change: 1 addition & 0 deletions docs/_extensions/lazy_autodoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ def run() -> None:
"Acts::Logging::DefaultFilterPolicy",
"Acts::Logging::DefaultPrintPolicy",
"Acts::SourceLink",
"Acts::JsonDetectorElement",
}

role_instances["func"] = {
Expand Down

0 comments on commit 0c5aacc

Please sign in to comment.