Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-27 07:57:31

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/Surfaces/Surface.hpp"
0015 #include "Acts/Utilities/BinningData.hpp"
0016 #include "Acts/Utilities/BinningType.hpp"
0017 #include "Acts/Utilities/Enumerate.hpp"
0018 #include "ActsPlugins/Json/ProtoDetectorJsonConverter.hpp"
0019 #include "ActsPlugins/Json/SurfaceJsonConverter.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 ActsTests {
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 ProtoVolume& one, const 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] : 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] : 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] : 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 BOOST_AUTO_TEST_SUITE(JsonSuite)
0115 
0116 BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) {
0117   ExtentEnvelope cylinderLayerEnvelope = ExtentEnvelope::Zero();
0118   cylinderLayerEnvelope[AxisDirection::AxisR] = {1., 1.};
0119   cylinderLayerEnvelope[AxisDirection::AxisZ] = {2., 2.};
0120 
0121   ExtentEnvelope discLayerEnvelope = ExtentEnvelope::Zero();
0122   discLayerEnvelope[AxisDirection::AxisR] = {1., 1.};
0123   discLayerEnvelope[AxisDirection::AxisZ] = {1., 1.};
0124 
0125   // Beam Pipe container
0126   ProtoVolume beamPipeContainer;
0127   beamPipeContainer.name = "odd-beam-pipe";
0128   beamPipeContainer.extent.set(AxisDirection::AxisR, 0., 25);
0129   ProtoVolume beamPipe;
0130   beamPipe.name = "odd-beam-pipe-l";
0131   beamPipe.extent.set(AxisDirection::AxisR, 2., 24.);
0132   beamPipe.internal =
0133       ProtoVolume::InternalStructure{Surface::SurfaceType::Cylinder};
0134   beamPipeContainer.container = ProtoVolume::ContainerStructure{
0135       {beamPipe}, {BinningData(open, AxisDirection::AxisR, {0., 1.})}, true};
0136 
0137   // Pixel section
0138   ProtoVolume pixelContainer;
0139   pixelContainer.name = "odd-pixel";
0140   pixelContainer.extent.set(AxisDirection::AxisR, 25., 200);
0141 
0142   ProtoVolume pixelNec;
0143   pixelNec.name = "odd-pixel-nec";
0144   pixelNec.extent.set(AxisDirection::AxisZ, -3100., -580);
0145 
0146   ProtoVolume pixNecD6;
0147   pixNecD6.name = "odd-pixel-nec-d6";
0148   pixNecD6.extent.set(AxisDirection::AxisZ, -1540., -1500);
0149   ProtoVolume pixNecD5;
0150   pixNecD5.name = "odd-pixel-nec-d5";
0151   pixNecD5.extent.set(AxisDirection::AxisZ, -1340., -1300);
0152   ProtoVolume pixNecD4;
0153   pixNecD4.name = "odd-pixel-nec-d4";
0154   pixNecD4.extent.set(AxisDirection::AxisZ, -1140., -1100);
0155   ProtoVolume pixNecD3;
0156   pixNecD3.name = "odd-pixel-nec-d3";
0157   pixNecD3.extent.set(AxisDirection::AxisZ, -1000., -960.);
0158   ProtoVolume pixNecD2;
0159   pixNecD2.name = "odd-pixel-nec-d2";
0160   pixNecD2.extent.set(AxisDirection::AxisZ, -860., -820);
0161   ProtoVolume pixNecD1;
0162   pixNecD1.name = "odd-pixel-nec-d1";
0163   pixNecD1.extent.set(AxisDirection::AxisZ, -740., -700);
0164   ProtoVolume pixNecD0;
0165   pixNecD0.name = "odd-pixel-nec-d0";
0166   pixNecD0.extent.set(AxisDirection::AxisZ, -640., -600);
0167   pixelNec.container = ProtoVolume::ContainerStructure{
0168       {pixNecD6, pixNecD5, pixNecD4, pixNecD3, pixNecD2, pixNecD1, pixNecD0},
0169       {BinningData(open, AxisDirection::AxisZ, {0., 1.})},
0170       true};
0171 
0172   BinningData pixEcBinningR =
0173       BinningData(open, AxisDirection::AxisR, 2., 0., 1.);
0174   BinningData pixEcBinningPhi = BinningData(
0175       closed, AxisDirection::AxisPhi, 30., -std::numbers::pi, std::numbers::pi);
0176 
0177   for (auto& cv : pixelNec.container.value().constituentVolumes) {
0178     cv.extent.setEnvelope(discLayerEnvelope);
0179     cv.internal = ProtoVolume::InternalStructure{
0180         Surface::SurfaceType::Disc, {pixEcBinningR, pixEcBinningPhi}};
0181   }
0182 
0183   ProtoVolume pixelBarrel;
0184   pixelBarrel.name = "odd-pixel-barrel";
0185   pixelBarrel.extent.set(AxisDirection::AxisZ, -580., 580);
0186 
0187   ProtoVolume pixBarrelL0;
0188   pixBarrelL0.name = "odd-pixel-barrel-l0";
0189   pixBarrelL0.extent.set(AxisDirection::AxisR, 28., 48.);
0190   pixBarrelL0.extent.set(AxisDirection::AxisZ, -580., 580);
0191   ProtoVolume pixBarrelL1;
0192   pixBarrelL1.name = "odd-pixel-barrel-l1";
0193   pixBarrelL1.extent.set(AxisDirection::AxisR, 62., 76);
0194   pixBarrelL1.extent.set(AxisDirection::AxisZ, -580., 580);
0195   ProtoVolume pixBarrelL2;
0196   pixBarrelL2.name = "odd-pixel-barrel-l2";
0197   pixBarrelL2.extent.set(AxisDirection::AxisR, 100., 120.);
0198   pixBarrelL2.extent.set(AxisDirection::AxisZ, -580., 580);
0199   ProtoVolume pixBarrelL3;
0200   pixBarrelL3.name = "odd-pixel-barrel-l3";
0201   pixBarrelL3.extent.set(AxisDirection::AxisR, 160., 180.);
0202   pixBarrelL3.extent.set(AxisDirection::AxisZ, -580., 580);
0203 
0204   pixelBarrel.container = ProtoVolume::ContainerStructure{
0205       {pixBarrelL0, pixBarrelL1, pixBarrelL2, pixBarrelL3},
0206       {BinningData(open, AxisDirection::AxisR, {0., 1})},
0207       true};
0208 
0209   for (auto& cv : pixelBarrel.container.value().constituentVolumes) {
0210     cv.extent.setEnvelope(cylinderLayerEnvelope);
0211     cv.internal =
0212         ProtoVolume::InternalStructure{Surface::SurfaceType::Cylinder};
0213   }
0214 
0215   ProtoVolume pixelPec;
0216   pixelPec.name = "odd-pixel-pec";
0217   pixelPec.extent.set(AxisDirection::AxisZ, 580., 3100.);
0218 
0219   ProtoVolume pixPecD0;
0220   pixPecD0.name = "odd-pixel-pec-d0";
0221   pixPecD0.extent.set(AxisDirection::AxisZ, 600., 640);
0222   ProtoVolume pixPecD1;
0223   pixPecD1.name = "odd-pixel-pec-d1";
0224   pixPecD1.extent.set(AxisDirection::AxisZ, 700., 740);
0225   ProtoVolume pixPecD2;
0226   pixPecD2.name = "odd-pixel-pec-d2";
0227   pixPecD2.extent.set(AxisDirection::AxisZ, 820., 860.);
0228   ProtoVolume pixPecD3;
0229   pixPecD3.name = "odd-pixel-pec-d3";
0230   pixPecD3.extent.set(AxisDirection::AxisZ, 960., 1000.);
0231   ProtoVolume pixPecD4;
0232   pixPecD4.name = "odd-pixel-pec-d4";
0233   pixPecD4.extent.set(AxisDirection::AxisZ, 1100., 1140);
0234   ProtoVolume pixPecD5;
0235   pixPecD5.name = "odd-pixel-pec-d5";
0236   pixPecD5.extent.set(AxisDirection::AxisZ, 1300., 1340.);
0237   ProtoVolume pixPecD6;
0238   pixPecD6.name = "odd-pixel-pec-d6";
0239   pixPecD6.extent.set(AxisDirection::AxisZ, 1500., 1540.);
0240 
0241   pixelPec.container = ProtoVolume::ContainerStructure{
0242       {pixPecD0, pixPecD1, pixPecD2, pixPecD3, pixPecD4, pixPecD5, pixPecD6},
0243       {BinningData(open, AxisDirection::AxisZ, {0., 1})},
0244       true};
0245 
0246   for (auto& cv : pixelPec.container.value().constituentVolumes) {
0247     cv.extent.setEnvelope(discLayerEnvelope);
0248     cv.internal = ProtoVolume::InternalStructure{
0249         Surface::SurfaceType::Disc, {pixEcBinningR, pixEcBinningPhi}};
0250   }
0251 
0252   pixelContainer.container = ProtoVolume::ContainerStructure{
0253       {pixelNec, pixelBarrel, pixelPec},
0254       {BinningData(open, AxisDirection::AxisZ, {-3100., -580., 580., 3100.})}};
0255 
0256   // Short Strip section
0257   ProtoVolume pstContainer;
0258   pstContainer.name = "odd-pst";
0259   pstContainer.extent.set(AxisDirection::AxisR, 200., 210.);
0260   ProtoVolume pst;
0261   pst.name = "odd-pst-l";
0262   pst.extent.set(AxisDirection::AxisR, 201., 209.);
0263   pst.internal = ProtoVolume::InternalStructure{Surface::SurfaceType::Cylinder};
0264   pstContainer.container = ProtoVolume::ContainerStructure{
0265       {pst}, {BinningData(open, AxisDirection::AxisR, {0., 1.})}, true};
0266 
0267   // Short Strip section
0268   ProtoVolume sstripContainer;
0269   sstripContainer.name = "odd-sstrip";
0270   sstripContainer.extent.set(AxisDirection::AxisR, 210., 720);
0271 
0272   BinningData sstripEcBinningR =
0273       BinningData(open, AxisDirection::AxisR, 3., 0., 1.);
0274   BinningData sstripEcBinningPhi = BinningData(
0275       closed, AxisDirection::AxisPhi, 42., -std::numbers::pi, std::numbers::pi);
0276 
0277   ProtoVolume sstripNec;
0278   sstripNec.name = "odd-sstrip-nec";
0279   sstripNec.extent.set(AxisDirection::AxisZ, -3100., -1200);
0280   ProtoVolume sstripNecD5;
0281   sstripNecD5.name = "odd-sstrip-nec-d5";
0282   sstripNecD5.extent.set(AxisDirection::AxisZ, -3000, -2900.);
0283   ProtoVolume sstripNecD4;
0284   sstripNecD4.name = "odd-sstrip-nec-d4";
0285   sstripNecD4.extent.set(AxisDirection::AxisZ, -2600., -2500.);
0286   ProtoVolume sstripNecD3;
0287   sstripNecD3.name = "odd-sstrip-nec-d3";
0288   sstripNecD3.extent.set(AxisDirection::AxisZ, -2250, -2150.);
0289   ProtoVolume sstripNecD2;
0290   sstripNecD2.name = "odd-sstrip-nec-d2";
0291   sstripNecD2.extent.set(AxisDirection::AxisZ, -1900, -1800.);
0292   ProtoVolume sstripNecD1;
0293   sstripNecD1.name = "odd-sstrip-nec-d1";
0294   sstripNecD1.extent.set(AxisDirection::AxisZ, -1600., -1500.);
0295   ProtoVolume sstripNecD0;
0296   sstripNecD0.name = "odd-sstrip-nec-d0";
0297   sstripNecD0.extent.set(AxisDirection::AxisZ, -1350., -1250.);
0298 
0299   sstripNec.container = ProtoVolume::ContainerStructure{
0300       {sstripNecD5, sstripNecD4, sstripNecD3, sstripNecD2, sstripNecD1,
0301        sstripNecD0},
0302       {BinningData(open, AxisDirection::AxisZ, {0., 1})},
0303       true};
0304 
0305   for (auto& cv : sstripNec.container.value().constituentVolumes) {
0306     cv.extent.setEnvelope(discLayerEnvelope);
0307     cv.internal = ProtoVolume::InternalStructure{
0308         Surface::SurfaceType::Disc, {sstripEcBinningR, sstripEcBinningPhi}};
0309   }
0310 
0311   ProtoVolume sstripBarrel;
0312   sstripBarrel.name = "odd-sstrip-barrel";
0313   sstripBarrel.extent.set(AxisDirection::AxisZ, -1200., 1200);
0314 
0315   ProtoVolume sstripBarrelL0;
0316   sstripBarrelL0.name = "odd-sstrip-barrel-l0";
0317   sstripBarrelL0.extent.set(AxisDirection::AxisR, 240., 280.);
0318   ProtoVolume sstripBarrelL1;
0319   sstripBarrelL1.name = "odd-sstrip-barrel-l1";
0320   sstripBarrelL1.extent.set(AxisDirection::AxisR, 340., 380.);
0321   ProtoVolume sstripBarrelL2;
0322   sstripBarrelL2.name = "odd-sstrip-barrel-l2";
0323   sstripBarrelL2.extent.set(AxisDirection::AxisR, 480., 520.);
0324   ProtoVolume sstripBarrelL3;
0325   sstripBarrelL3.name = "odd-sstrip-barrel-l3";
0326   sstripBarrelL3.extent.set(AxisDirection::AxisR, 640., 680.);
0327 
0328   sstripBarrel.container = ProtoVolume::ContainerStructure{
0329       {sstripBarrelL0, sstripBarrelL1, sstripBarrelL2, sstripBarrelL3},
0330       {BinningData(open, AxisDirection::AxisR, {0., 1})},
0331       true};
0332 
0333   for (auto& cv : sstripBarrel.container.value().constituentVolumes) {
0334     cv.extent.setEnvelope(cylinderLayerEnvelope);
0335     cv.internal =
0336         ProtoVolume::InternalStructure{Surface::SurfaceType::Cylinder};
0337   }
0338 
0339   ProtoVolume sstripPec;
0340   sstripPec.name = "odd-sstrip-pec";
0341   sstripPec.extent.set(AxisDirection::AxisZ, 1200., 3100);
0342 
0343   ProtoVolume sstripPecD0;
0344   sstripPecD0.name = "odd-sstrip-pec-d0";
0345   sstripPecD0.extent.set(AxisDirection::AxisZ, 1250., 1350);
0346   ProtoVolume sstripPecD1;
0347   sstripPecD1.name = "odd-sstrip-pec-d1";
0348   sstripPecD1.extent.set(AxisDirection::AxisZ, 1500., 1600.);
0349   ProtoVolume sstripPecD2;
0350   sstripPecD2.name = "odd-sstrip-pec-d2";
0351   sstripPecD2.extent.set(AxisDirection::AxisZ, 1800., 1900.);
0352   ProtoVolume sstripPecD3;
0353   sstripPecD3.name = "odd-sstrip-pec-d3";
0354   sstripPecD3.extent.set(AxisDirection::AxisZ, 2150., 2250.);
0355   ProtoVolume sstripPecD4;
0356   sstripPecD4.name = "odd-sstrip-pec-d4";
0357   sstripPecD4.extent.set(AxisDirection::AxisZ, 2500., 2600.);
0358   ProtoVolume sstripPecD5;
0359   sstripPecD5.name = "odd-sstrip-pec-d5";
0360   sstripPecD5.extent.set(AxisDirection::AxisZ, 2900., 3000.);
0361 
0362   sstripPec.container = ProtoVolume::ContainerStructure{
0363       {sstripPecD0, sstripPecD1, sstripPecD2, sstripPecD3, sstripPecD4,
0364        sstripPecD5},
0365       {BinningData(open, AxisDirection::AxisZ, {0., 1})},
0366       true};
0367   for (auto& cv : sstripPec.container.value().constituentVolumes) {
0368     cv.extent.setEnvelope(discLayerEnvelope);
0369     cv.internal = ProtoVolume::InternalStructure{
0370         Surface::SurfaceType::Disc, {sstripEcBinningR, sstripEcBinningPhi}};
0371   }
0372 
0373   sstripContainer.container = ProtoVolume::ContainerStructure{
0374       {sstripNec, sstripBarrel, sstripPec},
0375       {BinningData(open, AxisDirection::AxisZ,
0376                    {-3100., -1200., 1200., 3100.})}};
0377 
0378   // Long Strip section
0379   ProtoVolume lstripContainer;
0380   lstripContainer.name = "odd-lstrip";
0381   lstripContainer.extent.set(AxisDirection::AxisR, 720, 1100.);
0382 
0383   ProtoVolume lstripNec;
0384   lstripNec.name = "odd-lstrip-nec";
0385   lstripNec.extent.set(AxisDirection::AxisZ, -3100., -1200);
0386   ProtoVolume lstripNecD5;
0387   lstripNecD5.name = "odd-lstrip-nec-d5";
0388   lstripNecD5.extent.set(AxisDirection::AxisZ, -3050, -2900.);
0389   ProtoVolume lstripNecD4;
0390   lstripNecD4.name = "odd-lstrip-nec-d4";
0391   lstripNecD4.extent.set(AxisDirection::AxisZ, -2650., -2500.);
0392   ProtoVolume lstripNecD3;
0393   lstripNecD3.name = "odd-lstrip-nec-d3";
0394   lstripNecD3.extent.set(AxisDirection::AxisZ, -2300, -2150.);
0395   ProtoVolume lstripNecD2;
0396   lstripNecD2.name = "odd-lstrip-nec-d2";
0397   lstripNecD2.extent.set(AxisDirection::AxisZ, -1950, -1800.);
0398   ProtoVolume lstripNecD1;
0399   lstripNecD1.name = "odd-lstrip-nec-d1";
0400   lstripNecD1.extent.set(AxisDirection::AxisZ, -1650., -1500.);
0401   ProtoVolume lstripNecD0;
0402   lstripNecD0.name = "odd-lstrip-nec-d0";
0403   lstripNecD0.extent.set(AxisDirection::AxisZ, -1400., -1250.);
0404 
0405   lstripNec.container = ProtoVolume::ContainerStructure{
0406       {lstripNecD5, lstripNecD4, lstripNecD3, lstripNecD2, lstripNecD1,
0407        lstripNecD0},
0408       {BinningData(open, AxisDirection::AxisZ, {0., 1})},
0409       true};
0410 
0411   for (auto& cv : lstripNec.container.value().constituentVolumes) {
0412     cv.extent.setEnvelope(discLayerEnvelope);
0413     cv.internal = ProtoVolume::InternalStructure{Surface::SurfaceType::Disc};
0414   }
0415 
0416   ProtoVolume lstripBarrel;
0417   lstripBarrel.name = "odd-lstrip-barrel";
0418   lstripBarrel.extent.set(AxisDirection::AxisZ, -1200., 1200);
0419 
0420   ProtoVolume lstripBarrelL0;
0421   lstripBarrelL0.name = "odd-lstrip-barrel-l0";
0422   lstripBarrelL0.extent.set(AxisDirection::AxisR, 800., 840.);
0423   ProtoVolume lstripBarrelL1;
0424   lstripBarrelL1.name = "odd-lstrip-barrel-l1";
0425   lstripBarrelL1.extent.set(AxisDirection::AxisR, 1000., 1050.);
0426 
0427   lstripBarrel.container = ProtoVolume::ContainerStructure{
0428       {lstripBarrelL0, lstripBarrelL1},
0429       {BinningData(open, AxisDirection::AxisR, {0., 1})},
0430       true};
0431 
0432   for (auto& cv : lstripBarrel.container.value().constituentVolumes) {
0433     cv.extent.setEnvelope(cylinderLayerEnvelope);
0434     cv.internal =
0435         ProtoVolume::InternalStructure{Surface::SurfaceType::Cylinder};
0436   }
0437 
0438   ProtoVolume lstripPec;
0439   lstripPec.name = "odd-lstrip-pec";
0440   lstripPec.extent.set(AxisDirection::AxisZ, 1200., 3100);
0441 
0442   ProtoVolume lstripPecD0;
0443   lstripPecD0.name = "odd-lstrip-pec-d0";
0444   lstripPecD0.extent.set(AxisDirection::AxisZ, 1250., 1400);
0445   ProtoVolume lstripPecD1;
0446   lstripPecD1.name = "odd-lstrip-pec-d1";
0447   lstripPecD1.extent.set(AxisDirection::AxisZ, 1500., 1650.);
0448   ProtoVolume lstripPecD2;
0449   lstripPecD2.name = "odd-lstrip-pec-d2";
0450   lstripPecD2.extent.set(AxisDirection::AxisZ, 1800., 1950.);
0451   ProtoVolume lstripPecD3;
0452   lstripPecD3.name = "odd-lstrip-pec-d3";
0453   lstripPecD3.extent.set(AxisDirection::AxisZ, 2150., 2300.);
0454   ProtoVolume lstripPecD4;
0455   lstripPecD4.name = "odd-lstrip-pec-d4";
0456   lstripPecD4.extent.set(AxisDirection::AxisZ, 2500., 2650.);
0457   ProtoVolume lstripPecD5;
0458   lstripPecD5.name = "odd-lstrip-pec-d5";
0459   lstripPecD5.extent.set(AxisDirection::AxisZ, 2900., 3050.);
0460 
0461   lstripPec.container = ProtoVolume::ContainerStructure{
0462       {lstripPecD0, lstripPecD1, lstripPecD2, lstripPecD3, lstripPecD4,
0463        lstripPecD5},
0464       {BinningData(open, AxisDirection::AxisZ, {0., 1})},
0465       true};
0466   for (auto& cv : lstripPec.container.value().constituentVolumes) {
0467     cv.internal = ProtoVolume::InternalStructure{Surface::SurfaceType::Disc};
0468     cv.extent.setEnvelope(discLayerEnvelope);
0469   }
0470   lstripContainer.container = ProtoVolume::ContainerStructure{
0471       {lstripNec, lstripBarrel, lstripPec},
0472       {BinningData(open, AxisDirection::AxisZ,
0473                    {-3100., -1200., 1200., 3100.})}};
0474 
0475   // The overall container
0476   ProtoVolume detectorContainer;
0477   detectorContainer.name = "odd-light-world";
0478   detectorContainer.extent.set(AxisDirection::AxisR, 0., 1100.);
0479   detectorContainer.extent.set(AxisDirection::AxisZ, -3100., 3100.);
0480   detectorContainer.container = ProtoVolume::ContainerStructure{
0481       {beamPipeContainer, pixelContainer, pstContainer, sstripContainer,
0482        lstripContainer},
0483       {BinningData(open, AxisDirection::AxisR,
0484                    {0., 25., 200., 210., 720., 1100.})}};
0485 
0486   // ----------------------------------------------------------
0487   ProtoDetector detector;
0488   detector.name = "odd-light";
0489   detector.worldVolume = detectorContainer;
0490 
0491   // Transform into json
0492   nlohmann::json jdet;
0493   jdet["detector"] = detector;
0494 
0495   std::ofstream out;
0496   out.open("odd-proto-detector.json");
0497   out << jdet.dump(4);
0498   out.close();
0499 
0500   ProtoDetector detectorIn = jdet["detector"];
0501 
0502   // Let's compare
0503   BOOST_CHECK_EQUAL(detector.name, detectorIn.name);
0504 
0505   const auto& world = detector.worldVolume;
0506   const auto& worldIn = detectorIn.worldVolume;
0507 
0508   BOOST_CHECK(isEqual(world, worldIn, 0.1));
0509 }
0510 
0511 BOOST_AUTO_TEST_SUITE_END()
0512 
0513 }  // namespace ActsTests