File indexing completed on 2025-12-16 09:25:32
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0013 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0014 #include "Acts/Geometry/DetectorElementBase.hpp"
0015 #include "Acts/Geometry/GeometryIdentifier.hpp"
0016 #include "Acts/Geometry/Portal.hpp"
0017 #include "Acts/Geometry/PortalLinkBase.hpp"
0018 #include "Acts/Geometry/TrackingGeometry.hpp"
0019 #include "Acts/Geometry/TrackingVolume.hpp"
0020 #include "Acts/Geometry/TrapezoidVolumeBounds.hpp"
0021 #include "Acts/Geometry/TrivialPortalLink.hpp"
0022 #include "Acts/Geometry/VolumeBounds.hpp"
0023 #include "Acts/Surfaces/AnnulusBounds.hpp"
0024 #include "Acts/Surfaces/BoundaryTolerance.hpp"
0025 #include "Acts/Surfaces/CylinderBounds.hpp"
0026 #include "Acts/Surfaces/PlaneSurface.hpp"
0027 #include "Acts/Surfaces/RadialBounds.hpp"
0028 #include "Acts/Surfaces/RectangleBounds.hpp"
0029 #include "Acts/Surfaces/TrapezoidBounds.hpp"
0030 #include "Acts/Utilities/Logger.hpp"
0031 #include "Acts/Visualization/ObjVisualization3D.hpp"
0032 #include "ActsPlugins/Detray/DetrayConversionUtils.hpp"
0033 #include "ActsPlugins/Detray/DetrayPayloadConverter.hpp"
0034 #include "ActsTests/CommonHelpers/CylindricalTrackingGeometry.hpp"
0035 #include "ActsTests/CommonHelpers/DetectorElementStub.hpp"
0036 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0037
0038 #include <memory>
0039 #include <numbers>
0040
0041 #include <detray/io/backend/geometry_reader.hpp>
0042 #include <detray/io/backend/geometry_writer.hpp>
0043 #include <detray/io/backend/homogeneous_material_reader.hpp>
0044 #include <detray/io/backend/homogeneous_material_writer.hpp>
0045 #include <detray/io/backend/material_map_reader.hpp>
0046 #include <detray/io/backend/surface_grid_reader.hpp>
0047 #include <detray/io/frontend/definitions.hpp>
0048 #include <detray/io/frontend/detector_writer.hpp>
0049 #include <detray/io/frontend/detector_writer_config.hpp>
0050 #include <detray/io/frontend/payloads.hpp>
0051 #include <detray/io/json/json_io.hpp>
0052 #include <detray/plugins/svgtools/illustrator.hpp>
0053 #include <detray/plugins/svgtools/writer.hpp>
0054 #include <detray/utils/consistency_checker.hpp>
0055 #include <detray/utils/grid/detail/concepts.hpp>
0056 #include <nlohmann/json_fwd.hpp>
0057 #include <vecmem/memory/host_memory_resource.hpp>
0058 #include <vecmem/memory/memory_resource.hpp>
0059
0060 #include "detray/geometry/tracking_volume.hpp"
0061
0062 auto logger = Acts::getDefaultLogger("Test", Acts::Logging::INFO);
0063
0064 using namespace Acts;
0065 using namespace ActsPlugins;
0066
0067 namespace ActsTests {
0068
0069 BOOST_AUTO_TEST_SUITE(DetrayConversion)
0070
0071 BOOST_AUTO_TEST_CASE(DetrayTransformConversion) {
0072 auto transform = Transform3::Identity();
0073 transform.pretranslate(Vector3(1., 2., 3.));
0074 transform.rotate(Eigen::AngleAxisd(std::numbers::pi / 2., Vector3::UnitZ()));
0075
0076 detray::io::transform_payload payload =
0077 DetrayConversionUtils::convertTransform(transform);
0078
0079 CHECK_CLOSE_ABS(payload.tr[0u], 1., std::numeric_limits<double>::epsilon());
0080 CHECK_CLOSE_ABS(payload.tr[1u], 2., std::numeric_limits<double>::epsilon());
0081 CHECK_CLOSE_ABS(payload.tr[2u], 3., std::numeric_limits<double>::epsilon());
0082
0083 RotationMatrix3 rotation = transform.rotation().transpose();
0084 CHECK_CLOSE_ABS(payload.rot[0u], rotation(0, 0),
0085 std::numeric_limits<double>::epsilon());
0086 CHECK_CLOSE_ABS(payload.rot[1u], rotation(0, 1),
0087 std::numeric_limits<double>::epsilon());
0088 CHECK_CLOSE_ABS(payload.rot[2u], rotation(0, 2),
0089 std::numeric_limits<double>::epsilon());
0090 CHECK_CLOSE_ABS(payload.rot[3u], rotation(1, 0),
0091 std::numeric_limits<double>::epsilon());
0092 CHECK_CLOSE_ABS(payload.rot[4u], rotation(1, 1),
0093 std::numeric_limits<double>::epsilon());
0094 CHECK_CLOSE_ABS(payload.rot[5u], rotation(1, 2),
0095 std::numeric_limits<double>::epsilon());
0096 CHECK_CLOSE_ABS(payload.rot[6u], rotation(2, 0),
0097 std::numeric_limits<double>::epsilon());
0098 CHECK_CLOSE_ABS(payload.rot[7u], rotation(2, 1),
0099 std::numeric_limits<double>::epsilon());
0100 CHECK_CLOSE_ABS(payload.rot[8u], rotation(2, 2),
0101 std::numeric_limits<double>::epsilon());
0102 }
0103
0104 BOOST_AUTO_TEST_CASE(DetrayMaskConversion) {
0105
0106 {
0107 Acts::AnnulusBounds annulus(10., 20., 0.5, 1.5, {1., 2.}, 1.);
0108 auto payload = DetrayPayloadConverter::convertMask(annulus, false);
0109 BOOST_CHECK(payload.shape == detray::io::shape_id::annulus2);
0110 using enum detray::annulus2D::boundaries;
0111 CHECK_CLOSE_ABS(payload.boundaries[e_min_r], 10., 1e-10);
0112 CHECK_CLOSE_ABS(payload.boundaries[e_max_r], 20., 1e-10);
0113 CHECK_CLOSE_ABS(payload.boundaries[e_min_phi_rel], 0.5,
0114 1e-10);
0115 CHECK_CLOSE_ABS(payload.boundaries[e_max_phi_rel], 1.5,
0116 1e-10);
0117 CHECK_CLOSE_ABS(payload.boundaries[e_average_phi], 1.,
0118 1e-10);
0119 CHECK_CLOSE_ABS(payload.boundaries[e_shift_x], 1., 1e-10);
0120 CHECK_CLOSE_ABS(payload.boundaries[e_shift_y], 2., 1e-10);
0121 }
0122
0123
0124 {
0125 Acts::RectangleBounds rectangle(5., 10.);
0126 auto payload = DetrayPayloadConverter::convertMask(rectangle, false);
0127 BOOST_CHECK(payload.shape == detray::io::shape_id::rectangle2);
0128 using enum detray::rectangle2D::boundaries;
0129 CHECK_CLOSE_ABS(payload.boundaries[e_half_x], 5., 1e-10);
0130 CHECK_CLOSE_ABS(payload.boundaries[e_half_y], 10., 1e-10);
0131 }
0132
0133
0134 {
0135 Acts::CylinderBounds cylinder(50., 100.);
0136 auto payload = DetrayPayloadConverter::convertMask(cylinder, false);
0137 BOOST_CHECK(payload.shape == detray::io::shape_id::cylinder2);
0138 using enum detray::concentric_cylinder2D::boundaries;
0139 CHECK_CLOSE_ABS(payload.boundaries[e_r], 50., 1e-10);
0140 CHECK_CLOSE_ABS(payload.boundaries[e_lower_z], -100., 1e-10);
0141 CHECK_CLOSE_ABS(payload.boundaries[e_upper_z], 100., 1e-10);
0142
0143
0144 auto portalPayload = DetrayPayloadConverter::convertMask(cylinder, true);
0145 BOOST_CHECK(portalPayload.shape == detray::io::shape_id::portal_cylinder2);
0146 CHECK_CLOSE_ABS(portalPayload.boundaries[e_r], 50., 1e-10);
0147 CHECK_CLOSE_ABS(portalPayload.boundaries[e_lower_z], -100.,
0148 1e-10);
0149 CHECK_CLOSE_ABS(portalPayload.boundaries[e_upper_z], 100.,
0150 1e-10);
0151 }
0152
0153
0154 {
0155 Acts::TrapezoidBounds trapezoid(4., 8., 10.,
0156 0.);
0157 auto payload = DetrayPayloadConverter::convertMask(trapezoid, false);
0158 BOOST_CHECK(payload.shape == detray::io::shape_id::trapezoid2);
0159 using enum detray::trapezoid2D::boundaries;
0160 CHECK_CLOSE_ABS(payload.boundaries[e_half_length_0], 4.,
0161 1e-10);
0162 CHECK_CLOSE_ABS(payload.boundaries[e_half_length_1], 8.,
0163 1e-10);
0164 CHECK_CLOSE_ABS(payload.boundaries[e_half_length_2], 10.,
0165 1e-10);
0166 CHECK_CLOSE_ABS(payload.boundaries[e_divisor], 1. / (2. * 10.),
0167 1e-10);
0168 }
0169
0170
0171 {
0172 Acts::RadialBounds radial(5.,
0173 15);
0174 auto payload = DetrayPayloadConverter::convertMask(radial, false);
0175 BOOST_CHECK(payload.shape == detray::io::shape_id::ring2);
0176 using enum detray::ring2D::boundaries;
0177 CHECK_CLOSE_ABS(payload.boundaries[e_inner_r], 5., 1e-10);
0178 CHECK_CLOSE_ABS(payload.boundaries[e_outer_r], 15., 1e-10);
0179 }
0180 }
0181
0182 BOOST_AUTO_TEST_CASE(DetrayMaskConversionErrors) {
0183
0184
0185
0186 {
0187 std::array<double, Acts::RectangleBounds::eSize> values = {
0188 -2., -3., 5., 4.};
0189 Acts::RectangleBounds asymmetricRect(values);
0190 BOOST_CHECK_THROW(
0191 DetrayPayloadConverter::convertMask(asymmetricRect, false),
0192 std::runtime_error);
0193 }
0194
0195
0196 {
0197 Acts::RadialBounds partialRadial(5., 15., 0.5 * std::numbers::pi);
0198 BOOST_CHECK_THROW(DetrayPayloadConverter::convertMask(partialRadial, false),
0199 std::runtime_error);
0200 }
0201
0202 {
0203 Acts::RadialBounds partialRadial(
0204 5., 15., std::numbers::pi,
0205 0.75 * std::numbers::pi);
0206 BOOST_CHECK_THROW(DetrayPayloadConverter::convertMask(partialRadial, false),
0207 std::runtime_error);
0208 }
0209
0210
0211 {
0212 class MockDiscBounds final : public Acts::SurfaceBounds {
0213 public:
0214 BoundsType type() const final { return BoundsType::eDisc; }
0215 bool isCartesian() const final { return true; }
0216 SquareMatrix2 boundToCartesianJacobian(
0217 const Vector2& ) const final {
0218 return SquareMatrix2::Identity();
0219 }
0220 SquareMatrix2 boundToCartesianMetric(
0221 const Vector2& ) const final {
0222 return SquareMatrix2::Identity();
0223 }
0224 std::vector<double> values() const final { return {}; }
0225 Vector2 center() const final { return Vector2::Zero(); }
0226 bool inside(const Vector2& ) const final { return false; }
0227 Vector2 closestPoint(const Vector2& lposition,
0228 const SquareMatrix2& ) const final {
0229 return lposition;
0230 }
0231 bool inside(const Acts::Vector2& ,
0232 const Acts::BoundaryTolerance& ) const final {
0233 return false;
0234 }
0235 std::ostream& toStream(std::ostream& sl) const final { return sl; }
0236 };
0237 MockDiscBounds mockDisc;
0238 BOOST_CHECK_THROW(DetrayPayloadConverter::convertMask(mockDisc, false),
0239 std::runtime_error);
0240 }
0241
0242
0243 {
0244 class MockUnknownBounds final : public Acts::SurfaceBounds {
0245 public:
0246 BoundsType type() const final {
0247 return static_cast<BoundsType>(999);
0248 }
0249 bool isCartesian() const final { return true; }
0250 SquareMatrix2 boundToCartesianJacobian(
0251 const Vector2& ) const final {
0252 return SquareMatrix2::Identity();
0253 }
0254 SquareMatrix2 boundToCartesianMetric(
0255 const Vector2& ) const final {
0256 return SquareMatrix2::Identity();
0257 }
0258 std::vector<double> values() const final { return {}; }
0259 Vector2 center() const final { return Vector2::Zero(); }
0260 bool inside(const Vector2& ) const final { return false; }
0261 Vector2 closestPoint(const Vector2& lposition,
0262 const SquareMatrix2& ) const final {
0263 return lposition;
0264 }
0265 bool inside(const Acts::Vector2& ,
0266 const Acts::BoundaryTolerance& ) const final {
0267 return false;
0268 }
0269 std::ostream& toStream(std::ostream& sl) const final { return sl; }
0270 };
0271 MockUnknownBounds mockUnknown;
0272 auto payload = DetrayPayloadConverter::convertMask(mockUnknown, false);
0273 BOOST_CHECK(payload.shape == detray::io::shape_id::unknown);
0274 }
0275 }
0276
0277 BOOST_AUTO_TEST_CASE(DetraySurfaceConversionTests) {
0278 GeometryContext gctx;
0279
0280
0281 Transform3 transform = Transform3::Identity();
0282 transform.pretranslate(Vector3(1., 2., 3.));
0283 transform.rotate(Eigen::AngleAxisd(0.5 * std::numbers::pi, Vector3::UnitZ()));
0284
0285
0286 auto bounds = std::make_shared<RectangleBounds>(5., 10.);
0287
0288
0289 auto surface = Surface::makeShared<PlaneSurface>(transform, bounds);
0290
0291
0292 {
0293 DetrayPayloadConverter::Config cfg;
0294 cfg.sensitiveStrategy =
0295 DetrayPayloadConverter::Config::SensitiveStrategy::Identifier;
0296
0297 DetrayPayloadConverter converter(cfg);
0298
0299
0300 {
0301 auto payload = converter.convertSurface(gctx, *surface);
0302
0303
0304 BOOST_CHECK(payload.type == detray::surface_id::e_passive);
0305
0306
0307 CHECK_CLOSE_ABS(payload.transform.tr[0], 1., 1e-10);
0308 CHECK_CLOSE_ABS(payload.transform.tr[1], 2., 1e-10);
0309 CHECK_CLOSE_ABS(payload.transform.tr[2], 3., 1e-10);
0310
0311
0312 BOOST_CHECK(payload.masks.at(0).shape ==
0313 detray::io::shape_id::rectangle2);
0314 using enum detray::rectangle2D::boundaries;
0315 CHECK_CLOSE_ABS(payload.masks.at(0).boundaries[e_half_x], 5., 1e-10);
0316 CHECK_CLOSE_ABS(payload.masks.at(0).boundaries[e_half_y], 10., 1e-10);
0317 }
0318
0319
0320 {
0321 auto sensitiveSurface =
0322 Surface::makeShared<PlaneSurface>(transform, bounds);
0323 sensitiveSurface->assignGeometryId(GeometryIdentifier().withSensitive(1));
0324
0325 auto payload = converter.convertSurface(gctx, *sensitiveSurface);
0326
0327 BOOST_CHECK(payload.type == detray::surface_id::e_sensitive);
0328 }
0329 }
0330
0331
0332 {
0333 DetrayPayloadConverter::Config cfg;
0334 cfg.sensitiveStrategy =
0335 DetrayPayloadConverter::Config::SensitiveStrategy::DetectorElement;
0336
0337 DetrayPayloadConverter converter(cfg);
0338
0339
0340 {
0341 auto payload = converter.convertSurface(gctx, *surface);
0342 BOOST_CHECK(payload.type == detray::surface_id::e_passive);
0343 }
0344
0345
0346 {
0347
0348 auto detElement =
0349 std::make_shared<DetectorElementStub>(transform, bounds, 1.0);
0350
0351
0352 auto sensitiveSurface =
0353 Surface::makeShared<PlaneSurface>(bounds, *detElement);
0354
0355 auto payload = converter.convertSurface(gctx, *sensitiveSurface);
0356 BOOST_CHECK(payload.type == detray::surface_id::e_sensitive);
0357 }
0358 }
0359 }
0360
0361 BOOST_AUTO_TEST_CASE(DetrayPortalConversionTests) {
0362 GeometryContext gctx;
0363
0364
0365 Transform3 transform = Transform3::Identity();
0366 transform.pretranslate(Vector3(1., 2., 3.));
0367 transform.rotate(Eigen::AngleAxisd(0.5 * std::numbers::pi, Vector3::UnitZ()));
0368
0369
0370 auto bounds = std::make_shared<RectangleBounds>(5., 10.);
0371
0372 auto cvlBounds = std::make_shared<CylinderVolumeBounds>(5., 10., 10.);
0373 TrackingVolume tv(transform, cvlBounds);
0374
0375
0376 auto surface = Surface::makeShared<PlaneSurface>(transform, bounds);
0377
0378
0379 auto portal = std::make_shared<Portal>(Direction::AlongNormal(), surface, tv);
0380
0381
0382 {
0383 DetrayPayloadConverter::Config cfg;
0384 DetrayPayloadConverter converter(cfg);
0385 auto payload = converter.convertSurface(gctx, portal->surface(), true);
0386
0387
0388 BOOST_CHECK(payload.type == detray::surface_id::e_portal);
0389
0390
0391 CHECK_CLOSE_ABS(payload.transform.tr[0], 1., 1e-10);
0392 CHECK_CLOSE_ABS(payload.transform.tr[1], 2., 1e-10);
0393 CHECK_CLOSE_ABS(payload.transform.tr[2], 3., 1e-10);
0394
0395
0396
0397 BOOST_CHECK(payload.masks.at(0).shape == detray::io::shape_id::rectangle2);
0398 using enum detray::rectangle2D::boundaries;
0399 CHECK_CLOSE_ABS(payload.masks.at(0).boundaries[e_half_x], 5., 1e-10);
0400 CHECK_CLOSE_ABS(payload.masks.at(0).boundaries[e_half_y], 10., 1e-10);
0401 }
0402 }
0403
0404 BOOST_AUTO_TEST_CASE(DetrayVolumeConversionTests) {
0405
0406 Transform3 transform = Transform3::Identity();
0407 transform.pretranslate(Vector3(1., 2., 3.));
0408 transform.rotate(Eigen::AngleAxisd(0.5 * std::numbers::pi, Vector3::UnitZ()));
0409
0410 DetrayPayloadConverter::Config cfg;
0411 DetrayPayloadConverter converter(cfg);
0412
0413
0414 {
0415 auto cvlBounds = std::make_shared<CylinderVolumeBounds>(5., 10., 10.);
0416 auto volume =
0417 std::make_shared<TrackingVolume>(transform, cvlBounds, "TestCylinder");
0418
0419 auto payload = converter.convertVolume(*volume);
0420
0421
0422 BOOST_CHECK(payload.type == detray::volume_id::e_cylinder);
0423
0424
0425 BOOST_CHECK_EQUAL(payload.name, "TestCylinder");
0426
0427
0428 CHECK_CLOSE_ABS(payload.transform.tr[0], 1., 1e-10);
0429 CHECK_CLOSE_ABS(payload.transform.tr[1], 2., 1e-10);
0430 CHECK_CLOSE_ABS(payload.transform.tr[2], 3., 1e-10);
0431 }
0432
0433
0434 {
0435 auto cuboidBounds = std::make_shared<CuboidVolumeBounds>(5., 10., 15.);
0436 auto volume =
0437 std::make_shared<TrackingVolume>(transform, cuboidBounds, "TestCuboid");
0438
0439 auto payload = converter.convertVolume(*volume);
0440
0441 BOOST_CHECK(payload.type == detray::volume_id::e_cuboid);
0442 BOOST_CHECK_EQUAL(payload.name, "TestCuboid");
0443 }
0444
0445
0446 {
0447 auto trapBounds = std::make_shared<TrapezoidVolumeBounds>(4., 8., 10., 15.);
0448 auto volume = std::make_shared<TrackingVolume>(transform, trapBounds,
0449 "TestTrapezoid");
0450
0451 auto payload = converter.convertVolume(*volume);
0452
0453 BOOST_CHECK(payload.type == detray::volume_id::e_trapezoid);
0454 BOOST_CHECK_EQUAL(payload.name, "TestTrapezoid");
0455 }
0456
0457
0458 {
0459 class MockVolumeBounds : public VolumeBounds {
0460 public:
0461 BoundsType type() const final { return BoundsType::eOther; }
0462 std::vector<double> values() const final { return {}; }
0463 bool inside(const Vector3& , double ) const final {
0464 return false;
0465 }
0466 std::ostream& toStream(std::ostream& sl) const final { return sl; }
0467
0468 std::vector<OrientedSurface> orientedSurfaces(
0469 const Transform3& ) const final {
0470 return {};
0471 }
0472
0473 Volume::BoundingBox boundingBox(const Transform3* ,
0474 const Vector3& ,
0475 const Volume* ) const final {
0476 return {nullptr, Vector3::Zero(), Vector3::Zero()};
0477 }
0478 };
0479
0480 auto mockBounds = std::make_shared<MockVolumeBounds>();
0481 TrackingVolume tv(transform, mockBounds, "TestUnknown");
0482
0483 auto volume =
0484 std::make_shared<TrackingVolume>(transform, mockBounds, "TestUnknown");
0485
0486 auto payload = converter.convertVolume(*volume);
0487
0488 BOOST_CHECK(payload.type == detray::volume_id::e_unknown);
0489 BOOST_CHECK_EQUAL(payload.name, "TestUnknown");
0490 }
0491 }
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577 BOOST_AUTO_TEST_CASE(DetrayTrackingGeometryConversionTests) {
0578 GeometryContext gctx;
0579 auto geoLogger = getDefaultLogger("Geo", Logging::VERBOSE);
0580
0581 CylindricalTrackingGeometry cGeometry(gctx, true);
0582 auto tGeometry = cGeometry(*geoLogger);
0583
0584 ObjVisualization3D obj;
0585
0586 tGeometry->visualize(obj, gctx);
0587
0588 obj.write("cylindrical.obj");
0589
0590 vecmem::host_memory_resource mr;
0591
0592 DetrayPayloadConverter::Config cfg;
0593
0594 tGeometry->apply([&cfg](const TrackingVolume& volume) {
0595 if (volume.volumeName() == "Beampipe") {
0596 cfg.beampipeVolume = &volume;
0597 }
0598 });
0599
0600 auto logger = getDefaultLogger("Cnv", Logging::DEBUG);
0601 DetrayPayloadConverter converter(cfg, std::move(logger));
0602 auto payloads = converter.convertTrackingGeometry(gctx, *tGeometry);
0603
0604 const auto& detector = *payloads.detector;
0605 const auto& homogeneousMaterial = *payloads.homogeneousMaterial;
0606 auto& materialGrids = *payloads.materialGrids;
0607 const auto& surfaceGrids = *payloads.surfaceGrids;
0608
0609 BOOST_CHECK_EQUAL(detector.volumes.size(), 6);
0610 for (const auto& volume : detector.volumes) {
0611 BOOST_CHECK(volume.type == detray::volume_id::e_cylinder);
0612 }
0613 BOOST_CHECK_EQUAL(detector.volumes.at(0).name, "Beampipe");
0614 BOOST_CHECK_EQUAL(detector.volumes.at(1).name, "World");
0615 BOOST_CHECK_EQUAL(detector.volumes.at(2).name, "L0");
0616 BOOST_CHECK_EQUAL(detector.volumes.at(3).name, "L1");
0617 BOOST_CHECK_EQUAL(detector.volumes.at(4).name, "L2");
0618 BOOST_CHECK_EQUAL(detector.volumes.at(5).name, "L3");
0619
0620
0621
0622
0623 BOOST_CHECK_EQUAL(homogeneousMaterial.volumes.size(), 6);
0624
0625 for (const auto& volume : detector.volumes) {
0626 auto it = std::ranges::find_if(
0627 homogeneousMaterial.volumes, [&](const auto& hMat) {
0628 return hMat.volume_link.link == volume.index.link;
0629 });
0630
0631 if (it == homogeneousMaterial.volumes.end()) {
0632 BOOST_FAIL("No material slab found for volume: " + volume.name);
0633 continue;
0634 }
0635
0636 auto& hMat = *it;
0637
0638
0639 BOOST_CHECK_EQUAL(volume.surfaces.size(), hMat.mat_slabs.size());
0640 }
0641
0642 BOOST_CHECK_EQUAL(materialGrids.grids.size(), 2);
0643
0644 BOOST_CHECK_EQUAL(surfaceGrids.grids.size(), 4);
0645
0646
0647 const std::vector<std::pair<int, int>> kLayerBinning = {
0648 {16, 14}, {32, 14}, {52, 14}, {78, 14}};
0649
0650 for (const auto& [idx, it] : enumerate(surfaceGrids.grids)) {
0651 const auto [b0, b1] = kLayerBinning.at(idx);
0652
0653 const auto [key, grids] = it;
0654
0655
0656 BOOST_CHECK_EQUAL(grids.size(), 1);
0657
0658 auto& grid = grids.front();
0659
0660
0661 BOOST_CHECK_EQUAL(grid.axes.size(), 2);
0662
0663 BOOST_CHECK_EQUAL(b0, grid.axes.front().bins);
0664 BOOST_CHECK_EQUAL(b1, grid.axes.back().bins);
0665
0666 std::size_t nBinsExp = grid.axes.front().bins * grid.axes.back().bins;
0667 BOOST_CHECK_EQUAL(grid.bins.size(), nBinsExp);
0668 }
0669
0670 BOOST_CHECK_EQUAL(payloads.names.size(), 7);
0671
0672
0673
0674 {
0675 detray::io::geo_header_payload header_data;
0676 header_data.common = detray::io::detail::basic_converter::to_payload(
0677 payloads.names.at(0), detray::io::geometry_writer::tag);
0678 header_data.sub_header.emplace();
0679 auto& geo_sub_header = header_data.sub_header.value();
0680 geo_sub_header.n_volumes = detector.volumes.size();
0681 geo_sub_header.n_surfaces = 0;
0682 for (const auto& volume : detector.volumes) {
0683 geo_sub_header.n_surfaces += volume.surfaces.size();
0684 }
0685
0686 nlohmann::ordered_json out_json;
0687 out_json["header"] = header_data;
0688 out_json["data"] = detector;
0689
0690 std::ofstream ofs{"Detector_geometry_direct.json"};
0691 ofs << out_json.dump(2) << std::endl;
0692 }
0693
0694 {
0695 detray::io::homogeneous_material_header_payload header_data;
0696 header_data.common = detray::io::detail::basic_converter::to_payload(
0697 payloads.names.at(0), detray::io::homogeneous_material_writer::tag);
0698 header_data.sub_header.emplace();
0699 header_data.sub_header->n_rods = 0;
0700 header_data.sub_header->n_slabs = 0;
0701
0702 for (const auto& hVol : homogeneousMaterial.volumes) {
0703 if (hVol.mat_rods.has_value()) {
0704 header_data.sub_header->n_rods += hVol.mat_rods->size();
0705 }
0706 header_data.sub_header->n_slabs += hVol.mat_slabs.size();
0707 }
0708
0709 nlohmann::ordered_json out_json;
0710 out_json["header"] = header_data;
0711 out_json["data"] = homogeneousMaterial;
0712
0713 std::ofstream ofs{"Detector_homogeneous_material_direct.json"};
0714 ofs << out_json.dump(2) << std::endl;
0715 }
0716
0717
0718
0719 using detector_t =
0720 detray::detector<detray::default_metadata<detray::array<double>>>;
0721
0722
0723 detray::detector_builder<detector_t::metadata> detectorBuilder{};
0724
0725 detray::io::geometry_reader::from_payload<detector_t>(detectorBuilder,
0726 detector);
0727
0728 detray::io::homogeneous_material_reader::from_payload<detector_t>(
0729 detectorBuilder, homogeneousMaterial);
0730
0731 detray::io::material_map_reader<std::integral_constant<std::size_t, 2>>::
0732 from_payload<detector_t>(detectorBuilder, std::move(materialGrids));
0733
0734 detray::io::surface_grid_reader<detector_t::surface_type,
0735 std::integral_constant<std::size_t, 0>,
0736 std::integral_constant<std::size_t, 2>>::
0737 from_payload<detector_t>(detectorBuilder, surfaceGrids);
0738
0739 detector_t detrayDetector(detectorBuilder.build(mr));
0740
0741
0742 detray::detail::check_consistency(detrayDetector);
0743
0744 detray::svgtools::illustrator illustrator(detrayDetector, payloads.names);
0745 illustrator.hide_eta_lines(true);
0746 illustrator.show_info(true);
0747
0748 const auto svg_zr = illustrator.draw_detector(actsvg::views::z_r{});
0749 actsvg::style::stroke stroke_black = actsvg::style::stroke();
0750 auto zr_axis = actsvg::draw::x_y_axes("axes", {-250, 250}, {-250, 250},
0751 stroke_black, "z", "r");
0752 detray::svgtools::write_svg("test_svgtools_detector_zr", {
0753 zr_axis,
0754 svg_zr,
0755 });
0756
0757 const auto svg_xy = illustrator.draw_detector(actsvg::views::x_y{});
0758 auto xy_axis = actsvg::draw::x_y_axes("axes", {-250, 250}, {-250, 250},
0759 stroke_black, "x", "y");
0760 detray::svgtools::write_svg("test_svgtools_detector_xy", {
0761 xy_axis,
0762 svg_xy,
0763 });
0764
0765 auto writer_cfg = detray::io::detector_writer_config{}
0766 .format(detray::io::format::json)
0767 .replace_files(true);
0768
0769
0770
0771
0772 detray::io::write_detector(detrayDetector, payloads.names, writer_cfg);
0773 }
0774
0775 BOOST_AUTO_TEST_SUITE_END()
0776 }