Skip to content

Commit

Permalink
feat: Optionally decorate geometry dumps to json. (#1732)
Browse files Browse the repository at this point in the history
Added the possibility to pass a decorator to the json converter to add extra attributes to the json dump of certain objects. Decorator interfaces are defined for adding attributes to surface and volume or their material dumps.

One use case is to extend the json dumps of the ATLAS tracking geometry with the ATLAS detector element IDs.

The PR changes interfaces in Plugins/Json.
  • Loading branch information
goetzgaycken authored Jan 18, 2023
1 parent f44f1da commit 2442fa1
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 34 deletions.
5 changes: 3 additions & 2 deletions Examples/Io/Json/src/JsonDigitizationConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ void ActsExamples::writeDigiConfigToJson(
std::ofstream outfile(path, std::ofstream::out | std::ofstream::binary);
// rely on exception for error handling
outfile.exceptions(std::ofstream::failbit | std::ofstream::badbit);
outfile
<< DigiConfigConverter("digitization-configuration").toJson(cfg).dump(2);
outfile << DigiConfigConverter("digitization-configuration")
.toJson(cfg, nullptr)
.dump(2);
}
6 changes: 3 additions & 3 deletions Examples/Io/Json/src/JsonSurfacesWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ ProcessCode JsonSurfacesWriter::write(const AlgorithmContext& ctx) {
SurfaceContainer sContainer(cSurfaces);

if (not m_cfg.writeOnlyNames) {
auto j = SurfaceConverter("surfaces").toJson(sContainer);
auto j = SurfaceConverter("surfaces").toJson(sContainer, nullptr);
out << std::setprecision(m_cfg.outputPrecision) << j.dump(2);
out.close();
} else {
Expand All @@ -127,7 +127,7 @@ ProcessCode JsonSurfacesWriter::write(const AlgorithmContext& ctx) {
namedEntries.push_back({geometryId, geoTypeName.str()});
}
NamedContainer nContainer(namedEntries);
auto j = NamedConverter("surface_types").toJson(nContainer);
auto j = NamedConverter("surface_types").toJson(nContainer, nullptr);
out << j.dump(2);
out.close();
}
Expand All @@ -144,7 +144,7 @@ ProcessCode JsonSurfacesWriter::endRun() {
m_cfg.writeSensitive, m_cfg.writeBoundary);
SurfaceContainer sContainer(cSurfaces);

auto j = SurfaceConverter("surfaces").toJson(sContainer);
auto j = SurfaceConverter("surfaces").toJson(sContainer, nullptr);
out << std::setprecision(m_cfg.outputPrecision) << j.dump(2);
out.close();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file is part of the Acts project.
//
// Copyright (C) 2020-2021 CERN for the benefit of the Acts project
// Copyright (C) 2020-2023 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
Expand All @@ -13,7 +13,7 @@

#include <stdexcept>
#include <string>

#include <type_traits>
namespace Acts {

/// Convert a geometry hierarchy map to/from Json.
Expand All @@ -31,7 +31,8 @@ namespace Acts {
/// checked for consistency when decoding the Json object.
///
/// [1]: https://nlohmann.github.io/json/features/arbitrary_types/
template <typename value_t>
template <typename value_t,
class decorator_t = void /* e.g. ITrackingGeometryJsonDecorator */>
class GeometryHierarchyMapJsonConverter {
public:
using Value = value_t;
Expand All @@ -50,8 +51,11 @@ class GeometryHierarchyMapJsonConverter {
/// Encode the geometry hierarchy map into a Json object.
///
/// @param container Geometry hierarchy map that should be encoded
/// @param decorator nullptr or a decorator to add extra values to the json
/// output
/// @return Encoded Json object
nlohmann::json toJson(const Container& container) const;
nlohmann::json toJson(const Container& container,
const decorator_t* decorator) const;

/// Decode a Json object into a geometry hierarchy map.
///
Expand Down Expand Up @@ -105,9 +109,35 @@ class GeometryHierarchyMapJsonConverter {

// implementations

template <typename value_t>
nlohmann::json GeometryHierarchyMapJsonConverter<value_t>::toJson(
const Container& container) const {
// auxiliary struct to indicate a missing specialization of a template which
// requires specialisation
template <typename T, class decorator_t>
struct missing_specialization : std::false_type {};

// methods to adapt type decorations for the given decorator
template <class T, class decorator_t>
void decorateJson([[maybe_unused]] const decorator_t* decorator,
[[maybe_unused]] const T& src,
[[maybe_unused]] nlohmann::json& dest) {
// this needs to be specialised
static_assert(
missing_specialization<T, decorator_t>::value,
"Explicit specialization needed for each decorator_t and src T");
}
template <class T, class decorator_t>
void decorateJson([[maybe_unused]] const decorator_t* decorator,
[[maybe_unused]] const T* src,
[[maybe_unused]] nlohmann::json& dest) {
// this needs to be specialised
static_assert(
missing_specialization<T, decorator_t>::value,
"Explicit specialization needed for each decorator_t and src T");
}

template <typename value_t, class decorator_t>
nlohmann::json GeometryHierarchyMapJsonConverter<value_t, decorator_t>::toJson(
const Container& container,
[[maybe_unused]] const decorator_t* decorator) const {
// encode header
nlohmann::json encoded = nlohmann::json::object();
encoded[kHeaderKey] = nlohmann::json::object();
Expand All @@ -117,15 +147,19 @@ nlohmann::json GeometryHierarchyMapJsonConverter<value_t>::toJson(
nlohmann::json entries = nlohmann::json::array();
for (std::size_t i = 0; i < container.size(); ++i) {
auto entry = encodeIdentifier(container.idAt(i));
entry["value"] = nlohmann::json(container.valueAt(i));
auto value_json = nlohmann::json(container.valueAt(i));
if constexpr (not std::is_same<decorator_t, void>::value) {
decorateJson(decorator, container.valueAt(i), value_json);
}
entry["value"] = std::move(value_json);
entries.push_back(std::move(entry));
}
encoded[kEntriesKey] = std::move(entries);
return encoded;
}

template <typename value_t>
auto GeometryHierarchyMapJsonConverter<value_t>::fromJson(
template <typename value_t, class decorator_t>
auto GeometryHierarchyMapJsonConverter<value_t, decorator_t>::fromJson(
const nlohmann::json& encoded) const -> Container {
// verify json format header
auto header = encoded.find(kHeaderKey);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// This file is part of the Acts project.
//
// Copyright (C) 2017-2023 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/Plugins/Json/ActsJson.hpp"

namespace Acts {
class TrackingVolume;
class Surface;

/// helper class to add extra informtion to surface or volume json objects
class ITrackingGeometryJsonDecorator {
public:
virtual ~ITrackingGeometryJsonDecorator() = default;

/// Add extra elements to the json object already filled for the given
/// surface
///
/// @param surface the surface which was used to fill the json object
/// @param json the json object that is enhanced
virtual void decorate(const Acts::Surface &surface,
nlohmann::json &json) const = 0;

/// Add extra elements to the json object already filled for the given
/// volume
///
/// @param volume the volume which was used to fill the json object
/// @param json the json object that is enhanced
virtual void decorate(const Acts::TrackingVolume &volume,
nlohmann::json &json) const = 0;
};
} // namespace Acts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// This file is part of the Acts project.
//
// Copyright (C) 2017-2023 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/Plugins/Json/ActsJson.hpp"

namespace Acts {
class ISurfaceMaterial;
class IVolumeMaterial;

/// helper class to add extra informtion to surface or volume json objects
class IVolumeMaterialJsonDecorator {
public:
virtual ~IVolumeMaterialJsonDecorator() = default;

/// Add extra elements to the json object already filled for the given
/// surface material
///
/// @param material the surface material which was used to
/// fill the json object
/// @param json the json object that is enhanced
virtual void decorate(const Acts::ISurfaceMaterial &material,
nlohmann::json &json) const = 0;

/// Add extra elements to the json object already filled for the given
/// volume material
///
/// @param material the volume material which was used to
/// fill the json object
/// @param json the json object that is enhanced
virtual void decorate(const Acts::IVolumeMaterial &material,
nlohmann::json &json) const = 0;
};
} // namespace Acts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file is part of the Acts project.
//
// Copyright (C) 2017-2021 CERN for the benefit of the Acts project
// Copyright (C) 2017-2023 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
Expand All @@ -13,6 +13,8 @@
#include "Acts/Material/IVolumeMaterial.hpp"
#include "Acts/Plugins/Json/ActsJson.hpp"
#include "Acts/Plugins/Json/GeometryHierarchyMapJsonConverter.hpp"
#include "Acts/Plugins/Json/ITrackingGeometryJsonDecorator.hpp"
#include "Acts/Plugins/Json/IVolumeMaterialJsonDecorator.hpp"
#include "Acts/Utilities/Logger.hpp"
#include <Acts/Geometry/TrackingVolume.hpp>
#include <Acts/Surfaces/Surface.hpp>
Expand Down Expand Up @@ -81,13 +83,19 @@ class MaterialMapJsonConverter {
/// Convert a DetectorMaterialMaps to json
///
/// @param maps The material map collection
nlohmann::json materialMapsToJson(const DetectorMaterialMaps& maps);
/// @param decorator nullptr or a decorator to add extra attributes
nlohmann::json materialMapsToJson(
const DetectorMaterialMaps& maps,
const IVolumeMaterialJsonDecorator* decorator = nullptr);

/// Convert a tracking geometry to json.
/// Can be used to initialise the material mapping process.
///
/// @param tGeometry is the tracking geometry
nlohmann::json trackingGeometryToJson(const TrackingGeometry& tGeometry);
/// @param decorator nullptr or a decorator to add extra attributes
nlohmann::json trackingGeometryToJson(
const TrackingGeometry& tGeometry,
const ITrackingGeometryJsonDecorator* decorator = nullptr);

/// Go through a volume to find subvolume, layers and surfaces.
/// Store volumes and surfaces in two vector used to initialised the geometry
Expand All @@ -114,19 +122,23 @@ class MaterialMapJsonConverter {
/// Name of the volume hierarchy
std::string m_volumeName = "Material Volume Map";
/// Geometry hierarchy writer for volume material.
Acts::GeometryHierarchyMapJsonConverter<const IVolumeMaterial*>
Acts::GeometryHierarchyMapJsonConverter<const IVolumeMaterial*,
Acts::IVolumeMaterialJsonDecorator>
m_volumeMaterialConverter;
/// Geometry hierarchy writer for tracking volume.
Acts::GeometryHierarchyMapJsonConverter<Acts::TrackingVolumeAndMaterial>
Acts::GeometryHierarchyMapJsonConverter<Acts::TrackingVolumeAndMaterial,
Acts::ITrackingGeometryJsonDecorator>
m_volumeConverter;

/// Name of the surface hierarchy
std::string m_surfaceName = "Material Surface Map";
/// Geometry hierarchy writer for surface material.
Acts::GeometryHierarchyMapJsonConverter<const ISurfaceMaterial*>
Acts::GeometryHierarchyMapJsonConverter<const ISurfaceMaterial*,
Acts::IVolumeMaterialJsonDecorator>
m_surfaceMaterialConverter;
/// Geometry hierarchy writer for surface.
Acts::GeometryHierarchyMapJsonConverter<Acts::SurfaceAndMaterialWithContext>
Acts::GeometryHierarchyMapJsonConverter<Acts::SurfaceAndMaterialWithContext,
Acts::ITrackingGeometryJsonDecorator>
m_surfaceConverter;

/// Private access to the logging instance
Expand Down
56 changes: 49 additions & 7 deletions Plugins/Json/src/MaterialMapJsonConverter.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file is part of the Acts project.
//
// Copyright (C) 2017-2021 CERN for the benefit of the Acts project
// Copyright (C) 2017-2023 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
Expand Down Expand Up @@ -28,6 +28,44 @@
#include <algorithm>
#include <map>

namespace Acts {
// specialisations of decoration helper function
// to pick correct objects from the contaier object
template <>
inline void decorateJson<Acts::SurfaceAndMaterialWithContext>(
const ITrackingGeometryJsonDecorator* decorator,
const Acts::SurfaceAndMaterialWithContext& src, nlohmann::json& dest) {
if (decorator != nullptr && std::get<0>(src) != nullptr) {
decorator->decorate(*std::get<0>(src), dest);
}
}
template <>
inline void decorateJson<Acts::TrackingVolumeAndMaterial>(
const ITrackingGeometryJsonDecorator* decorator,
const Acts::TrackingVolumeAndMaterial& src, nlohmann::json& dest) {
if (decorator != nullptr && src.first != nullptr) {
decorator->decorate(*src.first, dest);
}
}

template <>
inline void decorateJson<Acts::IVolumeMaterial>(
const IVolumeMaterialJsonDecorator* decorator,
const Acts::IVolumeMaterial* src, nlohmann::json& dest) {
if (decorator != nullptr && src != nullptr) {
decorator->decorate(*src, dest);
}
}
template <>
inline void decorateJson<Acts::ISurfaceMaterial>(
const IVolumeMaterialJsonDecorator* decorator,
const Acts::ISurfaceMaterial* src, nlohmann::json& dest) {
if (decorator != nullptr && src != nullptr) {
decorator->decorate(*src, dest);
}
}
} // namespace Acts

namespace {

Acts::SurfaceAndMaterialWithContext defaultSurfaceMaterial(
Expand Down Expand Up @@ -188,7 +226,8 @@ Acts::MaterialMapJsonConverter::MaterialMapJsonConverter(
/// Convert method
///
nlohmann::json Acts::MaterialMapJsonConverter::materialMapsToJson(
const DetectorMaterialMaps& maps) {
const DetectorMaterialMaps& maps,
const IVolumeMaterialJsonDecorator* decorator) {
VolumeMaterialMap volumeMap = maps.second;
std::vector<std::pair<GeometryIdentifier, const IVolumeMaterial*>>
mapVolumeInit;
Expand All @@ -198,7 +237,7 @@ nlohmann::json Acts::MaterialMapJsonConverter::materialMapsToJson(
GeometryHierarchyMap<const IVolumeMaterial*> hierarchyVolumeMap(
mapVolumeInit);
nlohmann::json materialVolume =
m_volumeMaterialConverter.toJson(hierarchyVolumeMap);
m_volumeMaterialConverter.toJson(hierarchyVolumeMap, decorator);
SurfaceMaterialMap surfaceMap = maps.first;
std::vector<std::pair<GeometryIdentifier, const ISurfaceMaterial*>>
mapSurfaceInit;
Expand All @@ -208,7 +247,7 @@ nlohmann::json Acts::MaterialMapJsonConverter::materialMapsToJson(
GeometryHierarchyMap<const ISurfaceMaterial*> hierarchySurfaceMap(
mapSurfaceInit);
nlohmann::json materialSurface =
m_surfaceMaterialConverter.toJson(hierarchySurfaceMap);
m_surfaceMaterialConverter.toJson(hierarchySurfaceMap, decorator);
nlohmann::json materialMap;
materialMap["Volumes"] = materialVolume;
materialMap["Surfaces"] = materialSurface;
Expand Down Expand Up @@ -245,7 +284,8 @@ Acts::MaterialMapJsonConverter::jsonToMaterialMaps(
}

nlohmann::json Acts::MaterialMapJsonConverter::trackingGeometryToJson(
const Acts::TrackingGeometry& tGeometry) {
const Acts::TrackingGeometry& tGeometry,
const ITrackingGeometryJsonDecorator* decorator) {
std::vector<std::pair<GeometryIdentifier, Acts::TrackingVolumeAndMaterial>>
volumeHierarchy;
std::vector<
Expand All @@ -255,10 +295,12 @@ nlohmann::json Acts::MaterialMapJsonConverter::trackingGeometryToJson(
tGeometry.highestTrackingVolume());
GeometryHierarchyMap<Acts::TrackingVolumeAndMaterial> hierarchyVolumeMap(
volumeHierarchy);
nlohmann::json jsonVolumes = m_volumeConverter.toJson(hierarchyVolumeMap);
nlohmann::json jsonVolumes =
m_volumeConverter.toJson(hierarchyVolumeMap, decorator);
GeometryHierarchyMap<Acts::SurfaceAndMaterialWithContext> hierarchySurfaceMap(
surfaceHierarchy);
nlohmann::json jsonSurfaces = m_surfaceConverter.toJson(hierarchySurfaceMap);
nlohmann::json jsonSurfaces =
m_surfaceConverter.toJson(hierarchySurfaceMap, decorator);
nlohmann::json hierarchyMap;
hierarchyMap["Volumes"] = jsonVolumes;
hierarchyMap["Surfaces"] = jsonSurfaces;
Expand Down
Loading

0 comments on commit 2442fa1

Please sign in to comment.