File indexing completed on 2026-08-25 08:19:28
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/tools/old/interface.hpp>
0010 #include <boost/test/unit_test.hpp>
0011
0012 #include "Acts/Definitions/Algebra.hpp"
0013 #include "Acts/Geometry/CylinderLayer.hpp"
0014 #include "Acts/Geometry/DiscLayer.hpp"
0015 #include "Acts/Geometry/Extent.hpp"
0016 #include "Acts/Geometry/GeometryContext.hpp"
0017 #include "Acts/Geometry/LayerCreator.hpp"
0018 #include "Acts/Geometry/ProtoLayer.hpp"
0019 #include "Acts/Geometry/SurfaceArrayCreator.hpp"
0020 #include "Acts/Surfaces/CylinderBounds.hpp"
0021 #include "Acts/Surfaces/PlanarBounds.hpp"
0022 #include "Acts/Surfaces/PlaneSurface.hpp"
0023 #include "Acts/Surfaces/RadialBounds.hpp"
0024 #include "Acts/Surfaces/RectangleBounds.hpp"
0025 #include "Acts/Surfaces/Surface.hpp"
0026 #include "Acts/Surfaces/SurfaceArray.hpp"
0027 #include "Acts/Utilities/BinningType.hpp"
0028 #include "Acts/Utilities/IAxis.hpp"
0029 #include "Acts/Utilities/Logger.hpp"
0030 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0031
0032 #include <cstddef>
0033 #include <fstream>
0034 #include <iomanip>
0035 #include <iostream>
0036 #include <memory>
0037 #include <numbers>
0038 #include <set>
0039 #include <string>
0040 #include <utility>
0041 #include <vector>
0042
0043 #include <boost/format.hpp>
0044
0045 using namespace Acts;
0046
0047 namespace ActsTests {
0048
0049
0050 GeometryContext tgContext = GeometryContext::dangerouslyDefaultConstruct();
0051
0052 using SrfVec = std::vector<std::shared_ptr<const Surface>>;
0053
0054 void draw_surfaces(const SrfVec& surfaces, const std::string& fname) {
0055 std::ofstream os;
0056 os.open(fname);
0057
0058 os << std::fixed << std::setprecision(4);
0059
0060 std::size_t nVtx = 0;
0061 for (const auto& srfx : surfaces) {
0062 std::shared_ptr<const PlaneSurface> srf =
0063 std::dynamic_pointer_cast<const PlaneSurface>(srfx);
0064 const PlanarBounds* bounds =
0065 dynamic_cast<const PlanarBounds*>(&srf->bounds());
0066
0067 for (const auto& vtxloc : bounds->vertices()) {
0068 Vector3 vtx = srf->localToGlobalTransform(tgContext) *
0069 Vector3(vtxloc.x(), vtxloc.y(), 0);
0070 os << "v " << vtx.x() << " " << vtx.y() << " " << vtx.z() << "\n";
0071 }
0072
0073
0074 os << "f";
0075 for (std::size_t i = 1; i <= bounds->vertices().size(); ++i) {
0076 os << " " << nVtx + i;
0077 }
0078 os << "\n";
0079
0080 nVtx += bounds->vertices().size();
0081 }
0082
0083 os.close();
0084 }
0085
0086 struct LayerCreatorFixture {
0087 std::shared_ptr<const SurfaceArrayCreator> p_SAC;
0088 std::shared_ptr<LayerCreator> p_LC;
0089
0090 std::vector<std::shared_ptr<const Surface>> m_surfaces;
0091
0092 LayerCreatorFixture() {
0093 p_SAC = std::make_shared<const SurfaceArrayCreator>(
0094 SurfaceArrayCreator::Config(),
0095 getDefaultLogger("SurfaceArrayCreator", Logging::VERBOSE));
0096 LayerCreator::Config cfg;
0097 cfg.surfaceArrayCreator = p_SAC;
0098 p_LC = std::make_shared<LayerCreator>(
0099 cfg, getDefaultLogger("LayerCreator", Logging::VERBOSE));
0100 }
0101
0102 bool checkBinContentSize(const SurfaceArray* sArray, std::size_t n) {
0103 std::size_t nBins = sArray->size();
0104 bool result = true;
0105 for (std::size_t i = 0; i < nBins; ++i) {
0106 if (!sArray->isValidBin(i)) {
0107 continue;
0108 }
0109 const std::span<const Surface* const> binContent = sArray->at(i);
0110 BOOST_TEST_INFO("Bin: " << i);
0111 BOOST_CHECK_EQUAL(binContent.size(), n);
0112 result = result && binContent.size() == n;
0113 }
0114
0115 return result;
0116 }
0117
0118 SrfVec fullPhiTestSurfacesEC(std::size_t n = 10, double shift = 0,
0119 double zbase = 0, double r = 10) {
0120 SrfVec res;
0121
0122 double phiStep = 2 * std::numbers::pi / n;
0123 for (std::size_t i = 0; i < n; ++i) {
0124 double z = zbase + ((i % 2 == 0) ? 1 : -1) * 0.2;
0125
0126 Transform3 trans;
0127 trans.setIdentity();
0128 trans.rotate(Eigen::AngleAxisd(i * phiStep + shift, Vector3(0, 0, 1)));
0129 trans.translate(Vector3(r, 0, z));
0130
0131 auto bounds = std::make_shared<const RectangleBounds>(2, 1);
0132 std::shared_ptr<PlaneSurface> srf =
0133 Surface::makeShared<PlaneSurface>(trans, bounds);
0134
0135 res.push_back(srf);
0136 m_surfaces.push_back(
0137 std::move(srf));
0138 }
0139
0140 return res;
0141 }
0142
0143 SrfVec fullPhiTestSurfacesBRL(int n = 10, double shift = 0, double zbase = 0,
0144 double incl = std::numbers::pi / 9.,
0145 double w = 2, double h = 1.5) {
0146 SrfVec res;
0147
0148 double phiStep = 2 * std::numbers::pi / n;
0149 for (int i = 0; i < n; ++i) {
0150 double z = zbase;
0151
0152 Transform3 trans;
0153 trans.setIdentity();
0154 trans.rotate(Eigen::AngleAxisd(i * phiStep + shift, Vector3(0, 0, 1)));
0155 trans.translate(Vector3(10, 0, z));
0156 trans.rotate(Eigen::AngleAxisd(incl, Vector3(0, 0, 1)));
0157 trans.rotate(Eigen::AngleAxisd(std::numbers::pi / 2., Vector3(0, 1, 0)));
0158
0159 auto bounds = std::make_shared<const RectangleBounds>(w, h);
0160 std::shared_ptr<PlaneSurface> srf =
0161 Surface::makeShared<PlaneSurface>(trans, bounds);
0162
0163 res.push_back(srf);
0164 m_surfaces.push_back(
0165 std::move(srf));
0166 }
0167
0168 return res;
0169 }
0170
0171 SrfVec makeBarrel(int nPhi, int nZ, double w, double h) {
0172 double z0 = -(nZ - 1) * w;
0173 SrfVec res;
0174
0175 for (int i = 0; i < nZ; i++) {
0176 double z = i * w * 2 + z0;
0177 std::cout << "z=" << z << std::endl;
0178 SrfVec ring =
0179 fullPhiTestSurfacesBRL(nPhi, 0, z, std::numbers::pi / 9., w, h);
0180 res.insert(res.end(), ring.begin(), ring.end());
0181 }
0182
0183 return res;
0184 }
0185
0186 std::pair<SrfVec, std::vector<std::pair<const Surface*, const Surface*>>>
0187 makeBarrelStagger(int nPhi, int nZ, double shift = 0,
0188 double incl = std::numbers::pi / 9., double w = 2,
0189 double h = 1.5) {
0190 double z0 = -(nZ - 1) * w;
0191 SrfVec res;
0192
0193 std::vector<std::pair<const Surface*, const Surface*>> pairs;
0194
0195 for (int i = 0; i < nZ; i++) {
0196 double z = i * w * 2 + z0;
0197
0198 double phiStep = 2 * std::numbers::pi / nPhi;
0199 for (int j = 0; j < nPhi; ++j) {
0200 Transform3 trans;
0201 trans.setIdentity();
0202 trans.rotate(Eigen::AngleAxisd(j * phiStep + shift, Vector3(0, 0, 1)));
0203 trans.translate(Vector3(10, 0, z));
0204 trans.rotate(Eigen::AngleAxisd(incl, Vector3(0, 0, 1)));
0205 trans.rotate(
0206 Eigen::AngleAxisd(std::numbers::pi / 2., Vector3(0, 1, 0)));
0207
0208 auto bounds = std::make_shared<const RectangleBounds>(w, h);
0209 std::shared_ptr<PlaneSurface> srfA =
0210 Surface::makeShared<PlaneSurface>(trans, bounds);
0211
0212 Vector3 nrm = srfA->normal(tgContext);
0213 Transform3 transB = trans;
0214 transB.pretranslate(nrm * 0.1);
0215 std::shared_ptr<PlaneSurface> srfB =
0216 Surface::makeShared<PlaneSurface>(transB, bounds);
0217
0218 pairs.push_back(std::make_pair(srfA.get(), srfB.get()));
0219
0220 res.push_back(srfA);
0221 res.push_back(srfB);
0222 m_surfaces.push_back(std::move(srfA));
0223 m_surfaces.push_back(std::move(srfB));
0224 }
0225 }
0226
0227 return {res, pairs};
0228 }
0229 };
0230
0231 BOOST_AUTO_TEST_SUITE(GeometrySuite)
0232
0233 BOOST_FIXTURE_TEST_CASE(LayerCreator_createCylinderLayer, LayerCreatorFixture) {
0234 std::vector<std::shared_ptr<const Surface>> srf;
0235
0236 srf = makeBarrel(30, 7, 2, 1.5);
0237 draw_surfaces(srf, "LayerCreator_createCylinderLayer_BRL_1.obj");
0238
0239
0240 double envR = 0.1, envZ = 0.5;
0241 ProtoLayer pl(tgContext, srf);
0242 pl.envelope[AxisDirection::AxisR] = {envR, envR};
0243 pl.envelope[AxisDirection::AxisZ] = {envZ, envZ};
0244 std::shared_ptr<CylinderLayer> layer =
0245 std::dynamic_pointer_cast<CylinderLayer>(
0246 p_LC->cylinderLayer(tgContext, srf, equidistant, equidistant, pl));
0247
0248
0249 double rMax = 10.6071, rMin = 9.59111;
0250 CHECK_CLOSE_REL(layer->layerThickness(), (rMax - rMin) + 2. * envR, 1e-3);
0251
0252 const CylinderBounds* bounds = &layer->bounds();
0253 CHECK_CLOSE_REL(bounds->get(CylinderBounds::eR), (rMax + rMin) / 2., 1e-3);
0254 CHECK_CLOSE_REL(bounds->get(CylinderBounds::eHalfLengthZ), 14 + envZ, 1e-3);
0255 auto axes = layer->surfaceArray()->getAxes();
0256 BOOST_CHECK_EQUAL(axes.at(0)->getNBins(), 30u);
0257 BOOST_CHECK_EQUAL(axes.at(1)->getNBins(), 7u);
0258 CHECK_CLOSE_REL(axes.at(0)->getMin(), -std::numbers::pi, 1e-3);
0259 CHECK_CLOSE_REL(axes.at(0)->getMax(), std::numbers::pi, 1e-3);
0260 CHECK_CLOSE_REL(axes.at(1)->getMin(), -14, 1e-3);
0261 CHECK_CLOSE_REL(axes.at(1)->getMax(), 14, 1e-3);
0262
0263
0264
0265 ProtoLayer pl2(tgContext, srf);
0266 pl2.envelope[AxisDirection::AxisR] = {envR, envR};
0267 pl2.envelope[AxisDirection::AxisZ] = {envZ, envZ};
0268 layer = std::dynamic_pointer_cast<CylinderLayer>(
0269 p_LC->cylinderLayer(tgContext, srf, 30, 7, pl2));
0270 CHECK_CLOSE_REL(layer->layerThickness(), (rMax - rMin) + 2 * envR, 1e-3);
0271 bounds = &layer->bounds();
0272 CHECK_CLOSE_REL(bounds->get(CylinderBounds::eR), (rMax + rMin) / 2., 1e-3);
0273 CHECK_CLOSE_REL(bounds->get(CylinderBounds::eHalfLengthZ), 14 + envZ, 1e-3);
0274 axes = layer->surfaceArray()->getAxes();
0275 BOOST_CHECK_EQUAL(axes.at(0)->getNBins(), 30u);
0276 BOOST_CHECK_EQUAL(axes.at(1)->getNBins(), 7u);
0277 CHECK_CLOSE_REL(axes.at(0)->getMin(), -std::numbers::pi, 1e-3);
0278 CHECK_CLOSE_REL(axes.at(0)->getMax(), std::numbers::pi, 1e-3);
0279 CHECK_CLOSE_REL(axes.at(1)->getMin(), -14, 1e-3);
0280 CHECK_CLOSE_REL(axes.at(1)->getMax(), 14, 1e-3);
0281
0282 layer = std::dynamic_pointer_cast<CylinderLayer>(
0283 p_LC->cylinderLayer(tgContext, srf, 13, 3, pl2));
0284 CHECK_CLOSE_REL(layer->layerThickness(), (rMax - rMin) + 2 * envR, 1e-3);
0285 bounds = &layer->bounds();
0286 CHECK_CLOSE_REL(bounds->get(CylinderBounds::eR), (rMax + rMin) / 2., 1e-3);
0287 CHECK_CLOSE_REL(bounds->get(CylinderBounds::eHalfLengthZ), 14 + envZ, 1e-3);
0288 axes = layer->surfaceArray()->getAxes();
0289 BOOST_CHECK_EQUAL(axes.at(0)->getNBins(), 13u);
0290 BOOST_CHECK_EQUAL(axes.at(1)->getNBins(), 3u);
0291 CHECK_CLOSE_REL(axes.at(0)->getMin(), -std::numbers::pi, 1e-3);
0292 CHECK_CLOSE_REL(axes.at(0)->getMax(), std::numbers::pi, 1e-3);
0293 CHECK_CLOSE_REL(axes.at(1)->getMin(), -14, 1e-3);
0294 CHECK_CLOSE_REL(axes.at(1)->getMax(), 14, 1e-3);
0295
0296
0297 ProtoLayer pl3;
0298 pl3.extent.range(AxisDirection::AxisR).set(1, 20);
0299 pl3.extent.range(AxisDirection::AxisZ).set(-25, 25);
0300 layer = std::dynamic_pointer_cast<CylinderLayer>(
0301 p_LC->cylinderLayer(tgContext, srf, equidistant, equidistant, pl3));
0302 CHECK_CLOSE_REL(layer->layerThickness(), 19, 1e-3);
0303 bounds = &layer->bounds();
0304 CHECK_CLOSE_REL(bounds->get(CylinderBounds::eR), 10.5, 1e-3);
0305 CHECK_CLOSE_REL(bounds->get(CylinderBounds::eHalfLengthZ), 25, 1e-3);
0306
0307 axes = layer->surfaceArray()->getAxes();
0308 BOOST_CHECK_EQUAL(axes.at(0)->getNBins(), 30u);
0309 BOOST_CHECK_EQUAL(axes.at(1)->getNBins(), 7u);
0310 CHECK_CLOSE_REL(axes.at(0)->getMin(), -std::numbers::pi, 1e-3);
0311 CHECK_CLOSE_REL(axes.at(0)->getMax(), std::numbers::pi, 1e-3);
0312 CHECK_CLOSE_REL(axes.at(1)->getMin(), -25, 1e-3);
0313 CHECK_CLOSE_REL(axes.at(1)->getMax(), 25, 1e-3);
0314 }
0315
0316 BOOST_FIXTURE_TEST_CASE(LayerCreator_createDiscLayer, LayerCreatorFixture) {
0317 std::vector<std::shared_ptr<const Surface>> surfaces;
0318 auto ringa = fullPhiTestSurfacesEC(30, 0, 0, 10);
0319 surfaces.insert(surfaces.end(), ringa.begin(), ringa.end());
0320 auto ringb = fullPhiTestSurfacesEC(30, 0, 0, 15);
0321 surfaces.insert(surfaces.end(), ringb.begin(), ringb.end());
0322 auto ringc = fullPhiTestSurfacesEC(30, 0, 0, 20);
0323 surfaces.insert(surfaces.end(), ringc.begin(), ringc.end());
0324 draw_surfaces(surfaces, "LayerCreator_createDiscLayer_EC_1.obj");
0325
0326 ProtoLayer pl(tgContext, surfaces);
0327 pl.extent.range(AxisDirection::AxisZ).set(-10, 10);
0328 pl.extent.range(AxisDirection::AxisR).set(5., 25.);
0329 std::shared_ptr<DiscLayer> layer = std::dynamic_pointer_cast<DiscLayer>(
0330 p_LC->discLayer(tgContext, surfaces, equidistant, equidistant, pl));
0331 CHECK_CLOSE_REL(layer->layerThickness(), 20, 1e-3);
0332 const RadialBounds* bounds =
0333 dynamic_cast<const RadialBounds*>(&layer->bounds());
0334 CHECK_CLOSE_REL(bounds->rMin(), 5, 1e-3);
0335 CHECK_CLOSE_REL(bounds->rMax(), 25, 1e-3);
0336 auto axes = layer->surfaceArray()->getAxes();
0337 BOOST_CHECK_EQUAL(axes.at(0)->getNBins(), 3u);
0338 BOOST_CHECK_EQUAL(axes.at(1)->getNBins(), 30u);
0339 CHECK_CLOSE_REL(axes.at(0)->getMin(), 5, 1e-3);
0340 CHECK_CLOSE_REL(axes.at(0)->getMax(), 25, 1e-3);
0341 CHECK_CLOSE_REL(axes.at(1)->getMin(), -std::numbers::pi, 1e-3);
0342 CHECK_CLOSE_REL(axes.at(1)->getMax(), std::numbers::pi, 1e-3);
0343 checkBinContentSize(layer->surfaceArray(), 1);
0344
0345
0346
0347
0348
0349
0350
0351 double envMinR = 1, envMaxR = 1, envZ = 5;
0352 std::size_t nBinsR = 3, nBinsPhi = 30;
0353 ProtoLayer pl2(tgContext, surfaces);
0354 pl2.envelope[AxisDirection::AxisR] = {envMinR, envMaxR};
0355 pl2.envelope[AxisDirection::AxisZ] = {envZ, envZ};
0356 layer = std::dynamic_pointer_cast<DiscLayer>(
0357 p_LC->discLayer(tgContext, surfaces, nBinsR, nBinsPhi, pl2));
0358
0359 double rMin = 8, rMax = 22.0227;
0360 CHECK_CLOSE_REL(layer->layerThickness(), 0.4 + 2 * envZ, 1e-3);
0361 bounds = dynamic_cast<const RadialBounds*>(&layer->bounds());
0362 CHECK_CLOSE_REL(bounds->rMin(), rMin - envMinR, 1e-3);
0363 CHECK_CLOSE_REL(bounds->rMax(), rMax + envMaxR, 1e-3);
0364 axes = layer->surfaceArray()->getAxes();
0365 BOOST_CHECK_EQUAL(axes.at(0)->getNBins(), nBinsR);
0366 BOOST_CHECK_EQUAL(axes.at(1)->getNBins(), nBinsPhi);
0367 CHECK_CLOSE_REL(axes.at(0)->getMin(), rMin, 1e-3);
0368 CHECK_CLOSE_REL(axes.at(0)->getMax(), rMax, 1e-3);
0369 CHECK_CLOSE_REL(axes.at(1)->getMin(), -std::numbers::pi, 1e-3);
0370 CHECK_CLOSE_REL(axes.at(1)->getMax(), std::numbers::pi, 1e-3);
0371 checkBinContentSize(layer->surfaceArray(), 1);
0372
0373
0374
0375
0376
0377
0378
0379 layer = std::dynamic_pointer_cast<DiscLayer>(
0380 p_LC->discLayer(tgContext, surfaces, equidistant, equidistant, pl2));
0381 CHECK_CLOSE_REL(layer->layerThickness(), 0.4 + 2 * envZ, 1e-3);
0382 bounds = dynamic_cast<const RadialBounds*>(&layer->bounds());
0383 CHECK_CLOSE_REL(bounds->rMin(), rMin - envMinR, 1e-3);
0384 CHECK_CLOSE_REL(bounds->rMax(), rMax + envMaxR, 1e-3);
0385 axes = layer->surfaceArray()->getAxes();
0386 BOOST_CHECK_EQUAL(axes.at(0)->getNBins(), nBinsR);
0387 BOOST_CHECK_EQUAL(axes.at(1)->getNBins(), nBinsPhi);
0388 CHECK_CLOSE_REL(axes.at(0)->getMin(), rMin, 1e-3);
0389 CHECK_CLOSE_REL(axes.at(0)->getMax(), rMax, 1e-3);
0390 CHECK_CLOSE_REL(axes.at(1)->getMin(), -std::numbers::pi, 1e-3);
0391 CHECK_CLOSE_REL(axes.at(1)->getMax(), std::numbers::pi, 1e-3);
0392 checkBinContentSize(layer->surfaceArray(), 1);
0393
0394
0395
0396
0397
0398
0399 }
0400
0401 BOOST_FIXTURE_TEST_CASE(LayerCreator_barrelStagger, LayerCreatorFixture) {
0402 auto barrel = makeBarrelStagger(30, 7, 0, std::numbers::pi / 9.);
0403 auto brl = barrel.first;
0404 draw_surfaces(brl, "LayerCreator_barrelStagger.obj");
0405
0406 double envR = 0, envZ = 0;
0407 ProtoLayer pl(tgContext, brl);
0408 pl.envelope[AxisDirection::AxisR] = {envR, envR};
0409 pl.envelope[AxisDirection::AxisZ] = {envZ, envZ};
0410 std::shared_ptr<CylinderLayer> layer =
0411 std::dynamic_pointer_cast<CylinderLayer>(
0412 p_LC->cylinderLayer(tgContext, brl, equidistant, equidistant, pl));
0413
0414 auto axes = layer->surfaceArray()->getAxes();
0415 BOOST_CHECK_EQUAL(axes.at(0)->getNBins(), 30u);
0416 BOOST_CHECK_EQUAL(axes.at(1)->getNBins(), 7u);
0417
0418
0419 for (const auto& pr : barrel.second) {
0420 auto A = pr.first;
0421 auto B = pr.second;
0422
0423
0424
0425
0426
0427
0428 Vector3 ctr = A->referencePosition(tgContext, AxisDirection::AxisR);
0429 const std::span<const Surface* const> binContent =
0430 layer->surfaceArray()->at(tgContext, ctr, ctr.normalized());
0431 BOOST_CHECK_EQUAL(binContent.size(), 2u);
0432
0433 std::set<const Surface*> exp({A, B});
0434 BOOST_CHECK(std::ranges::includes(binContent, exp));
0435 }
0436 }
0437
0438 BOOST_AUTO_TEST_SUITE_END()
0439
0440 }