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