Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-27 07:24:17

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 // Project include(s)
0010 #include "detray/definitions/algebra.hpp"
0011 #include "detray/utils/consistency_checker.hpp"
0012 #include "detray/utils/logging.hpp"
0013 
0014 // Detray IO include(s)
0015 #include "detray/io/backend/geometry_reader.hpp"
0016 #include "detray/io/backend/geometry_writer.hpp"
0017 #include "detray/io/frontend/detector_reader.hpp"
0018 #include "detray/io/frontend/detector_writer.hpp"
0019 #include "detray/io/json/json_converter.hpp"
0020 
0021 // Detray test include(s)
0022 #include "detray/test/common/build_telescope_detector.hpp"
0023 #include "detray/test/common/build_toy_detector.hpp"
0024 #include "detray/test/common/build_wire_chamber.hpp"
0025 #include "detray/test/cpu/toy_detector_test.hpp"
0026 
0027 // Vecmem include(s)
0028 #include <vecmem/memory/host_memory_resource.hpp>
0029 
0030 // GTest include(s)
0031 #include <gtest/gtest.h>
0032 
0033 // System include(s)
0034 #include <filesystem>
0035 #include <ios>
0036 
0037 using namespace detray;
0038 
0039 namespace {
0040 
0041 /// Compare two files with names @param file_name1 and @param file_name2 for
0042 /// equality, while skipping the first @param skip lines (header part)
0043 bool compare_files(const std::string& file_name1, const std::string& file_name2,
0044                    std::size_t skip = 15u) {
0045   auto file1 =
0046       io::file_handle(file_name1, std::ios_base::in | std::ios_base::binary);
0047   auto file2 =
0048       io::file_handle(file_name2, std::ios_base::in | std::ios_base::binary);
0049 
0050   std::string line1;
0051   std::string line2;
0052 
0053   // Check files line by line
0054   std::size_t i{1u};
0055   while (std::getline(*file1, line1)) {
0056     if (std::getline(*file2, line2)) {
0057       if (skip < i && line1 != line2) {
0058         DETRAY_ERROR_HOST("In line " << i << ":" << std::endl
0059                                      << line1 << std::endl
0060                                      << line2);
0061         return false;
0062       }
0063     } else {
0064       DETRAY_ERROR_HOST("Could not read next line from file 2:"
0065                         << std::endl
0066                         << "In line " << i << ":" << std::endl
0067                         << line1);
0068       return false;
0069     }
0070     ++i;
0071   }
0072 
0073   // Are there more lines in file2 than file1?
0074   if (std::getline(*file2, line2)) {
0075     DETRAY_ERROR_HOST("Could not read next line from file 1:"
0076                       << std::endl
0077                       << "In line " << i << ":" << std::endl
0078                       << line2);
0079     return false;
0080   }
0081 
0082   // Passed
0083   return true;
0084 }
0085 
0086 /// Full IO round trip for a given detector
0087 /// @returns a detector read back in from the writer files
0088 template <std::size_t CAP = 0u, typename detector_t>
0089 auto test_detector_json_io(
0090     const detector_t& det, const typename detector_t::name_map& names,
0091     std::map<std::string, std::string, std::less<>>& file_names,
0092     vecmem::host_memory_resource& host_mr) {
0093   auto writer_cfg = io::detector_writer_config{}
0094                         .format(io::format::json)
0095                         .replace_files(true)
0096                         .write_grids(true)
0097                         .write_material(true);
0098   io::write_detector(det, names, writer_cfg);
0099 
0100   // Read the detector back in
0101   io::detector_reader_config reader_cfg{};
0102   reader_cfg.verbose_check(true);
0103   for (auto& [_, name] : file_names) {
0104     reader_cfg.add_file(name);
0105   }
0106 
0107   auto [det2, names2] = io::read_detector<detector_t, CAP>(host_mr, reader_cfg);
0108 
0109   // Write the result to a different set of files
0110   writer_cfg.replace_files(false);
0111   io::write_detector(det2, names2, writer_cfg);
0112 
0113   // Compare writing round-trip
0114   std::string geometry_file{names.get_detector_name() + "_geometry_2.json"};
0115   EXPECT_TRUE(compare_files(file_names["geometry"], geometry_file));
0116   std::filesystem::remove(geometry_file);
0117   std::filesystem::remove(file_names["geometry"]);
0118 
0119   // Check a homogeneous material description, if present
0120   if (auto search = file_names.find("homogeneous_material");
0121       search != file_names.end()) {
0122     std::string hom_mat_file{names.get_detector_name() +
0123                              "_homogeneous_material_2.json"};
0124     EXPECT_TRUE(
0125         compare_files(file_names["homogeneous_material"], hom_mat_file));
0126     std::filesystem::remove(hom_mat_file);
0127     std::filesystem::remove(file_names["homogeneous_material"]);
0128   }
0129 
0130   // Check a material map description, if present
0131   if (auto search = file_names.find("material_maps");
0132       search != file_names.end()) {
0133     std::string mat_map_file{names.get_detector_name() +
0134                              "_material_maps_2.json"};
0135     EXPECT_TRUE(compare_files(file_names["material_maps"], mat_map_file));
0136     std::filesystem::remove(mat_map_file);
0137     std::filesystem::remove(file_names["material_maps"]);
0138   }
0139 
0140   // Check a homogeneous material description, if present
0141   if (auto search = file_names.find("surface_grids");
0142       search != file_names.end()) {
0143     std::string grids_file{names.get_detector_name() + "_surface_grids_2.json"};
0144     EXPECT_TRUE(compare_files(file_names["surface_grids"], grids_file));
0145     std::filesystem::remove(grids_file);
0146     std::filesystem::remove(file_names["surface_grids"]);
0147   }
0148 
0149   return std::make_pair(std::move(det2), std::move(names2));
0150 }
0151 
0152 }  // anonymous namespace
0153 
0154 /// Test the reading and writing of a telescope detector
0155 GTEST_TEST(io, json_telescope_detector_reader) {
0156   using test_algebra = test::algebra;
0157   using scalar = test::scalar;
0158 
0159   mask<rectangle2D, test_algebra> rec2{0u, 100.f, 100.f};
0160 
0161   // Surface positions
0162   std::vector<scalar> positions = {1.f,   50.f,  100.f, 150.f, 200.f, 250.f,
0163                                    300.f, 350.f, 400.f, 450.f, 500.f};
0164 
0165   tel_det_config tel_cfg{rec2};
0166   tel_cfg.positions(positions);
0167 
0168   // Telescope detector
0169   vecmem::host_memory_resource host_mr;
0170   auto [tel_det, tel_names] =
0171       build_telescope_detector<test_algebra>(host_mr, tel_cfg);
0172 
0173   std::map<std::string, std::string, std::less<>> file_names;
0174   file_names["geometry"] = "telescope_detector_geometry.json";
0175   file_names["homogeneous_material"] =
0176       "telescope_detector_homogeneous_material.json";
0177 
0178   auto [det_io, names_io] =
0179       test_detector_json_io(tel_det, tel_names, file_names, host_mr);
0180 
0181   const auto& mat_store = det_io.material_store();
0182   const auto& slabs =
0183       mat_store.get<decltype(tel_det)::material::id::e_material_slab>();
0184 
0185   EXPECT_EQ(det_io.volumes().size(), 1u);
0186   EXPECT_EQ(slabs.size(), positions.size());
0187 }
0188 
0189 /// Test the reading and writing of a toy detector geometry
0190 GTEST_TEST(io, json_toy_geometry) {
0191   using metadata_t = test::toy_metadata;
0192   using test_algebra = metadata_t::algebra_type;
0193   using detector_t = detector<metadata_t>;
0194   using scalar = test::scalar;
0195 
0196   // Toy detector
0197   vecmem::host_memory_resource host_mr;
0198   toy_det_config<scalar> toy_cfg{};
0199   toy_cfg.use_material_maps(false);
0200   auto [toy_det, names] = build_toy_detector<test_algebra>(host_mr, toy_cfg);
0201 
0202   // Write the detector
0203   io::json_converter<detector_t, io::geometry_writer> geo_writer;
0204   auto file_name = geo_writer.write(
0205       toy_det, names, std::ios::out | std::ios::binary | std::ios::trunc);
0206 
0207   // Empty volume name map to be filled
0208   typename detector_t::name_map volume_name_map{};
0209   volume_name_map.set_detector_name("toy_detector");
0210 
0211   // Read the detector back in
0212   detector_builder<metadata_t> toy_builder;
0213   io::json_converter<detector_t, io::geometry_reader> geo_reader;
0214   geo_reader.read(toy_builder, file_name);
0215   auto det = toy_builder.build(host_mr, volume_name_map);
0216 
0217   // @TODO: Will only work again after IO can perform data deduplication
0218   // EXPECT_TRUE(toy_detector_test(det, volume_name_map));
0219 
0220   // Read the toy detector into the default detector type
0221   using default_metadata_t = test::default_metadata;
0222   detector_builder<default_metadata_t> comp_builder;
0223   io::json_converter<detector<default_metadata_t>, io::geometry_reader>
0224       comp_geo_reader;
0225   comp_geo_reader.read(comp_builder, file_name);
0226   volume_name_map.clear_names();
0227   auto comp_det = comp_builder.build(host_mr, volume_name_map);
0228 
0229   using mask_id = detector<default_metadata_t>::masks::id;
0230   const auto& masks = comp_det.mask_store();
0231 
0232   EXPECT_EQ(comp_det.volumes().size(), 22u);
0233   EXPECT_EQ(comp_det.surfaces().size(), 3230);
0234   EXPECT_EQ(comp_det.transform_store().size(), 3252);
0235   EXPECT_EQ(masks.template size<mask_id::e_rectangle2D>(), 2492u);
0236   EXPECT_EQ(masks.template size<mask_id::e_trapezoid2D>(), 648u);
0237   EXPECT_EQ(masks.template size<mask_id::e_annulus2D>(), 0u);
0238   EXPECT_EQ(masks.template size<mask_id::e_cylinder2D>(), 0u);
0239   EXPECT_EQ(masks.template size<mask_id::e_concentric_cylinder2D>(), 56u);
0240   EXPECT_EQ(masks.template size<mask_id::e_ring2D>(), 60u);
0241   EXPECT_EQ(masks.template size<mask_id::e_ring2D>(), 60u);
0242   EXPECT_EQ(masks.template size<mask_id::e_straw_tube>(), 0u);
0243   EXPECT_EQ(masks.template size<mask_id::e_drift_cell>(), 0u);
0244 
0245   detail::check_consistency(comp_det);
0246 }
0247 
0248 /// Test the reading and writing of a toy detector geometry "light"
0249 GTEST_TEST(io, json_toy_detector_roundtrip_homogeneous_material) {
0250   using test_algebra = test::algebra;
0251   using scalar = test::scalar;
0252 
0253   // Toy detector
0254   vecmem::host_memory_resource host_mr;
0255   toy_det_config<scalar> toy_cfg{};
0256   toy_cfg.use_material_maps(false);
0257   const auto [toy_det, toy_names] =
0258       build_toy_detector<test_algebra>(host_mr, toy_cfg);
0259 
0260   std::map<std::string, std::string, std::less<>> file_names;
0261   file_names["geometry"] = "toy_detector_geometry.json";
0262   file_names["homogeneous_material"] = "toy_detector_homogeneous_material.json";
0263   file_names["surface_grids"] = "toy_detector_surface_grids.json";
0264 
0265   auto [det_io, names_io] =
0266       test_detector_json_io<1u>(toy_det, toy_names, file_names, host_mr);
0267 
0268   // Remove empty files as there are not material maps
0269   std::filesystem::remove("toy_detector_material_maps.json");
0270   std::filesystem::remove("toy_detector_material_maps_2.json");
0271 
0272   // @TODO: Will only work again after IO can perform data deduplication
0273   // EXPECT_TRUE(toy_detector_test(det_io, names_io));
0274 }
0275 
0276 /// Test the reading and writing of a toy detector geometry
0277 GTEST_TEST(io, json_toy_detector_roundtrip_material_maps) {
0278   using test_algebra = test::algebra;
0279   using scalar = test::scalar;
0280 
0281   // Toy detector
0282   vecmem::host_memory_resource host_mr;
0283   toy_det_config<scalar> toy_cfg{};
0284   toy_cfg.use_material_maps(true);
0285   const auto [toy_det, toy_names] =
0286       build_toy_detector<test_algebra>(host_mr, toy_cfg);
0287 
0288   std::map<std::string, std::string, std::less<>> file_names;
0289   file_names["geometry"] = "toy_detector_geometry.json";
0290   file_names["homogeneous_material"] = "toy_detector_homogeneous_material.json";
0291   file_names["material_maps"] = "toy_detector_material_maps.json";
0292   file_names["surface_grids"] = "toy_detector_surface_grids.json";
0293 
0294   auto [det_io, names_io] =
0295       test_detector_json_io<1u>(toy_det, toy_names, file_names, host_mr);
0296 
0297   // @TODO: Will only work again after IO can perform data deduplication
0298   // EXPECT_TRUE(toy_detector_test(det_io, names_io));
0299 }
0300 
0301 /// Test the reading and writing of a wire chamber
0302 GTEST_TEST(io, json_wire_chamber_reader) {
0303   using test_algebra = test::algebra;
0304   using scalar = test::scalar;
0305 
0306   // Wire chamber
0307   vecmem::host_memory_resource host_mr;
0308   wire_chamber_config<scalar> wire_cfg{};
0309   auto [wire_det, wire_names] =
0310       build_wire_chamber<test_algebra>(host_mr, wire_cfg);
0311 
0312   std::map<std::string, std::string, std::less<>> file_names;
0313   file_names["geometry"] = "wire_chamber_geometry.json";
0314   file_names["homogeneous_material"] = "wire_chamber_homogeneous_material.json";
0315   file_names["surface_grids"] = "wire_chamber_surface_grids.json";
0316 
0317   auto [det_io, names_io] =
0318       test_detector_json_io(wire_det, wire_names, file_names, host_mr);
0319 
0320   // Remove empty files as there are material
0321   std::filesystem::remove("wire_chamber_material_maps.json");
0322   std::filesystem::remove("wire_chamber_material_maps_2.json");
0323 
0324   EXPECT_EQ(det_io.volumes().size(), 11u);
0325 }