Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:13:12

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 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Detector/ProtoDetector.hpp"
0013 #include "Acts/Geometry/Extent.hpp"
0014 #include "Acts/Plugins/Json/ProtoDetectorJsonConverter.hpp"
0015 #include "Acts/Plugins/Json/SurfaceJsonConverter.hpp"
0016 #include "Acts/Surfaces/Surface.hpp"
0017 #include "Acts/Utilities/BinningData.hpp"
0018 #include "Acts/Utilities/BinningType.hpp"
0019 #include "Acts/Utilities/Enumerate.hpp"
0020 
0021 #include <array>
0022 #include <cmath>
0023 #include <fstream>
0024 #include <iterator>
0025 #include <numbers>
0026 #include <optional>
0027 #include <string>
0028 #include <vector>
0029 
0030 #include <nlohmann/json.hpp>
0031 
0032 #include "EqualityHelpers.hpp"
0033 
0034 using namespace Acts;
0035 
0036 namespace {
0037 
0038 /// @brief Helper method to compare proto volumes
0039 /// @param one the first volume object
0040 /// @param two the second volume object
0041 /// @param tolerance the tolerance
0042 /// @return a boolean to see if they are equal
0043 bool isEqual(const Acts::ProtoVolume& one, const Acts::ProtoVolume& two,
0044              const double tolerance = 0.) {
0045   bool nameEq = (one.name == two.name);
0046   // Name
0047   BOOST_CHECK(nameEq);
0048   // Extent
0049   bool extentEq = isEqual(one.extent, two.extent, tolerance);
0050   BOOST_CHECK(extentEq);
0051 
0052   // Check internal structure
0053   bool internalValueEq = (one.internal.has_value() == two.internal.has_value());
0054   BOOST_CHECK(internalValueEq);
0055   bool internalEq = internalValueEq;
0056   if (one.internal.has_value() && two.internal.has_value()) {
0057     // Check consistency of the internal structure
0058     const auto& itsOne = one.internal.value();
0059     const auto& itsTwo = two.internal.value();
0060     bool layerTypeEq = (itsOne.layerType == itsTwo.layerType);
0061     BOOST_CHECK(layerTypeEq);
0062     internalEq = layerTypeEq;
0063     bool sBinningSizeEq =
0064         (itsOne.surfaceBinning.size() == itsTwo.surfaceBinning.size());
0065     BOOST_CHECK(sBinningSizeEq);
0066     internalEq = internalEq && sBinningSizeEq;
0067     for (auto [isb, sb] : Acts::enumerate(itsOne.surfaceBinning)) {
0068       bool sBinningEq = isEqual(sb, itsTwo.surfaceBinning[isb], tolerance);
0069       BOOST_CHECK(sBinningEq);
0070       internalEq = internalEq && sBinningEq;
0071     }
0072   }
0073   BOOST_CHECK(internalEq);
0074 
0075   // Check container structure
0076   bool containerValueEq =
0077       (one.container.has_value() == two.container.has_value());
0078   BOOST_CHECK(containerValueEq);
0079   bool containerEq = containerValueEq;
0080   if (one.container.has_value() && two.container.has_value()) {
0081     // Check consistency of the container structure
0082     const auto& ctsOne = one.container.value();
0083     const auto& ctsTwo = two.container.value();
0084     bool layerContainerEq = (ctsOne.layerContainer == ctsTwo.layerContainer);
0085     BOOST_CHECK(layerContainerEq);
0086     containerEq = layerContainerEq;
0087     bool cBinningSizeEq =
0088         ctsOne.constituentBinning.size() == ctsTwo.constituentBinning.size();
0089     containerEq = containerEq && cBinningSizeEq;
0090     BOOST_CHECK(cBinningSizeEq);
0091     for (auto [icb, cb] : Acts::enumerate(ctsOne.constituentBinning)) {
0092       bool cBinningEq = isEqual(cb, ctsTwo.constituentBinning[icb], tolerance);
0093       BOOST_CHECK(cBinningEq);
0094       containerEq = containerEq && cBinningEq;
0095     }
0096     // Recursively walk down
0097     bool cSizeEq =
0098         (ctsOne.constituentVolumes.size() == ctsTwo.constituentVolumes.size());
0099     BOOST_CHECK(cSizeEq);
0100     containerEq = cSizeEq;
0101     for (auto [ic, cOne] : Acts::enumerate(ctsOne.constituentVolumes)) {
0102       const auto& cTwo = ctsTwo.constituentVolumes[ic];
0103       bool cEq = isEqual(cOne, cTwo, tolerance);
0104       BOOST_CHECK(cEq);
0105       containerEq = containerEq && cEq;
0106     }
0107   }
0108   BOOST_CHECK(containerEq);
0109 
0110   // Give the overall judgement
0111   return nameEq && extentEq && internalEq && containerEq;
0112 }
0113 
0114 }  // namespace
0115 
0116 BOOST_AUTO_TEST_SUITE(ProtoDetectorJsonConverter)
0117 
0118 BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) {
0119   Acts::ExtentEnvelope cylinderLayerEnvelope = ExtentEnvelope::Zero();
0120   cylinderLayerEnvelope[Acts::AxisDirection::AxisR] = {1., 1.};
0121   cylinderLayerEnvelope[Acts::AxisDirection::AxisZ] = {2., 2.};
0122 
0123   Acts::ExtentEnvelope discLayerEnvelope = ExtentEnvelope::Zero();
0124   discLayerEnvelope[Acts::AxisDirection::AxisR] = {1., 1.};
0125   discLayerEnvelope[Acts::AxisDirection::AxisZ] = {1., 1.};
0126 
0127   // Beam Pipe container
0128   Acts::ProtoVolume beamPipeContainer;
0129   beamPipeContainer.name = "odd-beam-pipe";
0130   beamPipeContainer.extent.set(Acts::AxisDirection::AxisR, 0., 25);
0131   Acts::ProtoVolume beamPipe;
0132   beamPipe.name = "odd-beam-pipe-l";
0133   beamPipe.extent.set(Acts::AxisDirection::AxisR, 2., 24.);
0134   beamPipe.internal = Acts::ProtoVolume::InternalStructure{
0135       Acts::Surface::SurfaceType::Cylinder};
0136   beamPipeContainer.container = Acts::ProtoVolume::ContainerStructure{
0137       {beamPipe},
0138       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisR, {0., 1.})},
0139       true};
0140 
0141   // Pixel section
0142   Acts::ProtoVolume pixelContainer;
0143   pixelContainer.name = "odd-pixel";
0144   pixelContainer.extent.set(Acts::AxisDirection::AxisR, 25., 200);
0145 
0146   Acts::ProtoVolume pixelNec;
0147   pixelNec.name = "odd-pixel-nec";
0148   pixelNec.extent.set(Acts::AxisDirection::AxisZ, -3100., -580);
0149 
0150   Acts::ProtoVolume pixNecD6;
0151   pixNecD6.name = "odd-pixel-nec-d6";
0152   pixNecD6.extent.set(Acts::AxisDirection::AxisZ, -1540., -1500);
0153   Acts::ProtoVolume pixNecD5;
0154   pixNecD5.name = "odd-pixel-nec-d5";
0155   pixNecD5.extent.set(Acts::AxisDirection::AxisZ, -1340., -1300);
0156   Acts::ProtoVolume pixNecD4;
0157   pixNecD4.name = "odd-pixel-nec-d4";
0158   pixNecD4.extent.set(Acts::AxisDirection::AxisZ, -1140., -1100);
0159   Acts::ProtoVolume pixNecD3;
0160   pixNecD3.name = "odd-pixel-nec-d3";
0161   pixNecD3.extent.set(Acts::AxisDirection::AxisZ, -1000., -960.);
0162   Acts::ProtoVolume pixNecD2;
0163   pixNecD2.name = "odd-pixel-nec-d2";
0164   pixNecD2.extent.set(Acts::AxisDirection::AxisZ, -860., -820);
0165   Acts::ProtoVolume pixNecD1;
0166   pixNecD1.name = "odd-pixel-nec-d1";
0167   pixNecD1.extent.set(Acts::AxisDirection::AxisZ, -740., -700);
0168   Acts::ProtoVolume pixNecD0;
0169   pixNecD0.name = "odd-pixel-nec-d0";
0170   pixNecD0.extent.set(Acts::AxisDirection::AxisZ, -640., -600);
0171   pixelNec.container = Acts::ProtoVolume::ContainerStructure{
0172       {pixNecD6, pixNecD5, pixNecD4, pixNecD3, pixNecD2, pixNecD1, pixNecD0},
0173       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisZ, {0., 1.})},
0174       true};
0175 
0176   Acts::BinningData pixEcBinningR =
0177       Acts::BinningData(Acts::open, Acts::AxisDirection::AxisR, 2., 0., 1.);
0178   Acts::BinningData pixEcBinningPhi =
0179       Acts::BinningData(Acts::closed, Acts::AxisDirection::AxisPhi, 30.,
0180                         -std::numbers::pi, std::numbers::pi);
0181 
0182   for (auto& cv : pixelNec.container.value().constituentVolumes) {
0183     cv.extent.setEnvelope(discLayerEnvelope);
0184     cv.internal = Acts::ProtoVolume::InternalStructure{
0185         Acts::Surface::SurfaceType::Disc, {pixEcBinningR, pixEcBinningPhi}};
0186   }
0187 
0188   Acts::ProtoVolume pixelBarrel;
0189   pixelBarrel.name = "odd-pixel-barrel";
0190   pixelBarrel.extent.set(Acts::AxisDirection::AxisZ, -580., 580);
0191 
0192   Acts::ProtoVolume pixBarrelL0;
0193   pixBarrelL0.name = "odd-pixel-barrel-l0";
0194   pixBarrelL0.extent.set(Acts::AxisDirection::AxisR, 28., 48.);
0195   pixBarrelL0.extent.set(Acts::AxisDirection::AxisZ, -580., 580);
0196   Acts::ProtoVolume pixBarrelL1;
0197   pixBarrelL1.name = "odd-pixel-barrel-l1";
0198   pixBarrelL1.extent.set(Acts::AxisDirection::AxisR, 62., 76);
0199   pixBarrelL1.extent.set(Acts::AxisDirection::AxisZ, -580., 580);
0200   Acts::ProtoVolume pixBarrelL2;
0201   pixBarrelL2.name = "odd-pixel-barrel-l2";
0202   pixBarrelL2.extent.set(Acts::AxisDirection::AxisR, 100., 120.);
0203   pixBarrelL2.extent.set(Acts::AxisDirection::AxisZ, -580., 580);
0204   Acts::ProtoVolume pixBarrelL3;
0205   pixBarrelL3.name = "odd-pixel-barrel-l3";
0206   pixBarrelL3.extent.set(Acts::AxisDirection::AxisR, 160., 180.);
0207   pixBarrelL3.extent.set(Acts::AxisDirection::AxisZ, -580., 580);
0208 
0209   pixelBarrel.container = Acts::ProtoVolume::ContainerStructure{
0210       {pixBarrelL0, pixBarrelL1, pixBarrelL2, pixBarrelL3},
0211       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisR, {0., 1})},
0212       true};
0213 
0214   for (auto& cv : pixelBarrel.container.value().constituentVolumes) {
0215     cv.extent.setEnvelope(cylinderLayerEnvelope);
0216     cv.internal = Acts::ProtoVolume::InternalStructure{
0217         Acts::Surface::SurfaceType::Cylinder};
0218   }
0219 
0220   Acts::ProtoVolume pixelPec;
0221   pixelPec.name = "odd-pixel-pec";
0222   pixelPec.extent.set(Acts::AxisDirection::AxisZ, 580., 3100.);
0223 
0224   Acts::ProtoVolume pixPecD0;
0225   pixPecD0.name = "odd-pixel-pec-d0";
0226   pixPecD0.extent.set(Acts::AxisDirection::AxisZ, 600., 640);
0227   Acts::ProtoVolume pixPecD1;
0228   pixPecD1.name = "odd-pixel-pec-d1";
0229   pixPecD1.extent.set(Acts::AxisDirection::AxisZ, 700., 740);
0230   Acts::ProtoVolume pixPecD2;
0231   pixPecD2.name = "odd-pixel-pec-d2";
0232   pixPecD2.extent.set(Acts::AxisDirection::AxisZ, 820., 860.);
0233   Acts::ProtoVolume pixPecD3;
0234   pixPecD3.name = "odd-pixel-pec-d3";
0235   pixPecD3.extent.set(Acts::AxisDirection::AxisZ, 960., 1000.);
0236   Acts::ProtoVolume pixPecD4;
0237   pixPecD4.name = "odd-pixel-pec-d4";
0238   pixPecD4.extent.set(Acts::AxisDirection::AxisZ, 1100., 1140);
0239   Acts::ProtoVolume pixPecD5;
0240   pixPecD5.name = "odd-pixel-pec-d5";
0241   pixPecD5.extent.set(Acts::AxisDirection::AxisZ, 1300., 1340.);
0242   Acts::ProtoVolume pixPecD6;
0243   pixPecD6.name = "odd-pixel-pec-d6";
0244   pixPecD6.extent.set(Acts::AxisDirection::AxisZ, 1500., 1540.);
0245 
0246   pixelPec.container = Acts::ProtoVolume::ContainerStructure{
0247       {pixPecD0, pixPecD1, pixPecD2, pixPecD3, pixPecD4, pixPecD5, pixPecD6},
0248       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisZ, {0., 1})},
0249       true};
0250 
0251   for (auto& cv : pixelPec.container.value().constituentVolumes) {
0252     cv.extent.setEnvelope(discLayerEnvelope);
0253     cv.internal = Acts::ProtoVolume::InternalStructure{
0254         Acts::Surface::SurfaceType::Disc, {pixEcBinningR, pixEcBinningPhi}};
0255   }
0256 
0257   pixelContainer.container = Acts::ProtoVolume::ContainerStructure{
0258       {pixelNec, pixelBarrel, pixelPec},
0259       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisZ,
0260                          {-3100., -580., 580., 3100.})}};
0261 
0262   // Short Strip section
0263   Acts::ProtoVolume pstContainer;
0264   pstContainer.name = "odd-pst";
0265   pstContainer.extent.set(Acts::AxisDirection::AxisR, 200., 210.);
0266   Acts::ProtoVolume pst;
0267   pst.name = "odd-pst-l";
0268   pst.extent.set(Acts::AxisDirection::AxisR, 201., 209.);
0269   pst.internal = Acts::ProtoVolume::InternalStructure{
0270       Acts::Surface::SurfaceType::Cylinder};
0271   pstContainer.container = Acts::ProtoVolume::ContainerStructure{
0272       {pst},
0273       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisR, {0., 1.})},
0274       true};
0275 
0276   // Short Strip section
0277   Acts::ProtoVolume sstripContainer;
0278   sstripContainer.name = "odd-sstrip";
0279   sstripContainer.extent.set(Acts::AxisDirection::AxisR, 210., 720);
0280 
0281   Acts::BinningData sstripEcBinningR =
0282       Acts::BinningData(Acts::open, Acts::AxisDirection::AxisR, 3., 0., 1.);
0283   Acts::BinningData sstripEcBinningPhi =
0284       Acts::BinningData(Acts::closed, Acts::AxisDirection::AxisPhi, 42.,
0285                         -std::numbers::pi, std::numbers::pi);
0286 
0287   Acts::ProtoVolume sstripNec;
0288   sstripNec.name = "odd-sstrip-nec";
0289   sstripNec.extent.set(Acts::AxisDirection::AxisZ, -3100., -1200);
0290   Acts::ProtoVolume sstripNecD5;
0291   sstripNecD5.name = "odd-sstrip-nec-d5";
0292   sstripNecD5.extent.set(Acts::AxisDirection::AxisZ, -3000, -2900.);
0293   Acts::ProtoVolume sstripNecD4;
0294   sstripNecD4.name = "odd-sstrip-nec-d4";
0295   sstripNecD4.extent.set(Acts::AxisDirection::AxisZ, -2600., -2500.);
0296   Acts::ProtoVolume sstripNecD3;
0297   sstripNecD3.name = "odd-sstrip-nec-d3";
0298   sstripNecD3.extent.set(Acts::AxisDirection::AxisZ, -2250, -2150.);
0299   Acts::ProtoVolume sstripNecD2;
0300   sstripNecD2.name = "odd-sstrip-nec-d2";
0301   sstripNecD2.extent.set(Acts::AxisDirection::AxisZ, -1900, -1800.);
0302   Acts::ProtoVolume sstripNecD1;
0303   sstripNecD1.name = "odd-sstrip-nec-d1";
0304   sstripNecD1.extent.set(Acts::AxisDirection::AxisZ, -1600., -1500.);
0305   Acts::ProtoVolume sstripNecD0;
0306   sstripNecD0.name = "odd-sstrip-nec-d0";
0307   sstripNecD0.extent.set(Acts::AxisDirection::AxisZ, -1350., -1250.);
0308 
0309   sstripNec.container = Acts::ProtoVolume::ContainerStructure{
0310       {sstripNecD5, sstripNecD4, sstripNecD3, sstripNecD2, sstripNecD1,
0311        sstripNecD0},
0312       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisZ, {0., 1})},
0313       true};
0314 
0315   for (auto& cv : sstripNec.container.value().constituentVolumes) {
0316     cv.extent.setEnvelope(discLayerEnvelope);
0317     cv.internal = Acts::ProtoVolume::InternalStructure{
0318         Acts::Surface::SurfaceType::Disc,
0319         {sstripEcBinningR, sstripEcBinningPhi}};
0320   }
0321 
0322   Acts::ProtoVolume sstripBarrel;
0323   sstripBarrel.name = "odd-sstrip-barrel";
0324   sstripBarrel.extent.set(Acts::AxisDirection::AxisZ, -1200., 1200);
0325 
0326   Acts::ProtoVolume sstripBarrelL0;
0327   sstripBarrelL0.name = "odd-sstrip-barrel-l0";
0328   sstripBarrelL0.extent.set(Acts::AxisDirection::AxisR, 240., 280.);
0329   Acts::ProtoVolume sstripBarrelL1;
0330   sstripBarrelL1.name = "odd-sstrip-barrel-l1";
0331   sstripBarrelL1.extent.set(Acts::AxisDirection::AxisR, 340., 380.);
0332   Acts::ProtoVolume sstripBarrelL2;
0333   sstripBarrelL2.name = "odd-sstrip-barrel-l2";
0334   sstripBarrelL2.extent.set(Acts::AxisDirection::AxisR, 480., 520.);
0335   Acts::ProtoVolume sstripBarrelL3;
0336   sstripBarrelL3.name = "odd-sstrip-barrel-l3";
0337   sstripBarrelL3.extent.set(Acts::AxisDirection::AxisR, 640., 680.);
0338 
0339   sstripBarrel.container = Acts::ProtoVolume::ContainerStructure{
0340       {sstripBarrelL0, sstripBarrelL1, sstripBarrelL2, sstripBarrelL3},
0341       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisR, {0., 1})},
0342       true};
0343 
0344   for (auto& cv : sstripBarrel.container.value().constituentVolumes) {
0345     cv.extent.setEnvelope(cylinderLayerEnvelope);
0346     cv.internal = Acts::ProtoVolume::InternalStructure{
0347         Acts::Surface::SurfaceType::Cylinder};
0348   }
0349 
0350   Acts::ProtoVolume sstripPec;
0351   sstripPec.name = "odd-sstrip-pec";
0352   sstripPec.extent.set(Acts::AxisDirection::AxisZ, 1200., 3100);
0353 
0354   Acts::ProtoVolume sstripPecD0;
0355   sstripPecD0.name = "odd-sstrip-pec-d0";
0356   sstripPecD0.extent.set(Acts::AxisDirection::AxisZ, 1250., 1350);
0357   Acts::ProtoVolume sstripPecD1;
0358   sstripPecD1.name = "odd-sstrip-pec-d1";
0359   sstripPecD1.extent.set(Acts::AxisDirection::AxisZ, 1500., 1600.);
0360   Acts::ProtoVolume sstripPecD2;
0361   sstripPecD2.name = "odd-sstrip-pec-d2";
0362   sstripPecD2.extent.set(Acts::AxisDirection::AxisZ, 1800., 1900.);
0363   Acts::ProtoVolume sstripPecD3;
0364   sstripPecD3.name = "odd-sstrip-pec-d3";
0365   sstripPecD3.extent.set(Acts::AxisDirection::AxisZ, 2150., 2250.);
0366   Acts::ProtoVolume sstripPecD4;
0367   sstripPecD4.name = "odd-sstrip-pec-d4";
0368   sstripPecD4.extent.set(Acts::AxisDirection::AxisZ, 2500., 2600.);
0369   Acts::ProtoVolume sstripPecD5;
0370   sstripPecD5.name = "odd-sstrip-pec-d5";
0371   sstripPecD5.extent.set(Acts::AxisDirection::AxisZ, 2900., 3000.);
0372 
0373   sstripPec.container = Acts::ProtoVolume::ContainerStructure{
0374       {sstripPecD0, sstripPecD1, sstripPecD2, sstripPecD3, sstripPecD4,
0375        sstripPecD5},
0376       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisZ, {0., 1})},
0377       true};
0378   for (auto& cv : sstripPec.container.value().constituentVolumes) {
0379     cv.extent.setEnvelope(discLayerEnvelope);
0380     cv.internal = Acts::ProtoVolume::InternalStructure{
0381         Acts::Surface::SurfaceType::Disc,
0382         {sstripEcBinningR, sstripEcBinningPhi}};
0383   }
0384 
0385   sstripContainer.container = Acts::ProtoVolume::ContainerStructure{
0386       {sstripNec, sstripBarrel, sstripPec},
0387       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisZ,
0388                          {-3100., -1200., 1200., 3100.})}};
0389 
0390   // Long Strip section
0391   Acts::ProtoVolume lstripContainer;
0392   lstripContainer.name = "odd-lstrip";
0393   lstripContainer.extent.set(Acts::AxisDirection::AxisR, 720, 1100.);
0394 
0395   Acts::ProtoVolume lstripNec;
0396   lstripNec.name = "odd-lstrip-nec";
0397   lstripNec.extent.set(Acts::AxisDirection::AxisZ, -3100., -1200);
0398   Acts::ProtoVolume lstripNecD5;
0399   lstripNecD5.name = "odd-lstrip-nec-d5";
0400   lstripNecD5.extent.set(Acts::AxisDirection::AxisZ, -3050, -2900.);
0401   Acts::ProtoVolume lstripNecD4;
0402   lstripNecD4.name = "odd-lstrip-nec-d4";
0403   lstripNecD4.extent.set(Acts::AxisDirection::AxisZ, -2650., -2500.);
0404   Acts::ProtoVolume lstripNecD3;
0405   lstripNecD3.name = "odd-lstrip-nec-d3";
0406   lstripNecD3.extent.set(Acts::AxisDirection::AxisZ, -2300, -2150.);
0407   Acts::ProtoVolume lstripNecD2;
0408   lstripNecD2.name = "odd-lstrip-nec-d2";
0409   lstripNecD2.extent.set(Acts::AxisDirection::AxisZ, -1950, -1800.);
0410   Acts::ProtoVolume lstripNecD1;
0411   lstripNecD1.name = "odd-lstrip-nec-d1";
0412   lstripNecD1.extent.set(Acts::AxisDirection::AxisZ, -1650., -1500.);
0413   Acts::ProtoVolume lstripNecD0;
0414   lstripNecD0.name = "odd-lstrip-nec-d0";
0415   lstripNecD0.extent.set(Acts::AxisDirection::AxisZ, -1400., -1250.);
0416 
0417   lstripNec.container = Acts::ProtoVolume::ContainerStructure{
0418       {lstripNecD5, lstripNecD4, lstripNecD3, lstripNecD2, lstripNecD1,
0419        lstripNecD0},
0420       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisZ, {0., 1})},
0421       true};
0422 
0423   for (auto& cv : lstripNec.container.value().constituentVolumes) {
0424     cv.extent.setEnvelope(discLayerEnvelope);
0425     cv.internal =
0426         Acts::ProtoVolume::InternalStructure{Acts::Surface::SurfaceType::Disc};
0427   }
0428 
0429   Acts::ProtoVolume lstripBarrel;
0430   lstripBarrel.name = "odd-lstrip-barrel";
0431   lstripBarrel.extent.set(Acts::AxisDirection::AxisZ, -1200., 1200);
0432 
0433   Acts::ProtoVolume lstripBarrelL0;
0434   lstripBarrelL0.name = "odd-lstrip-barrel-l0";
0435   lstripBarrelL0.extent.set(Acts::AxisDirection::AxisR, 800., 840.);
0436   Acts::ProtoVolume lstripBarrelL1;
0437   lstripBarrelL1.name = "odd-lstrip-barrel-l1";
0438   lstripBarrelL1.extent.set(Acts::AxisDirection::AxisR, 1000., 1050.);
0439 
0440   lstripBarrel.container = Acts::ProtoVolume::ContainerStructure{
0441       {lstripBarrelL0, lstripBarrelL1},
0442       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisR, {0., 1})},
0443       true};
0444 
0445   for (auto& cv : lstripBarrel.container.value().constituentVolumes) {
0446     cv.extent.setEnvelope(cylinderLayerEnvelope);
0447     cv.internal = Acts::ProtoVolume::InternalStructure{
0448         Acts::Surface::SurfaceType::Cylinder};
0449   }
0450 
0451   Acts::ProtoVolume lstripPec;
0452   lstripPec.name = "odd-lstrip-pec";
0453   lstripPec.extent.set(Acts::AxisDirection::AxisZ, 1200., 3100);
0454 
0455   Acts::ProtoVolume lstripPecD0;
0456   lstripPecD0.name = "odd-lstrip-pec-d0";
0457   lstripPecD0.extent.set(Acts::AxisDirection::AxisZ, 1250., 1400);
0458   Acts::ProtoVolume lstripPecD1;
0459   lstripPecD1.name = "odd-lstrip-pec-d1";
0460   lstripPecD1.extent.set(Acts::AxisDirection::AxisZ, 1500., 1650.);
0461   Acts::ProtoVolume lstripPecD2;
0462   lstripPecD2.name = "odd-lstrip-pec-d2";
0463   lstripPecD2.extent.set(Acts::AxisDirection::AxisZ, 1800., 1950.);
0464   Acts::ProtoVolume lstripPecD3;
0465   lstripPecD3.name = "odd-lstrip-pec-d3";
0466   lstripPecD3.extent.set(Acts::AxisDirection::AxisZ, 2150., 2300.);
0467   Acts::ProtoVolume lstripPecD4;
0468   lstripPecD4.name = "odd-lstrip-pec-d4";
0469   lstripPecD4.extent.set(Acts::AxisDirection::AxisZ, 2500., 2650.);
0470   Acts::ProtoVolume lstripPecD5;
0471   lstripPecD5.name = "odd-lstrip-pec-d5";
0472   lstripPecD5.extent.set(Acts::AxisDirection::AxisZ, 2900., 3050.);
0473 
0474   lstripPec.container = Acts::ProtoVolume::ContainerStructure{
0475       {lstripPecD0, lstripPecD1, lstripPecD2, lstripPecD3, lstripPecD4,
0476        lstripPecD5},
0477       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisZ, {0., 1})},
0478       true};
0479   for (auto& cv : lstripPec.container.value().constituentVolumes) {
0480     cv.internal =
0481         Acts::ProtoVolume::InternalStructure{Acts::Surface::SurfaceType::Disc};
0482     cv.extent.setEnvelope(discLayerEnvelope);
0483   }
0484   lstripContainer.container = Acts::ProtoVolume::ContainerStructure{
0485       {lstripNec, lstripBarrel, lstripPec},
0486       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisZ,
0487                          {-3100., -1200., 1200., 3100.})}};
0488 
0489   // The overall container
0490   Acts::ProtoVolume detectorContainer;
0491   detectorContainer.name = "odd-light-world";
0492   detectorContainer.extent.set(Acts::AxisDirection::AxisR, 0., 1100.);
0493   detectorContainer.extent.set(Acts::AxisDirection::AxisZ, -3100., 3100.);
0494   detectorContainer.container = Acts::ProtoVolume::ContainerStructure{
0495       {beamPipeContainer, pixelContainer, pstContainer, sstripContainer,
0496        lstripContainer},
0497       {Acts::BinningData(Acts::open, Acts::AxisDirection::AxisR,
0498                          {0., 25., 200., 210., 720., 1100.})}};
0499 
0500   // ----------------------------------------------------------
0501   Acts::ProtoDetector detector;
0502   detector.name = "odd-light";
0503   detector.worldVolume = detectorContainer;
0504 
0505   // Transform into json
0506   nlohmann::json jdet;
0507   jdet["detector"] = detector;
0508 
0509   std::ofstream out;
0510   out.open("odd-proto-detector.json");
0511   out << jdet.dump(4);
0512   out.close();
0513 
0514   Acts::ProtoDetector detectorIn = jdet["detector"];
0515 
0516   // Let's compare
0517   BOOST_CHECK_EQUAL(detector.name, detectorIn.name);
0518 
0519   const auto& world = detector.worldVolume;
0520   const auto& worldIn = detectorIn.worldVolume;
0521 
0522   BOOST_CHECK(isEqual(world, worldIn, 0.1));
0523 }
0524 
0525 BOOST_AUTO_TEST_SUITE_END()