Skip to content

Commit

Permalink
refactor(geo): Teach ProtoLayer to respect local coordinate system (#…
Browse files Browse the repository at this point in the history
…3697)

Needed for #3502

---

This pull request introduces several enhancements and new features to the `ProtoLayer` struct and its associated tests in the `Core` and `Tests` directories. The key changes include the addition of a local transform, multiple constructors, and new test cases to validate the functionality.

### Enhancements to `ProtoLayer` struct:

* Added a new member `transform` to the `ProtoLayer` struct and updated its constructors to accept a `Transform3` parameter with a default value of `Transform3::Identity()`. (`Core/include/Acts/Geometry/ProtoLayer.hpp`, `Core/src/Geometry/ProtoLayer.cpp`) [[1]](diffhunk://#diff-1451530599ae50cdf187f035045a620fe857ff4abcb25c7a0eefc33189ef3260R36-R38) [[2]](diffhunk://#diff-1451530599ae50cdf187f035045a620fe857ff4abcb25c7a0eefc33189ef3260R47-R50) [[3]](diffhunk://#diff-1451530599ae50cdf187f035045a620fe857ff4abcb25c7a0eefc33189ef3260R60-R76) [[4]](diffhunk://#diff-4d780d37fe19501d1f964a2d67f4a654c4365f31f736d0c9653a169f1637f29eL16-R43) [[5]](diffhunk://#diff-4d780d37fe19501d1f964a2d67f4a654c4365f31f736d0c9653a169f1637f29eL81-R95)
* Implemented a friend function for the output stream operator to facilitate easy printing of `ProtoLayer` objects. (`Core/include/Acts/Geometry/ProtoLayer.hpp`)

### Codebase simplification:

* Removed unused `#include` directives from `ProtoLayer.cpp` to clean up the code. (`Core/src/Geometry/ProtoLayer.cpp`)

### Enhancements to unit tests:

* Added new test cases in `ProtoLayerTests.cpp` to validate the behavior of `ProtoLayer` with different transformations.

These changes enhance the flexibility and functionality of the `ProtoLayer` struct and ensure that the new features are thoroughly tested.
  • Loading branch information
paulgessinger authored Oct 7, 2024
1 parent 8f0ae3c commit 39c6aca
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 43 deletions.
32 changes: 30 additions & 2 deletions Core/include/Acts/Geometry/ProtoLayer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ struct ProtoLayer {
/// The envelope parameters
ExtentEnvelope envelope = ExtentEnvelope::Zero();

/// The local transform
Transform3 transform = Transform3::Identity();

/// Constructor
///
/// Loops over a provided vector of surface and calculates the various
Expand All @@ -41,8 +44,10 @@ struct ProtoLayer {
///
/// @param gctx The current geometry context object, e.g. alignment
/// @param surfaces The vector of surfaces to consider
/// @param transformIn The local transform to evaluate the sizing in
ProtoLayer(const GeometryContext& gctx,
const std::vector<const Surface*>& surfaces);
const std::vector<const Surface*>& surfaces,
const Transform3& transformIn = Transform3::Identity());

/// Constructor
///
Expand All @@ -52,8 +57,23 @@ struct ProtoLayer {
///
/// @param gctx The current geometry context object, e.g. alignment
/// @param surfaces The vector of surfaces to consider
/// @param transformIn The local transform to evaluate the sizing in
ProtoLayer(const GeometryContext& gctx,
const std::vector<std::shared_ptr<const Surface>>& surfaces);
const std::vector<std::shared_ptr<const Surface>>& surfaces,
const Transform3& transformIn = Transform3::Identity());

/// Constructor
///
/// Loops over a provided vector of surface and calculates the various
/// min/max values in one go. Also takes into account the thickness
/// of an associated DetectorElement, if it exists.
///
/// @param gctx The current geometry context object, e.g. alignment
/// @param surfaces The vector of surfaces to consider
/// @param transformIn The local transform to evaluate the sizing in
ProtoLayer(const GeometryContext& gctx,
const std::vector<std::shared_ptr<Surface>>& surfaces,
const Transform3& transformIn = Transform3::Identity());

ProtoLayer() = default;

Expand Down Expand Up @@ -81,6 +101,14 @@ struct ProtoLayer {
/// @param sl the input ostream
std::ostream& toStream(std::ostream& sl) const;

/// Output stream operator
/// @param sl the input ostream
/// @param pl the ProtoLayer to be printed
/// @return the output ostream
friend std::ostream& operator<<(std::ostream& sl, const ProtoLayer& pl) {
return pl.toStream(sl);
}

/// Give access to the surfaces used/assigned to the ProtoLayer
const std::vector<const Surface*>& surfaces() const;

Expand Down
34 changes: 20 additions & 14 deletions Core/src/Geometry/ProtoLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,34 @@
#include "Acts/Surfaces/RegularSurface.hpp"
#include "Acts/Utilities/Helpers.hpp"

#include <algorithm>
#include <array>
#include <string>
#include <utility>

using Acts::VectorHelpers::perp;
using Acts::VectorHelpers::phi;

namespace Acts {

ProtoLayer::ProtoLayer(const GeometryContext& gctx,
const std::vector<const Surface*>& surfaces)
: m_surfaces(surfaces) {
const std::vector<const Surface*>& surfaces,
const Transform3& transformIn)
: transform(transformIn), m_surfaces(surfaces) {
measure(gctx, surfaces);
}

ProtoLayer::ProtoLayer(
const GeometryContext& gctx,
const std::vector<std::shared_ptr<const Surface>>& surfaces)
: m_surfaces(unpack_shared_vector(surfaces)) {
const std::vector<std::shared_ptr<const Surface>>& surfaces,
const Transform3& transformIn)
: transform(transformIn), m_surfaces(unpack_shared_vector(surfaces)) {
measure(gctx, m_surfaces);
}

ProtoLayer::ProtoLayer(const GeometryContext& gctx,
const std::vector<std::shared_ptr<Surface>>& surfaces,
const Transform3& transformIn)
: transform(transformIn) {
m_surfaces.reserve(surfaces.size());
for (const auto& sf : surfaces) {
m_surfaces.push_back(sf.get());
}
measure(gctx, m_surfaces);
}

Expand Down Expand Up @@ -78,15 +86,13 @@ void ProtoLayer::measure(const GeometryContext& gctx,
double thickness = element->thickness();
// We need a translation along and opposite half thickness
Vector3 sfNormal = regSurface->normal(gctx, sf->center(gctx));
std::vector<double> deltaT = {-0.5 * thickness, 0.5 * thickness};
for (const auto& dT : deltaT) {
Transform3 dtransform = Transform3::Identity();
dtransform.pretranslate(dT * sfNormal);
for (const auto& dT : {-0.5 * thickness, 0.5 * thickness}) {
Transform3 dtransform = transform * Translation3{dT * sfNormal};
extent.extend(sfPolyhedron.extent(dtransform));
}
continue;
}
extent.extend(sfPolyhedron.extent());
extent.extend(sfPolyhedron.extent(transform));
}
}

Expand Down
161 changes: 134 additions & 27 deletions Tests/UnitTests/Core/Geometry/ProtoLayerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,33 @@
#include <boost/test/unit_test.hpp>

#include "Acts/Definitions/Algebra.hpp"
#include "Acts/Definitions/Units.hpp"
#include "Acts/Geometry/DetectorElementBase.hpp"
#include "Acts/Geometry/Extent.hpp"
#include "Acts/Geometry/GeometryContext.hpp"
#include "Acts/Geometry/ProtoLayer.hpp"
#include "Acts/Surfaces/PlaneSurface.hpp"
#include "Acts/Surfaces/RectangleBounds.hpp"
#include "Acts/Surfaces/Surface.hpp"
#include "Acts/Tests/CommonHelpers/DetectorElementStub.hpp"
#include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
#include "Acts/Utilities/BinningType.hpp"
#include "Acts/Utilities/RangeXD.hpp"

#include <array>
#include <cmath>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

namespace Acts::Test::Layers {

GeometryContext tgContext = GeometryContext();

BOOST_AUTO_TEST_SUITE(Geometry)

BOOST_AUTO_TEST_CASE(ProtoLayerTests) {
GeometryContext tgContext = GeometryContext();
using enum BinningValue;

// Create a proto layer with 4 surfaces on the x/y grid
auto recBounds = std::make_shared<RectangleBounds>(3., 6.);
Expand Down Expand Up @@ -105,20 +108,20 @@ BOOST_AUTO_TEST_CASE(ProtoLayerTests) {
// Test 1 - identity transform
auto protoLayer = createProtoLayer(Transform3::Identity());

CHECK_CLOSE_ABS(protoLayer.range(BinningValue::binX), 12., 1e-8);
CHECK_CLOSE_ABS(protoLayer.medium(BinningValue::binX), 0., 1e-8);
CHECK_CLOSE_ABS(protoLayer.min(BinningValue::binX), -6., 1e-8);
CHECK_CLOSE_ABS(protoLayer.max(BinningValue::binX), 6., 1e-8);
CHECK_CLOSE_ABS(protoLayer.range(BinningValue::binY), 6., 1e-8);
CHECK_CLOSE_ABS(protoLayer.medium(BinningValue::binY), 0., 1e-8);
CHECK_CLOSE_ABS(protoLayer.min(BinningValue::binY), -3., 1e-8);
CHECK_CLOSE_ABS(protoLayer.max(BinningValue::binY), 3., 1e-8);
CHECK_CLOSE_ABS(protoLayer.range(BinningValue::binZ), 12., 1e-8);
CHECK_CLOSE_ABS(protoLayer.medium(BinningValue::binZ), 0., 1e-8);
CHECK_CLOSE_ABS(protoLayer.min(BinningValue::binZ), -6., 1e-8);
CHECK_CLOSE_ABS(protoLayer.max(BinningValue::binZ), 6., 1e-8);
CHECK_CLOSE_ABS(protoLayer.max(BinningValue::binR), std::hypot(3, 6), 1e-8);
CHECK_CLOSE_ABS(protoLayer.min(BinningValue::binR), 3., 1e-8);
CHECK_CLOSE_ABS(protoLayer.range(binX), 12., 1e-8);
CHECK_CLOSE_ABS(protoLayer.medium(binX), 0., 1e-8);
CHECK_CLOSE_ABS(protoLayer.min(binX), -6., 1e-8);
CHECK_CLOSE_ABS(protoLayer.max(binX), 6., 1e-8);
CHECK_CLOSE_ABS(protoLayer.range(binY), 6., 1e-8);
CHECK_CLOSE_ABS(protoLayer.medium(binY), 0., 1e-8);
CHECK_CLOSE_ABS(protoLayer.min(binY), -3., 1e-8);
CHECK_CLOSE_ABS(protoLayer.max(binY), 3., 1e-8);
CHECK_CLOSE_ABS(protoLayer.range(binZ), 12., 1e-8);
CHECK_CLOSE_ABS(protoLayer.medium(binZ), 0., 1e-8);
CHECK_CLOSE_ABS(protoLayer.min(binZ), -6., 1e-8);
CHECK_CLOSE_ABS(protoLayer.max(binZ), 6., 1e-8);
CHECK_CLOSE_ABS(protoLayer.max(binR), std::hypot(3, 6), 1e-8);
CHECK_CLOSE_ABS(protoLayer.min(binR), 3., 1e-8);

// Test 1a

Expand All @@ -127,16 +130,15 @@ BOOST_AUTO_TEST_CASE(ProtoLayerTests) {
auto protoLayerRot = createProtoLayer(AngleAxis3(-0.345, Vector3::UnitZ()) *
Transform3::Identity());

BOOST_CHECK_NE(protoLayer.min(BinningValue::binX), -6.);
CHECK_CLOSE_ABS(protoLayerRot.medium(BinningValue::binX), 0., 1e-8);
CHECK_CLOSE_ABS(protoLayerRot.medium(BinningValue::binY), 0., 1e-8);
CHECK_CLOSE_ABS(protoLayerRot.range(BinningValue::binZ), 12., 1e-8);
CHECK_CLOSE_ABS(protoLayerRot.medium(BinningValue::binZ), 0., 1e-8);
CHECK_CLOSE_ABS(protoLayerRot.min(BinningValue::binZ), -6., 1e-8);
CHECK_CLOSE_ABS(protoLayerRot.max(BinningValue::binZ), 6., 1e-8);
CHECK_CLOSE_ABS(protoLayerRot.min(BinningValue::binR), 3., 1e-8);
CHECK_CLOSE_ABS(protoLayerRot.max(BinningValue::binR), std::hypot(3, 6),
1e-8);
BOOST_CHECK_NE(protoLayer.min(binX), -6.);
CHECK_CLOSE_ABS(protoLayerRot.medium(binX), 0., 1e-8);
CHECK_CLOSE_ABS(protoLayerRot.medium(binY), 0., 1e-8);
CHECK_CLOSE_ABS(protoLayerRot.range(binZ), 12., 1e-8);
CHECK_CLOSE_ABS(protoLayerRot.medium(binZ), 0., 1e-8);
CHECK_CLOSE_ABS(protoLayerRot.min(binZ), -6., 1e-8);
CHECK_CLOSE_ABS(protoLayerRot.max(binZ), 6., 1e-8);
CHECK_CLOSE_ABS(protoLayerRot.min(binR), 3., 1e-8);
CHECK_CLOSE_ABS(protoLayerRot.max(binR), std::hypot(3, 6), 1e-8);

std::stringstream sstream;
protoLayerRot.toStream(sstream);
Expand All @@ -155,6 +157,111 @@ Extent in space :
BOOST_CHECK_EQUAL(sstream.str(), oString);
}

BOOST_AUTO_TEST_CASE(OrientedLayer) {
using enum BinningValue;
using namespace Acts::UnitLiterals;

Transform3 base = Transform3::Identity();

auto recBounds = std::make_shared<RectangleBounds>(3_mm, 6_mm);

std::vector<std::unique_ptr<DetectorElementBase>> detectorElements;

auto makeFan = [&](double yrot, double thickness = 0) {
detectorElements.clear();

std::size_t nSensors = 8;
double deltaPhi = 2 * M_PI / nSensors;
double r = 20_mm;
std::vector<std::shared_ptr<const Surface>> surfaces;
for (std::size_t i = 0; i < nSensors; i++) {
// Create a fan of sensors

Transform3 trf = base * AngleAxis3{yrot, Vector3::UnitY()} *
AngleAxis3{deltaPhi * i, Vector3::UnitZ()} *
Translation3(Vector3::UnitX() * r);

auto& element = detectorElements.emplace_back(
std::make_unique<DetectorElementStub>(trf, recBounds, thickness));

surfaces.push_back(element->surface().getSharedPtr());
}
return surfaces;
};

std::vector<std::shared_ptr<const Surface>> surfaces = makeFan(0_degree);

ProtoLayer protoLayer(tgContext, surfaces);

BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8);
BOOST_CHECK_CLOSE(protoLayer.min(binX), -23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.max(binX), 23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.min(binY), -23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.max(binY), 23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.min(binZ), 0_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.max(binZ), 0_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.min(binR), 17_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.max(binR), 23.769728648_mm, 1e-8);

surfaces = makeFan(45_degree);

// Do NOT provide rotation matrix: sizing will be affected
protoLayer = {tgContext, surfaces};

BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8);
BOOST_CHECK_CLOSE(protoLayer.min(binX), -16.26345596_mm, 1e-4);
BOOST_CHECK_CLOSE(protoLayer.max(binX), 16.26345596_mm, 1e-4);
BOOST_CHECK_CLOSE(protoLayer.min(binY), -23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.max(binY), 23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.min(binZ), -16.26345596_mm, 1e-4);
BOOST_CHECK_CLOSE(protoLayer.max(binZ), 16.26345596_mm, 1e-4);

protoLayer = {tgContext, surfaces,
Transform3{AngleAxis3{45_degree, Vector3::UnitY()}}.inverse()};

BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8);
BOOST_CHECK_CLOSE(protoLayer.range(binX), 46_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.min(binX), -23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.max(binX), 23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.range(binY), 46_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.min(binY), -23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.max(binY), 23_mm, 1e-8);
CHECK_SMALL(protoLayer.range(binZ), 1e-14);
CHECK_SMALL(protoLayer.min(binZ), 1e-14);
CHECK_SMALL(protoLayer.max(binZ), 1e-14);

surfaces = makeFan(0_degree, 10_mm);

protoLayer = {tgContext, surfaces};

BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8);
BOOST_CHECK_CLOSE(protoLayer.range(binX), 46_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.min(binX), -23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.max(binX), 23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.range(binY), 46_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.min(binY), -23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.max(binY), 23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.range(binZ), 10_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.min(binZ), -5_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.max(binZ), 5_mm, 1e-8);

surfaces = makeFan(45_degree, 10_mm);

protoLayer = {tgContext, surfaces,
Transform3{AngleAxis3{45_degree, Vector3::UnitY()}}.inverse()};

BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8);
BOOST_CHECK_CLOSE(protoLayer.range(binX), 46_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.min(binX), -23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.max(binX), 23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.range(binY), 46_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.min(binY), -23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.max(binY), 23_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.range(binZ), 10_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.min(binZ), -5_mm, 1e-8);
BOOST_CHECK_CLOSE(protoLayer.max(binZ), 5_mm, 1e-8);
}

BOOST_AUTO_TEST_SUITE_END()

} // namespace Acts::Test::Layers

0 comments on commit 39c6aca

Please sign in to comment.