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