File indexing completed on 2026-10-29 08:23:13
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsPlugins/Json/MaterialMapJsonConverter.hpp"
0010 #include "ActsPlugins/Json/TrackingGeometryMaterialJsonConverter.hpp"
0011 #include "ActsPlugins/Json/detail/JsonIo.hpp"
0012
0013 #ifdef ACTS_MATERIAL_MIGRATE_ROOT
0014 #include "ActsPlugins/Root/RootMaterialDecorator.hpp"
0015 #endif
0016
0017 #include <charconv>
0018 #include <filesystem>
0019 #include <iostream>
0020 #include <stdexcept>
0021 #include <string>
0022 #include <string_view>
0023
0024 namespace {
0025 constexpr std::string_view usage =
0026 "Usage: ActsMaterialMapMigrate INPUT OUTPUT [OPTIONS]\n"
0027 "Migrate legacy surface material maps to the version 1 format.\n"
0028 "ROOT input (.root) requires ACTS_BUILD_PLUGIN_ROOT=ON.\n"
0029 "Input: JSON or CBOR, optionally zstd compressed (detected from content).\n"
0030 "Output: .json, .cbor, .json.zst or .cbor.zst.\n"
0031 "Volume material is not supported by version 1.\n\n"
0032 "Options:\n"
0033 " --material-fraction-bits N Retained fraction bits, 0-23 (default 23)\n"
0034 " --compression-level N zstd level (default 9)\n"
0035 " --indentation N JSON indentation (default 4)\n"
0036 " --help Show this help\n";
0037
0038 template <typename T>
0039 T number(std::string_view text) {
0040 T result{};
0041 const auto [end, error] =
0042 std::from_chars(text.data(), text.data() + text.size(), result);
0043 if (error != std::errc{} || end != text.data() + text.size()) {
0044 throw std::invalid_argument("Invalid numeric option: " + std::string(text));
0045 }
0046 return result;
0047 }
0048
0049 Acts::TrackingGeometryMaterial readMaterial(
0050 const std::filesystem::path& input) {
0051 if (input.extension() == ".root") {
0052 #ifdef ACTS_MATERIAL_MIGRATE_ROOT
0053 ActsPlugins::RootMaterialDecorator::Config config;
0054 config.fileName = input.string();
0055 auto material =
0056 ActsPlugins::RootMaterialDecorator(config, Acts::Logging::WARNING)
0057 .materialMaps();
0058 if (material.surfaceMaterials.empty() && material.volumeMaterials.empty()) {
0059 throw std::invalid_argument("No material maps found in ROOT input");
0060 }
0061 return material;
0062 #else
0063 throw std::invalid_argument(
0064 "ROOT input is unavailable in this build; rebuild with "
0065 "ACTS_BUILD_PLUGIN_ROOT=ON");
0066 #endif
0067 }
0068 const auto document = Acts::detail::readJsonFile(input);
0069
0070 if (!document.contains("Surfaces") || !document.contains("Volumes")) {
0071 throw std::invalid_argument(
0072 "Expected a legacy material map with Surfaces and Volumes");
0073 }
0074 Acts::MaterialMapJsonConverter legacy({}, Acts::Logging::WARNING);
0075 return legacy.jsonToMaterialMaps(document);
0076 }
0077
0078 }
0079
0080 int main(int argc, char* argv[]) {
0081 for (int i = 1; i < argc; ++i) {
0082 if (std::string_view(argv[i]) == "--help") {
0083 std::cout << usage;
0084 return 0;
0085 }
0086 }
0087 if (argc < 3) {
0088 std::cerr << usage;
0089 return 1;
0090 }
0091 try {
0092 Acts::TrackingGeometryMaterialJsonConverter::Options options;
0093 for (int i = 3; i < argc; i += 2) {
0094 const std::string_view option = argv[i];
0095 if (i + 1 == argc) {
0096 throw std::invalid_argument("Missing value for " + std::string(option));
0097 }
0098 if (option == "--material-fraction-bits") {
0099 options.materialFractionBits = number<unsigned int>(argv[i + 1]);
0100 } else if (option == "--compression-level") {
0101 options.compressionLevel = number<int>(argv[i + 1]);
0102 } else if (option == "--indentation") {
0103 options.indentation = number<unsigned int>(argv[i + 1]);
0104 } else {
0105 throw std::invalid_argument("Unknown option: " + std::string(option));
0106 }
0107 }
0108 const std::filesystem::path input = argv[1];
0109 const std::filesystem::path output = argv[2];
0110 if (std::filesystem::exists(output) &&
0111 std::filesystem::equivalent(input, output)) {
0112 throw std::invalid_argument("Input and output must be different files");
0113 }
0114 const auto material = readMaterial(input);
0115 Acts::TrackingGeometryMaterialJsonConverter().toFile(material, output,
0116 options);
0117 std::cout << "Migrated "
0118 << material.surfaceMaterials.size() +
0119 material.keyedSurfaces.size()
0120 << " surface assignments to " << output << '\n';
0121 return 0;
0122 } catch (const std::exception& error) {
0123 std::cerr << "Material migration failed: " << error.what() << '\n';
0124 return 1;
0125 }
0126 }