Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ProtoDetectorJsonConverterTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file ProtoDetectorJsonConverterTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2022 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include <boost/test/unit_test.hpp>
10 
13 #include "Acts/Geometry/Extent.hpp"
19 
20 #include <array>
21 #include <cmath>
22 #include <fstream>
23 #include <iterator>
24 #include <optional>
25 #include <string>
26 #include <vector>
27 
28 #include <nlohmann/json.hpp>
29 
30 #include "EqualityHelpers.hpp"
31 
32 using namespace Acts;
33 
34 namespace {
35 
41 bool isEqual(const Acts::ProtoVolume& one, const Acts::ProtoVolume& two,
42  const Acts::ActsScalar tolerance = 0.) {
43  bool nameEq = (one.name == two.name);
44  // Name
45  BOOST_CHECK(nameEq);
46  // Extent
47  bool extentEq = isEqual(one.extent, two.extent, tolerance);
48  BOOST_CHECK(extentEq);
49 
50  // Check internal structure
51  bool internalValueEq = (one.internal.has_value() == two.internal.has_value());
52  BOOST_CHECK(internalValueEq);
53  bool internalEq = internalValueEq;
54  if (one.internal.has_value() and two.internal.has_value()) {
55  // Check consistency of the internal structure
56  const auto& itsOne = one.internal.value();
57  const auto& itsTwo = two.internal.value();
58  bool layerTypeEq = (itsOne.layerType == itsTwo.layerType);
59  BOOST_CHECK(layerTypeEq);
60  internalEq = layerTypeEq;
61  bool sBinningSizeEq =
62  (itsOne.surfaceBinning.size() == itsTwo.surfaceBinning.size());
63  BOOST_CHECK(sBinningSizeEq);
64  internalEq = internalEq and sBinningSizeEq;
65  for (auto [isb, sb] : Acts::enumerate(itsOne.surfaceBinning)) {
66  bool sBinningEq = isEqual(sb, itsTwo.surfaceBinning[isb], tolerance);
67  BOOST_CHECK(sBinningEq);
68  internalEq = internalEq and sBinningEq;
69  }
70  }
71  BOOST_CHECK(internalEq);
72 
73  // Check container structure
74  bool containerValueEq =
75  (one.container.has_value() == two.container.has_value());
76  BOOST_CHECK(containerValueEq);
77  bool containerEq = containerValueEq;
78  if (one.container.has_value() and two.container.has_value()) {
79  // Check consistency of the container structure
80  const auto& ctsOne = one.container.value();
81  const auto& ctsTwo = two.container.value();
82  bool layerContainerEq = (ctsOne.layerContainer == ctsTwo.layerContainer);
83  BOOST_CHECK(layerContainerEq);
84  containerEq = layerContainerEq;
85  bool cBinningSizeEq =
86  ctsOne.constituentBinning.size() == ctsTwo.constituentBinning.size();
87  containerEq = containerEq and cBinningSizeEq;
88  BOOST_CHECK(cBinningSizeEq);
89  for (auto [icb, cb] : Acts::enumerate(ctsOne.constituentBinning)) {
90  bool cBinningEq = isEqual(cb, ctsTwo.constituentBinning[icb], tolerance);
91  BOOST_CHECK(cBinningEq);
92  containerEq = containerEq and cBinningEq;
93  }
94  // Recursively walk down
95  bool cSizeEq =
96  (ctsOne.constituentVolumes.size() == ctsTwo.constituentVolumes.size());
97  BOOST_CHECK(cSizeEq);
98  containerEq = cSizeEq;
99  for (auto [ic, cOne] : Acts::enumerate(ctsOne.constituentVolumes)) {
100  const auto& cTwo = ctsTwo.constituentVolumes[ic];
101  bool cEq = isEqual(cOne, cTwo, tolerance);
102  BOOST_CHECK(cEq);
103  containerEq = containerEq and cEq;
104  }
105  }
106  BOOST_CHECK(containerEq);
107 
108  // Give the overall judgement
109  return nameEq and extentEq and internalEq and containerEq;
110 }
111 
112 } // namespace
113 
114 BOOST_AUTO_TEST_SUITE(ProtoDetectorJsonConverter)
115 
116 BOOST_AUTO_TEST_CASE(ProtoDetectorRoundTrip) {
117  Acts::ExtentEnvelope cylinderLayerEnvelope = zeroEnvelopes;
118  cylinderLayerEnvelope[Acts::binR] = {1., 1.};
119  cylinderLayerEnvelope[Acts::binZ] = {2., 2.};
120 
121  Acts::ExtentEnvelope discLayerEnvelope = zeroEnvelopes;
122  discLayerEnvelope[Acts::binR] = {1., 1.};
123  discLayerEnvelope[Acts::binZ] = {1., 1.};
124 
125  // Beam Pipe container
126  Acts::ProtoVolume beamPipeContainer;
127  beamPipeContainer.name = "odd-beam-pipe";
128  beamPipeContainer.extent.set(Acts::binR, 0., 25);
129  Acts::ProtoVolume beamPipe;
130  beamPipe.name = "odd-beam-pipe-l";
131  beamPipe.extent.set(Acts::binR, 2., 24.);
133  Acts::Surface::SurfaceType::Cylinder};
135  {beamPipe}, {Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}, true};
136 
137  // Pixel section
138  Acts::ProtoVolume pixelContainer;
139  pixelContainer.name = "odd-pixel";
140  pixelContainer.extent.set(Acts::binR, 25., 200);
141 
142  Acts::ProtoVolume pixelNec;
143  pixelNec.name = "odd-pixel-nec";
144  pixelNec.extent.set(Acts::binZ, -3100., -580);
145 
146  Acts::ProtoVolume pixNecD6;
147  pixNecD6.name = "odd-pixel-nec-d6";
148  pixNecD6.extent.set(Acts::binZ, -1540., -1500);
149  Acts::ProtoVolume pixNecD5;
150  pixNecD5.name = "odd-pixel-nec-d5";
151  pixNecD5.extent.set(Acts::binZ, -1340., -1300);
152  Acts::ProtoVolume pixNecD4;
153  pixNecD4.name = "odd-pixel-nec-d4";
154  pixNecD4.extent.set(Acts::binZ, -1140., -1100);
155  Acts::ProtoVolume pixNecD3;
156  pixNecD3.name = "odd-pixel-nec-d3";
157  pixNecD3.extent.set(Acts::binZ, -1000., -960.);
158  Acts::ProtoVolume pixNecD2;
159  pixNecD2.name = "odd-pixel-nec-d2";
160  pixNecD2.extent.set(Acts::binZ, -860., -820);
161  Acts::ProtoVolume pixNecD1;
162  pixNecD1.name = "odd-pixel-nec-d1";
163  pixNecD1.extent.set(Acts::binZ, -740., -700);
164  Acts::ProtoVolume pixNecD0;
165  pixNecD0.name = "odd-pixel-nec-d0";
166  pixNecD0.extent.set(Acts::binZ, -640., -600);
168  {pixNecD6, pixNecD5, pixNecD4, pixNecD3, pixNecD2, pixNecD1, pixNecD0},
170  true};
171 
172  Acts::BinningData pixEcBinningR =
174  Acts::BinningData pixEcBinningPhi =
175  Acts::BinningData(Acts::closed, Acts::binPhi, 30., -M_PI, M_PI);
176 
177  for (auto& cv : pixelNec.container.value().constituentVolumes) {
178  cv.extent.setEnvelope(discLayerEnvelope);
180  Acts::Surface::SurfaceType::Disc, {pixEcBinningR, pixEcBinningPhi}};
181  }
182 
183  Acts::ProtoVolume pixelBarrel;
184  pixelBarrel.name = "odd-pixel-barrel";
185  pixelBarrel.extent.set(Acts::binZ, -580., 580);
186 
187  Acts::ProtoVolume pixBarrelL0;
188  pixBarrelL0.name = "odd-pixel-barrel-l0";
189  pixBarrelL0.extent.set(Acts::binR, 28., 48.);
190  pixBarrelL0.extent.set(Acts::binZ, -580., 580);
191  Acts::ProtoVolume pixBarrelL1;
192  pixBarrelL1.name = "odd-pixel-barrel-l1";
193  pixBarrelL1.extent.set(Acts::binR, 62., 76);
194  pixBarrelL1.extent.set(Acts::binZ, -580., 580);
195  Acts::ProtoVolume pixBarrelL2;
196  pixBarrelL2.name = "odd-pixel-barrel-l2";
197  pixBarrelL2.extent.set(Acts::binR, 100., 120.);
198  pixBarrelL2.extent.set(Acts::binZ, -580., 580);
199  Acts::ProtoVolume pixBarrelL3;
200  pixBarrelL3.name = "odd-pixel-barrel-l3";
201  pixBarrelL3.extent.set(Acts::binR, 160., 180.);
202  pixBarrelL3.extent.set(Acts::binZ, -580., 580);
203 
205  {pixBarrelL0, pixBarrelL1, pixBarrelL2, pixBarrelL3},
207  true};
208 
209  for (auto& cv : pixelBarrel.container.value().constituentVolumes) {
210  cv.extent.setEnvelope(cylinderLayerEnvelope);
212  Acts::Surface::SurfaceType::Cylinder};
213  }
214 
215  Acts::ProtoVolume pixelPec;
216  pixelPec.name = "odd-pixel-pec";
217  pixelPec.extent.set(Acts::binZ, 580., 3100.);
218 
219  Acts::ProtoVolume pixPecD0;
220  pixPecD0.name = "odd-pixel-pec-d0";
221  pixPecD0.extent.set(Acts::binZ, 600., 640);
222  Acts::ProtoVolume pixPecD1;
223  pixPecD1.name = "odd-pixel-pec-d1";
224  pixPecD1.extent.set(Acts::binZ, 700., 740);
225  Acts::ProtoVolume pixPecD2;
226  pixPecD2.name = "odd-pixel-pec-d2";
227  pixPecD2.extent.set(Acts::binZ, 820., 860.);
228  Acts::ProtoVolume pixPecD3;
229  pixPecD3.name = "odd-pixel-pec-d3";
230  pixPecD3.extent.set(Acts::binZ, 960., 1000.);
231  Acts::ProtoVolume pixPecD4;
232  pixPecD4.name = "odd-pixel-pec-d4";
233  pixPecD4.extent.set(Acts::binZ, 1100., 1140);
234  Acts::ProtoVolume pixPecD5;
235  pixPecD5.name = "odd-pixel-pec-d5";
236  pixPecD5.extent.set(Acts::binZ, 1300., 1340.);
237  Acts::ProtoVolume pixPecD6;
238  pixPecD6.name = "odd-pixel-pec-d6";
239  pixPecD6.extent.set(Acts::binZ, 1500., 1540.);
240 
242  {pixPecD0, pixPecD1, pixPecD2, pixPecD3, pixPecD4, pixPecD5, pixPecD6},
244  true};
245 
246  for (auto& cv : pixelPec.container.value().constituentVolumes) {
247  cv.extent.setEnvelope(discLayerEnvelope);
249  Acts::Surface::SurfaceType::Disc, {pixEcBinningR, pixEcBinningPhi}};
250  }
251 
252  pixelContainer.container = Acts::ProtoVolume::ContainerStructure{
253  {pixelNec, pixelBarrel, pixelPec},
255  {-3100., -580., 580., 3100.})}};
256 
257  // Short Strip section
258  Acts::ProtoVolume pstContainer;
259  pstContainer.name = "odd-pst";
260  pstContainer.extent.set(Acts::binR, 200., 210.);
261  Acts::ProtoVolume pst;
262  pst.name = "odd-pst-l";
263  pst.extent.set(Acts::binR, 201., 209.);
265  Acts::Surface::SurfaceType::Cylinder};
266  pstContainer.container = Acts::ProtoVolume::ContainerStructure{
267  {pst}, {Acts::BinningData(Acts::open, Acts::binR, {0., 1.})}, true};
268 
269  // Short Strip section
270  Acts::ProtoVolume sstripContainer;
271  sstripContainer.name = "odd-sstrip";
272  sstripContainer.extent.set(Acts::binR, 210., 720);
273 
274  Acts::BinningData sstripEcBinningR =
276  Acts::BinningData sstripEcBinningPhi =
277  Acts::BinningData(Acts::closed, Acts::binPhi, 42., -M_PI, M_PI);
278 
279  Acts::ProtoVolume sstripNec;
280  sstripNec.name = "odd-sstrip-nec";
281  sstripNec.extent.set(Acts::binZ, -3100., -1200);
282  Acts::ProtoVolume sstripNecD5;
283  sstripNecD5.name = "odd-sstrip-nec-d5";
284  sstripNecD5.extent.set(Acts::binZ, -3000, -2900.);
285  Acts::ProtoVolume sstripNecD4;
286  sstripNecD4.name = "odd-sstrip-nec-d4";
287  sstripNecD4.extent.set(Acts::binZ, -2600., -2500.);
288  Acts::ProtoVolume sstripNecD3;
289  sstripNecD3.name = "odd-sstrip-nec-d3";
290  sstripNecD3.extent.set(Acts::binZ, -2250, -2150.);
291  Acts::ProtoVolume sstripNecD2;
292  sstripNecD2.name = "odd-sstrip-nec-d2";
293  sstripNecD2.extent.set(Acts::binZ, -1900, -1800.);
294  Acts::ProtoVolume sstripNecD1;
295  sstripNecD1.name = "odd-sstrip-nec-d1";
296  sstripNecD1.extent.set(Acts::binZ, -1600., -1500.);
297  Acts::ProtoVolume sstripNecD0;
298  sstripNecD0.name = "odd-sstrip-nec-d0";
299  sstripNecD0.extent.set(Acts::binZ, -1350., -1250.);
300 
302  {sstripNecD5, sstripNecD4, sstripNecD3, sstripNecD2, sstripNecD1,
303  sstripNecD0},
305  true};
306 
307  for (auto& cv : sstripNec.container.value().constituentVolumes) {
308  cv.extent.setEnvelope(discLayerEnvelope);
310  Acts::Surface::SurfaceType::Disc,
311  {sstripEcBinningR, sstripEcBinningPhi}};
312  }
313 
314  Acts::ProtoVolume sstripBarrel;
315  sstripBarrel.name = "odd-sstrip-barrel";
316  sstripBarrel.extent.set(Acts::binZ, -1200., 1200);
317 
318  Acts::ProtoVolume sstripBarrelL0;
319  sstripBarrelL0.name = "odd-sstrip-barrel-l0";
320  sstripBarrelL0.extent.set(Acts::binR, 240., 280.);
321  Acts::ProtoVolume sstripBarrelL1;
322  sstripBarrelL1.name = "odd-sstrip-barrel-l1";
323  sstripBarrelL1.extent.set(Acts::binR, 340., 380.);
324  Acts::ProtoVolume sstripBarrelL2;
325  sstripBarrelL2.name = "odd-sstrip-barrel-l2";
326  sstripBarrelL2.extent.set(Acts::binR, 480., 520.);
327  Acts::ProtoVolume sstripBarrelL3;
328  sstripBarrelL3.name = "odd-sstrip-barrel-l3";
329  sstripBarrelL3.extent.set(Acts::binR, 640., 680.);
330 
332  {sstripBarrelL0, sstripBarrelL1, sstripBarrelL2, sstripBarrelL3},
334  true};
335 
336  for (auto& cv : sstripBarrel.container.value().constituentVolumes) {
337  cv.extent.setEnvelope(cylinderLayerEnvelope);
339  Acts::Surface::SurfaceType::Cylinder};
340  }
341 
342  Acts::ProtoVolume sstripPec;
343  sstripPec.name = "odd-sstrip-pec";
344  sstripPec.extent.set(Acts::binZ, 1200., 3100);
345 
346  Acts::ProtoVolume sstripPecD0;
347  sstripPecD0.name = "odd-sstrip-pec-d0";
348  sstripPecD0.extent.set(Acts::binZ, 1250., 1350);
349  Acts::ProtoVolume sstripPecD1;
350  sstripPecD1.name = "odd-sstrip-pec-d1";
351  sstripPecD1.extent.set(Acts::binZ, 1500., 1600.);
352  Acts::ProtoVolume sstripPecD2;
353  sstripPecD2.name = "odd-sstrip-pec-d2";
354  sstripPecD2.extent.set(Acts::binZ, 1800., 1900.);
355  Acts::ProtoVolume sstripPecD3;
356  sstripPecD3.name = "odd-sstrip-pec-d3";
357  sstripPecD3.extent.set(Acts::binZ, 2150., 2250.);
358  Acts::ProtoVolume sstripPecD4;
359  sstripPecD4.name = "odd-sstrip-pec-d4";
360  sstripPecD4.extent.set(Acts::binZ, 2500., 2600.);
361  Acts::ProtoVolume sstripPecD5;
362  sstripPecD5.name = "odd-sstrip-pec-d5";
363  sstripPecD5.extent.set(Acts::binZ, 2900., 3000.);
364 
366  {sstripPecD0, sstripPecD1, sstripPecD2, sstripPecD3, sstripPecD4,
367  sstripPecD5},
369  true};
370  for (auto& cv : sstripPec.container.value().constituentVolumes) {
371  cv.extent.setEnvelope(discLayerEnvelope);
373  Acts::Surface::SurfaceType::Disc,
374  {sstripEcBinningR, sstripEcBinningPhi}};
375  }
376 
377  sstripContainer.container = Acts::ProtoVolume::ContainerStructure{
378  {sstripNec, sstripBarrel, sstripPec},
380  {-3100., -1200., 1200., 3100.})}};
381 
382  // Long Strip section
383  Acts::ProtoVolume lstripContainer;
384  lstripContainer.name = "odd-lstrip";
385  lstripContainer.extent.set(Acts::binR, 720, 1100.);
386 
387  Acts::ProtoVolume lstripNec;
388  lstripNec.name = "odd-lstrip-nec";
389  lstripNec.extent.set(Acts::binZ, -3100., -1200);
390  Acts::ProtoVolume lstripNecD5;
391  lstripNecD5.name = "odd-lstrip-nec-d5";
392  lstripNecD5.extent.set(Acts::binZ, -3050, -2900.);
393  Acts::ProtoVolume lstripNecD4;
394  lstripNecD4.name = "odd-lstrip-nec-d4";
395  lstripNecD4.extent.set(Acts::binZ, -2650., -2500.);
396  Acts::ProtoVolume lstripNecD3;
397  lstripNecD3.name = "odd-lstrip-nec-d3";
398  lstripNecD3.extent.set(Acts::binZ, -2300, -2150.);
399  Acts::ProtoVolume lstripNecD2;
400  lstripNecD2.name = "odd-lstrip-nec-d2";
401  lstripNecD2.extent.set(Acts::binZ, -1950, -1800.);
402  Acts::ProtoVolume lstripNecD1;
403  lstripNecD1.name = "odd-lstrip-nec-d1";
404  lstripNecD1.extent.set(Acts::binZ, -1650., -1500.);
405  Acts::ProtoVolume lstripNecD0;
406  lstripNecD0.name = "odd-lstrip-nec-d0";
407  lstripNecD0.extent.set(Acts::binZ, -1400., -1250.);
408 
410  {lstripNecD5, lstripNecD4, lstripNecD3, lstripNecD2, lstripNecD1,
411  lstripNecD0},
413  true};
414 
415  for (auto& cv : lstripNec.container.value().constituentVolumes) {
416  cv.extent.setEnvelope(discLayerEnvelope);
417  cv.internal =
418  Acts::ProtoVolume::InternalStructure{Acts::Surface::SurfaceType::Disc};
419  }
420 
421  Acts::ProtoVolume lstripBarrel;
422  lstripBarrel.name = "odd-lstrip-barrel";
423  lstripBarrel.extent.set(Acts::binZ, -1200., 1200);
424 
425  Acts::ProtoVolume lstripBarrelL0;
426  lstripBarrelL0.name = "odd-lstrip-barrel-l0";
427  lstripBarrelL0.extent.set(Acts::binR, 800., 840.);
428  Acts::ProtoVolume lstripBarrelL1;
429  lstripBarrelL1.name = "odd-lstrip-barrel-l1";
430  lstripBarrelL1.extent.set(Acts::binR, 1000., 1050.);
431 
433  {lstripBarrelL0, lstripBarrelL1},
435  true};
436 
437  for (auto& cv : lstripBarrel.container.value().constituentVolumes) {
438  cv.extent.setEnvelope(cylinderLayerEnvelope);
440  Acts::Surface::SurfaceType::Cylinder};
441  }
442 
443  Acts::ProtoVolume lstripPec;
444  lstripPec.name = "odd-lstrip-pec";
445  lstripPec.extent.set(Acts::binZ, 1200., 3100);
446 
447  Acts::ProtoVolume lstripPecD0;
448  lstripPecD0.name = "odd-lstrip-pec-d0";
449  lstripPecD0.extent.set(Acts::binZ, 1250., 1400);
450  Acts::ProtoVolume lstripPecD1;
451  lstripPecD1.name = "odd-lstrip-pec-d1";
452  lstripPecD1.extent.set(Acts::binZ, 1500., 1650.);
453  Acts::ProtoVolume lstripPecD2;
454  lstripPecD2.name = "odd-lstrip-pec-d2";
455  lstripPecD2.extent.set(Acts::binZ, 1800., 1950.);
456  Acts::ProtoVolume lstripPecD3;
457  lstripPecD3.name = "odd-lstrip-pec-d3";
458  lstripPecD3.extent.set(Acts::binZ, 2150., 2300.);
459  Acts::ProtoVolume lstripPecD4;
460  lstripPecD4.name = "odd-lstrip-pec-d4";
461  lstripPecD4.extent.set(Acts::binZ, 2500., 2650.);
462  Acts::ProtoVolume lstripPecD5;
463  lstripPecD5.name = "odd-lstrip-pec-d5";
464  lstripPecD5.extent.set(Acts::binZ, 2900., 3050.);
465 
467  {lstripPecD0, lstripPecD1, lstripPecD2, lstripPecD3, lstripPecD4,
468  lstripPecD5},
470  true};
471  for (auto& cv : lstripPec.container.value().constituentVolumes) {
472  cv.internal =
473  Acts::ProtoVolume::InternalStructure{Acts::Surface::SurfaceType::Disc};
474  cv.extent.setEnvelope(discLayerEnvelope);
475  }
476  lstripContainer.container = Acts::ProtoVolume::ContainerStructure{
477  {lstripNec, lstripBarrel, lstripPec},
479  {-3100., -1200., 1200., 3100.})}};
480 
481  // The overall container
482  Acts::ProtoVolume detectorContainer;
483  detectorContainer.name = "odd-light-world";
484  detectorContainer.extent.set(Acts::binR, 0., 1100.);
485  detectorContainer.extent.set(Acts::binZ, -3100., 3100.);
486  detectorContainer.container = Acts::ProtoVolume::ContainerStructure{
487  {beamPipeContainer, pixelContainer, pstContainer, sstripContainer,
488  lstripContainer},
490  {0., 25., 200., 210., 720., 1100.})}};
491 
492  // ----------------------------------------------------------
494  detector.name = "odd-light";
495  detector.worldVolume = detectorContainer;
496 
497  // Transform into json
498  nlohmann::json jdet;
499  jdet["detector"] = detector;
500 
501  std::ofstream out;
502  out.open("odd-proto-detector.json");
503  out << jdet.dump(4);
504  out.close();
505 
506  Acts::ProtoDetector detectorIn = jdet["detector"];
507 
508  // Let's compare
509  BOOST_CHECK(detector.name == detectorIn.name);
510 
511  const auto& world = detector.worldVolume;
512  const auto& worldIn = detectorIn.worldVolume;
513 
514  BOOST_CHECK(isEqual(world, worldIn, 0.1));
515 }
516 
517 BOOST_AUTO_TEST_SUITE_END()