Code owners
Assign users and groups as approvers for specific file changes. Learn more.
SurfaceArrayTests.cpp 13.51 KiB
// This file is part of the ACTS project.
//
// Copyright (C) 2017-2018 ACTS project team
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#define BOOST_TEST_MODULE SurfaceArray
#include <boost/test/included/unit_test.hpp>
#include <boost/format.hpp>
#include <boost/test/data/test_case.hpp>
#include "ACTS/Surfaces/CylinderBounds.hpp"
#include "ACTS/Surfaces/PlaneSurface.hpp"
#include "ACTS/Surfaces/RadialBounds.hpp"
#include "ACTS/Surfaces/RectangleBounds.hpp"
#include "ACTS/Surfaces/SurfaceArray.hpp"
#include "ACTS/Tools/LayerCreator.hpp"
#include "ACTS/Tools/SurfaceArrayCreator.hpp"
#include "ACTS/Utilities/BinningType.hpp"
#include "ACTS/Utilities/Definitions.hpp"
#include "ACTS/Utilities/VariantData.hpp"
#include "ACTS/Utilities/detail/Grid.hpp"
namespace bdata = boost::unit_test::data;
namespace tt = boost::test_tools;
namespace Acts {
namespace Test {
using SrfVec = std::vector<const Surface*>;
struct SurfaceArrayFixture
{
std::vector<std::unique_ptr<const Surface>> m_surfaces;
SurfaceArrayFixture() { BOOST_TEST_MESSAGE("setup fixture"); }
~SurfaceArrayFixture() { BOOST_TEST_MESSAGE("teardown fixture"); }
SrfVec
fullPhiTestSurfacesEC(size_t n = 10,
double shift = 0,
double zbase = 0,
double r = 10)
{
SrfVec res;
double phiStep = 2 * M_PI / n;
for (size_t i = 0; i < n; ++i) {
double z = zbase + ((i % 2 == 0) ? 1 : -1) * 0.2;
Transform3D trans;
trans.setIdentity();
trans.rotate(Eigen::AngleAxisd(i * phiStep + shift, Vector3D(0, 0, 1)));
trans.translate(Vector3D(r, 0, z));
auto bounds = std::make_shared<const RectangleBounds>(2, 1);
auto transptr = std::make_shared<const Transform3D>(trans);
auto srf = std::make_unique<const PlaneSurface>(transptr, bounds);
res.push_back(srf.get()); // use raw pointer
m_surfaces.push_back(
std::move(srf)); // keep unique, will get destroyed at the end
}
return res;
}
SrfVec
fullPhiTestSurfacesBRL(int n = 10,
double shift = 0,
double zbase = 0,
double incl = M_PI / 9.,
double w = 2,
double h = 1.5)
{
SrfVec res;
double phiStep = 2 * M_PI / n;
for (int i = 0; i < n; ++i) {
double z = zbase;
Transform3D trans;
trans.setIdentity();
trans.rotate(Eigen::AngleAxisd(i * phiStep + shift, Vector3D(0, 0, 1)));
trans.translate(Vector3D(10, 0, z));
trans.rotate(Eigen::AngleAxisd(incl, Vector3D(0, 0, 1)));
trans.rotate(Eigen::AngleAxisd(M_PI / 2., Vector3D(0, 1, 0)));
auto bounds = std::make_shared<const RectangleBounds>(w, h);
auto transptr = std::make_shared<const Transform3D>(trans);
auto srf = std::make_unique<const PlaneSurface>(transptr, bounds);
res.push_back(srf.get()); // use raw pointer
m_surfaces.push_back(
std::move(srf)); // keep unique, will get destroyed at the end
}
return res;
}
SrfVec
straightLineSurfaces(size_t n = 10.,
double step = 3,
Vector3D origin = {0, 0, 1.5},
Transform3D pretrans = Transform3D::Identity(),
Vector3D dir = {0, 0, 1})
{
SrfVec res;
for (size_t i = 0; i < n; ++i) {
Transform3D trans;
trans.setIdentity();
trans.translate(origin + dir * step * i);
// trans.rotate(AngleAxis3D(M_PI/9., Vector3D(0, 0, 1)));
trans.rotate(AngleAxis3D(M_PI / 2., Vector3D(1, 0, 0)));
trans = trans * pretrans;
auto bounds = std::make_shared<const RectangleBounds>(2, 1.5);
auto transptr = std::make_shared<const Transform3D>(trans);
auto srf = std::make_unique<const PlaneSurface>(transptr, bounds);
res.push_back(srf.get()); // use raw pointer
m_surfaces.push_back(
std::move(srf)); // keep unique, will get destroyed at the end
}
return res;
}
SrfVec
makeBarrel(int nPhi, int nZ, double w, double h)
{
double z0 = -(nZ - 1) * w;
SrfVec res;
for (int i = 0; i < nZ; i++) {
double z = i * w * 2 + z0;
// std::cout << "z=" << z << std::endl;
SrfVec ring = fullPhiTestSurfacesBRL(nPhi, 0, z, M_PI / 9., w, h);
res.insert(res.end(), ring.begin(), ring.end());
}
return res;
}
void
draw_surfaces(SrfVec surfaces, std::string fname)
{
std::ofstream os;
os.open(fname);
os << std::fixed << std::setprecision(4);
size_t nVtx = 0;
for (const auto& srfx : surfaces) {
const PlaneSurface* srf = dynamic_cast<const PlaneSurface*>(srfx);
const PlanarBounds* bounds
= dynamic_cast<const PlanarBounds*>(&srf->bounds());
for (const auto& vtxloc : bounds->vertices()) {
Vector3D vtx = srf->transform() * Vector3D(vtxloc.x(), vtxloc.y(), 0);
os << "v " << vtx.x() << " " << vtx.y() << " " << vtx.z() << "\n";
}
// connect them
os << "f";
for (size_t i = 1; i <= bounds->vertices().size(); ++i) {
os << " " << nVtx + i;
}
os << "\n";
nVtx += bounds->vertices().size();
}
os.close();
}
};
BOOST_AUTO_TEST_SUITE(Surfaces)
BOOST_FIXTURE_TEST_CASE(SurfaceArray_create, SurfaceArrayFixture)
{
SrfVec brl = makeBarrel(30, 7, 2, 1);
draw_surfaces(brl, "SurfaceArray_create_BRL_1.obj");
detail::Axis<detail::AxisType::Equidistant,
detail::AxisBoundaryType::Closed>
phiAxis(-M_PI, M_PI, 30u);
detail::Axis<detail::AxisType::Equidistant, detail::AxisBoundaryType::Bound>
zAxis(-14, 14, 7u);
double angleShift = 2 * M_PI / 30. / 2.;
auto transform = [angleShift](const Vector3D& pos) {
return Vector2D(pos.phi() + angleShift, pos.z());
};
double R = 10;
auto itransform = [angleShift, R](const Vector2D& loc) {
return Vector3D(R * std::cos(loc[0] - angleShift),
R * std::sin(loc[0] - angleShift),
loc[1]);
};
auto sl
= std::make_unique<SurfaceArray::SurfaceGridLookup<decltype(phiAxis),
decltype(zAxis)>>(
transform,
itransform,
std::make_tuple(std::move(phiAxis), std::move(zAxis)));
sl->fill(brl);
SurfaceArray sa(std::move(sl), brl);
// let's see if we can access all surfaces
sa.dump(std::cout);
for (const auto& srf : brl) {
Vector3D ctr = srf->binningPosition(binR);
SrfVec binContent = sa.at(ctr);
BOOST_TEST(binContent.size() == 1);
BOOST_TEST(srf == binContent.at(0));
}
std::vector<const Surface*> neighbors
= sa.neighbors(itransform(Vector2D(0, 0)));
BOOST_TEST(neighbors.size() == 9);
auto sl2
= std::make_unique<SurfaceArray::SurfaceGridLookup<decltype(phiAxis),
decltype(zAxis)>>(
transform,
itransform,
std::make_tuple(std::move(phiAxis), std::move(zAxis)));
// do NOT fill, only completebinning
sl2->completeBinning(brl);
SurfaceArray sa2(std::move(sl2), brl);
sa.dump(std::cout);
for (const auto& srf : brl) {
Vector3D ctr = srf->binningPosition(binR);
SrfVec binContent = sa2.at(ctr);
BOOST_TEST(binContent.size() == 1);
BOOST_TEST(srf == binContent.at(0));
}
}
BOOST_AUTO_TEST_CASE(SurfaceArray_singleElement)
{
double w = 3, h = 4;
auto bounds = std::make_shared<const RectangleBounds>(w, h);
auto transptr
= std::make_shared<const Transform3D>(Transform3D::Identity());
auto srf = std::make_unique<const PlaneSurface>(transptr, bounds);
SurfaceArray sa(srf.get());
auto binContent = sa.at(Vector3D(42, 42, 42));
BOOST_TEST(binContent.size() == 1);
BOOST_TEST(binContent.at(0) == srf.get());
BOOST_TEST(sa.surfaces().size() == 1);
BOOST_TEST(sa.surfaces().at(0) == srf.get());
}
BOOST_FIXTURE_TEST_CASE(SurfaceArray_toVariantData, SurfaceArrayFixture)
{
SrfVec brl = makeBarrel(30, 7, 2, 1);
detail::Axis<detail::AxisType::Equidistant,
detail::AxisBoundaryType::Closed>
phiAxis(-M_PI, M_PI, 30u);
std::vector<double> zAxis_bin_edges_exp = {-14, -10, 3, 5, 8, 14};
detail::Axis<detail::AxisType::Variable, detail::AxisBoundaryType::Bound>
zAxis(zAxis_bin_edges_exp);
double angleShift = 2 * M_PI / 30. / 2.;
auto transform = [angleShift](const Vector3D& pos) {
return Vector2D(pos.phi() + angleShift, pos.z());
};
double R = 10;
auto itransform = [angleShift, R](const Vector2D& loc) {
return Vector3D(R * std::cos(loc[0] - angleShift),
R * std::sin(loc[0] - angleShift),
loc[1]);
};
auto sl = std::make_unique<SurfaceArray::SurfaceGridLookup<decltype(phiAxis), decltype(zAxis)>>(
transform,
itransform,
std::make_tuple(std::move(phiAxis), std::move(zAxis)));
sl->fill(brl);
SurfaceArray sa(std::move(sl), brl);
sa.dump(std::cout);
variant_data data = sa.toVariantData();
// std::cout << data << std::endl;
const variant_map& var_map = boost::get<variant_map>(data);
BOOST_TEST(var_map.get<std::string>("type") == "SurfaceArray");
const variant_map& sa_var_pl = var_map.get<variant_map>("payload");
BOOST_TEST(sa_var_pl.count("surfacegridlookup") == 1);
const variant_map& sgl_var_pl
= sa_var_pl.get<variant_map>("surfacegridlookup")
.get<variant_map>("payload");
BOOST_TEST(sgl_var_pl.get<int>("dimensions") == 2);
const variant_vector& axes = sgl_var_pl.get<variant_vector>("axes");
BOOST_TEST(axes.size() == 2);
const variant_map& phiAxis_pl
= axes.get<variant_map>(0).get<variant_map>("payload");
BOOST_TEST(phiAxis_pl.get<std::string>("axisboundarytype") == "closed");
BOOST_TEST(phiAxis_pl.get<std::string>("axistype") == "equidistant");
BOOST_TEST(phiAxis_pl.get<double>("min") == -M_PI);
BOOST_TEST(phiAxis_pl.get<double>("max") == M_PI);
BOOST_TEST(phiAxis_pl.get<int>("nbins") == 30);
const variant_map& zAxis_pl
= axes.get<variant_map>(1).get<variant_map>("payload");
BOOST_TEST(zAxis_pl.get<std::string>("axisboundarytype") == "bound");
BOOST_TEST(zAxis_pl.get<std::string>("axistype") == "variable");
const variant_vector& zAxis_bin_edges
= zAxis_pl.get<variant_vector>("bin_edges");
BOOST_TEST(zAxis_bin_edges.size() == 6);
for (size_t i = 0; i < zAxis_bin_edges.size(); i++) {
BOOST_TEST(zAxis_bin_edges.get<double>(i) == zAxis_bin_edges_exp.at(i));
}
SurfaceArray sa2(data, transform, itransform);
sa2.dump(std::cout);
std::ostringstream dumpExp_os;
sa.dump(dumpExp_os);
std::string dumpExp = dumpExp_os.str();
boost::test_tools::output_test_stream dumpAct;
sa2.dump(dumpAct);
BOOST_TEST(dumpAct.is_equal(dumpExp));
}
BOOST_FIXTURE_TEST_CASE(SurfaceArray_toVariantData_1D, SurfaceArrayFixture)
{
detail::Axis<detail::AxisType::Equidistant, detail::AxisBoundaryType::Bound>
zAxis(0, 30, 10);
auto transform = [](const Vector3D& pos) {
return std::array<double, 1>({{pos.z()}});
};
auto itransform = [](const std::array<double, 1>& loc) {
return Vector3D(0, 0, loc[0]);
};
auto sl = std::make_unique<SurfaceArray::SurfaceGridLookup<decltype(zAxis)>>(
transform, itransform, std::make_tuple(zAxis));
// same thing in 1D
SrfVec line = straightLineSurfaces();
sl->fill(line);
SurfaceArray sa(std::move(sl), line);
sa.dump(std::cout);
variant_data data = sa.toVariantData();
// std::cout << data << std::endl;
const variant_map& var_map = boost::get<variant_map>(data);
BOOST_TEST(var_map.get<std::string>("type") == "SurfaceArray");
const variant_map& sa_var_pl = var_map.get<variant_map>("payload");
BOOST_TEST(sa_var_pl.count("surfacegridlookup") == 1);
const variant_map& sgl_var_pl
= sa_var_pl.get<variant_map>("surfacegridlookup")
.get<variant_map>("payload");
BOOST_TEST(sgl_var_pl.get<int>("dimensions") == 1);
const variant_vector& axes = sgl_var_pl.get<variant_vector>("axes");
BOOST_TEST(axes.size() == 1);
const variant_map& zAxis_pl
= axes.get<variant_map>(0).get<variant_map>("payload");
BOOST_TEST(zAxis_pl.get<std::string>("axisboundarytype") == "bound");
BOOST_TEST(zAxis_pl.get<std::string>("axistype") == "equidistant");
BOOST_TEST(zAxis_pl.get<double>("min") == 0);
BOOST_TEST(zAxis_pl.get<double>("max") == 30);
BOOST_TEST(zAxis_pl.get<int>("nbins") == 10);
SurfaceArray sa2(data, transform, itransform);
sa2.dump(std::cout);
std::ostringstream dumpExp_os;
sa.dump(dumpExp_os);
std::string dumpExp = dumpExp_os.str();
boost::test_tools::output_test_stream dumpAct;
sa2.dump(dumpAct);
BOOST_TEST(dumpAct.is_equal(dumpExp));
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace Test
} // end of namespace Acts