ATLAS Offline Software
Loading...
Searching...
No Matches
TrapezoidBoundsExpander.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
5
6#ifndef SIMULATIONBASE
8#include "Acts/Geometry/TrapezoidVolumeBounds.hpp"
9#include "Acts/Geometry/CuboidVolumeBounds.hpp"
10#include "Acts/Definitions/Tolerance.hpp"
11#include "Acts/Surfaces/detail/PlanarHelper.hpp"
12#include "Acts/Definitions/Units.hpp"
14
15using namespace Acts::PlanarHelper;
16using namespace Acts::UnitLiterals;
17
18namespace MuonGMR4 {
19std::string toString(const std::vector<TrapezoidBoundsExpander::TrapezoidPatch>& patches) {
20 std::stringstream sstr{};
21 for (const auto& patch : patches) {
22 sstr<<" **** "<<patch<<std::endl;
23 }
24 return sstr.str();
25}
26
27
29 std::shared_ptr<const Acts::VolumeBounds> volBounds):
30 toCenter{trf}, bounds{std::move(volBounds)} {}
31void TrapezoidBoundsExpander::TrapezoidPatch::print(std::ostream& ostr) const {
32 ostr<<"BL: "<<Amg::toString(makeVertex(*this, Side::left, Level::bottom))
33 <<", TL: "<<Amg::toString(makeVertex(*this, Side::left, Level::top))
36 <<", bounds: "<<(*bounds)
37 <<", shift: "<<Amg::toString(toCenter);
38}
43 const Side side, const Level lvl) {
44 const double halfX = lvl == Level::top ? MuonGMR4::halfXhighY(*trapezoid.bounds)
45 : MuonGMR4::halfXlowY(*trapezoid.bounds);
46 return trapezoid.toCenter * Amg::Vector3D{Acts::copySign(halfX, side),
47 Acts::copySign(MuonGMR4::halfY(*trapezoid.bounds), lvl), 0.};
48}
49
50void TrapezoidBoundsExpander::expand(const Acts::GeometryContext& tgContext,
51 const Acts::Volume& volume){
52 ACTS_DEBUG(__func__<<"() "<<__LINE__<<" - Bounds "<<volume.volumeBounds());
53 reCenter(cornerPoints(tgContext, volume));
54 m_constituents.emplace_back(volume.localToGlobalTransform(tgContext),
55 volume.volumeBoundsPtr());
56}
57
58std::uint8_t TrapezoidBoundsExpander::toIndex(const Side side, const Level lvl) {
59 return (side == Side::left) + 2*(lvl == Level::top);
60}
61
63 const Amg::Vector3D& edge,
64 const Amg::Vector3D& testMe,
65 const Side side) {
66 const Amg::Vector3D closest = intersectPlane(vertex, edge,
67 Amg::Vector3D::UnitY(), testMe).position();
68 return (testMe.x() - closest.x()) *Acts::toUnderlying(side);
69}
70
71void TrapezoidBoundsExpander::setMargin(const double margin) {
72 ACTS_DEBUG(__func__<<"() "<<__LINE__<<" - Assign "<<margin<<" to all vertices");
73 m_margin.fill(margin);
74}
75
76void TrapezoidBoundsExpander::setMargin(const double marginXlow, const double marginXhigh,
77 const double marginY, const double marginZ) {
78 m_margin[0] = marginXlow;
79 m_margin[1] = marginXhigh;
80 m_margin[2] = marginY;
81 m_margin[3] = marginZ;
82 ACTS_DEBUG(__func__<<"() "<<__LINE__<<" - Assign "<<marginXlow<<"/"<<marginXhigh
83 <<" to x-edges , "<<marginY<<" to the y-edge, "<<marginZ<<" to the z-edge as extra margin");
84}
85
86std::shared_ptr<Acts::VolumeBounds>
87 TrapezoidBoundsExpander::makeBounds(Acts::VolumeBoundFactory& factory) {
88 if (m_finalBounds) {
89 return m_finalBounds;
90 }
91 const auto boxMin = minima();
92 const auto boxMax = maxima();
93
94 const double halfZ = 0.5*(boxMax[Amg::z] - boxMin[Amg::z]);
95 const double halfY = 0.5*(boxMax[Amg::y] - boxMin[Amg::y]);
96
97 if (std::ranges::all_of(m_constituents, [](const TrapezoidPatch& patch) {
98 return patch.bounds->type() == Acts::VolumeBounds::BoundsType::eCuboid;
99 })) {
100 ACTS_VERBOSE(__func__<<"() "<<__LINE__<<" Only cuboids have been passed. Construct a cuboid");
101 m_finalBounds = factory.makeBounds<Acts::CuboidVolumeBounds>(0.5*(boxMax[Amg::x] - boxMin[Amg::x]+
102 std::max(m_margin[0], m_margin[1])),
103 halfY + 0.5*m_margin[2],
104 halfZ + 0.5* m_margin[3]);
105 m_constituents.clear();
106 return m_finalBounds;
107 }
109 for (TrapezoidPatch &trapezoid : m_constituents) {
110 trapezoid.toCenter = toVertexCenter() * trapezoid.toCenter;
111 ACTS_VERBOSE(__func__<<"() "<<__LINE__<<" - Trapezoid after shift: "<<trapezoid);
114 GeoTrf::CoordEulerAngles rotAngles = GeoTrf::getCoordRotationAngles(trapezoid.toCenter);
115 if (std::abs(rotAngles.gamma - 180._degree)< Acts::s_epsilon) {
116 trapezoid.toCenter = trapezoid.toCenter *Amg::getRotateZ3D(180._degree);
117 ACTS_VERBOSE(__func__<<"() "<<__LINE__<<" - Flip trapezoid around Z: "
118 <<Amg::toString(trapezoid.toCenter));
119 }
120 if (std::abs(rotAngles.alpha - 180._degree)< Acts::s_epsilon) {
121 trapezoid.toCenter = trapezoid.toCenter *Amg::getRotateX3D(180._degree);
122 ACTS_VERBOSE(__func__<<"() "<<__LINE__<<" - Flip trapezoid around X: "
123 <<Amg::toString(trapezoid.toCenter));
124 }
125 }
126
127 std::array<Amg::Vector3D, 4> expandedCorners{Acts::filledArray<Amg::Vector3D, 4>(Amg::Vector3D::Zero())};
128 for (const Side side : {Side::left, Side::right}) {
129 std::ranges::sort(m_constituents, [side](const auto& a, const auto& b){
130 const Amg::Vector3D botA = makeVertex(a, side, Level::bottom);
131 const Amg::Vector3D botB = makeVertex(b, side, Level::bottom);
132 if (std::abs(botA.y() - botB.y()) > Acts::s_onSurfaceTolerance) {
133 return botA.y() < botB.y();
134 }
135 return (botA.x() - botB.x()) * Acts::toUnderlying(side) > 0.;
136 });
137 std::size_t highPatch{0ul};
140 std::optional<std::size_t> lowPatch{};
141 for (std::size_t patch = 0ul; patch < m_constituents.size(); ++ patch) {
142 if (!lowPatch.has_value() && m_constituents.at(patch).bounds->type() == Acts::VolumeBounds::eTrapezoid) {
143 lowPatch = patch;
144 }
145 const Amg::Vector3D botA = makeVertex(m_constituents.at(highPatch),
146 side, Level::bottom);
147 const Amg::Vector3D botB = makeVertex(m_constituents.at(patch),
148 side, Level::bottom);
149 ACTS_VERBOSE(__func__<<"() "<<__LINE__<<" - Test: "<<patch<<" position: "
150 <<Amg::toString(botB)<<" --- best: "<<highPatch<<" position: "
151 <<Amg::toString(botA)<<", distance: "<<(botB.x() - botA.x())<<", side: "<<side);
152 if ((botB.x() - botA.x()) * Acts::toUnderlying(side) > 0.) {
153 highPatch = patch;
154 }
155 }
156 ACTS_DEBUG(__func__<<"() "<<__LINE__<<" - Expand corners at "<<side
157 <<" side. Resorted trapezoids:\n"<<toString(m_constituents)
158 <<"\n ---- Selected upper trapezoid:\n"
159 <<m_constituents.at(highPatch));
160
161 findTrapezoidEdge(expandedCorners[toIndex(side, Level::bottom)],
162 expandedCorners[toIndex(side, Level::top)], side,
163 lowPatch.value_or(0), highPatch);
164 }
165 const double halfXhighY = std::max(std::abs(expandedCorners[toIndex(Side::left, Level::top)].x()),
166 std::abs(expandedCorners[toIndex(Side::right, Level::top)].x()));
167 const double halfXlowY = std::max(std::abs(expandedCorners[toIndex(Side::left, Level::bottom)].x()),
168 std::abs(expandedCorners[toIndex(Side::right, Level::bottom)].x()));
169 if (std::abs(halfXhighY - halfXlowY) > Acts::s_onSurfaceTolerance) {
170 m_finalBounds = factory.makeBounds<Acts::TrapezoidVolumeBounds>(halfXlowY + 0.5*m_margin[0],
171 halfXhighY + 0.5*m_margin[1],
172 halfY + 0.5*m_margin[2],
173 halfZ + 0.5* m_margin[3]);
174 } else {
175 m_finalBounds = factory.makeBounds<Acts::CuboidVolumeBounds>(halfXlowY + 0.5*std::max(m_margin[0], m_margin[1]),
176 halfY + 0.5*m_margin[2],
177 halfZ + 0.5* m_margin[3]);
178 }
179 ACTS_DEBUG(__func__<<"() "<<__LINE__<<" - Created new bounds "<<(*m_finalBounds));
180 m_constituents.clear();
181 return m_finalBounds;
182}
184 Amg::Vector3D& topCorner,
185 const Side side,
186 const std::size_t lowPatch,
187 const std::size_t highPatch) const {
188 const double halfY = 0.5*(maxima()[Amg::y] - minima()[Amg::y]);
189 botCorner = makeVertex(m_constituents.at(lowPatch), side, Level::bottom);
190 topCorner = makeVertex(m_constituents.at(highPatch), side, Level::top);
191 Amg::Vector3D edge = Amg::projectDirOntoPlane((botCorner - topCorner).unit(),
192 Amg::Vector3D::UnitZ());
193 botCorner = intersectPlane(botCorner, edge, Amg::Vector3D::UnitY(), -halfY).position();
194 topCorner = intersectPlane(topCorner, edge, Amg::Vector3D::UnitY(), halfY).position();
195
196 double steepM{0.};
198 auto updateSlope = [&]( const Amg::Vector3D& v) {
199 if (v.y() <= botCorner.y()) {
200 return;
201 }
202 const double m = (v.x() - botCorner.x()) / (v.y() - botCorner.y());
203 if(std::abs(m)> std::abs(steepM)) {
204 steepM = m;
205 }
206 };
207 updateSlope(topCorner);
208 ACTS_DEBUG(__func__<<"() "<<__LINE__<<" - Identified "<<Amg::toString(botCorner)
209 <<", "<<Amg::toString(topCorner)<<" as vertices. Edge: "<<Amg::toString(edge));
210 Amg::Vector3D farestVtx{botCorner};
211 double area{0.};
212 for (const TrapezoidPatch& patch : m_constituents) {
213 area += patch.area();
214 for (auto lvl : {Level::bottom, Level::top}) {
215 const Amg::Vector3D vtx = makeVertex(patch, side, lvl);
216 const double d = distanceToTrapezoid(botCorner, edge, vtx, side);
217 ACTS_VERBOSE(__func__<<"() "<<__LINE__<<" - Vertex at "<<lvl
218 <<" edge "<<Amg::toString(vtx)<<" distance: "<<d);
220 if (d > 0. && d > distanceToTrapezoid(botCorner, edge, farestVtx, side)) {
221 updateSlope(vtx);
222 farestVtx = vtx;
223 ACTS_VERBOSE(__func__<<"() "<<__LINE__<<" - Shift the trapezoid.");
224 }
225 }
226 }
227 ACTS_VERBOSE(__func__<<"() "<<__LINE__<<" - The farest "<<Amg::toString(farestVtx)<<" with distance "
228 <<distanceToTrapezoid(botCorner, edge, farestVtx, side)<<", steepest m: "<<steepM
229 <<", start M: "<<(topCorner.x() - botCorner.x()) / (topCorner.y() - botCorner.y()));
230
231 edge = Amg::Vector3D{steepM, 1., 0.}.unit();
232 botCorner = intersectPlane(farestVtx, edge, Amg::Vector3D::UnitY(), -halfY).position();
233 topCorner = intersectPlane(farestVtx, edge, Amg::Vector3D::UnitY(), halfY).position();
235 const double envArea = (std::abs(botCorner.x()) + std::abs(topCorner.x()))* 2.*halfY;
236 ACTS_VERBOSE(__func__<<"() "<<__LINE__<<" - Update corners to "<<Amg::toString(botCorner)
237 <<" (bottom) and "<<Amg::toString(topCorner)<<" (top) New area: "<<envArea
238 <<", old area: "<<area<<", diff: "<<(area/ envArea));
239}
240
241}
242#endif
double area(double R)
detray::unit< scalar_t > unit
static Double_t a
#define x
static std::vector< Amg::Vector3D > cornerPoints(const Acts::GeometryContext &tgContext, const Acts::Volume &volume, const std::size_t nSegments=3)
Returns the vertices from a volume.
std::span< const double > maxima() const
Returns the triplet of the maximum coordinates from the ensemble of all seen vertices.
std::span< const double > minima() const
Returns the triplet of the minimum coordinates from the ensemble of all seen vertices.
Acts::Transform3 toVertexCenter() const
Returns the transform from the ATLAS frame to the center of all seen vertices.
void reCenter(std::span< const Amg::Vector3D > vertices)
Update the center point from a list of global vertices.
virtual std::shared_ptr< Acts::VolumeBounds > makeBounds(Acts::VolumeBoundFactory &factory) override final
void findTrapezoidEdge(Amg::Vector3D &botCorner, Amg::Vector3D &topCorner, const Side side, const std::size_t lowPatch, const std::size_t highPatch) const
Moves the position of the bottom and top corner of a trapezoid side such that all vertices are enclos...
std::vector< TrapezoidPatch > m_constituents
void setMargin(const double margin)
Apply an extra margin to all four bound dimensions.
std::shared_ptr< Acts::VolumeBounds > m_finalBounds
static Amg::Vector3D makeVertex(const TrapezoidPatch &trapezoid, const Side side, const Level lvl)
Returns the vertex point from a trapezoid.
Level
Enum to select the top / bottom corners of a trapezoid.
Side
Enum to select the left / right corners of a trapezoid.
static double distanceToTrapezoid(const Amg::Vector3D &vertex, const Amg::Vector3D &edge, const Amg::Vector3D &testMe, const Side side)
Returns the distance to the inclided trapezoidal side Positive values imply that the test point is ou...
virtual void expand(const Acts::GeometryContext &tgContext, const Acts::Volume &volume) override final
static std::uint8_t toIndex(const Side side, const Level lvl)
Construct an index from [0;3] from the side and level.
Amg::Vector3D projectDirOntoPlane(const Amg::Vector3D &direction, const Amg::Vector3D &planeNorm)
Project the direction vector onto the plane and renormalize to unity.
Amg::Isometry3D getRotateX3D(double angle)
Rotate the coordinate system by an angle around the x-axis.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, 3, 1 > Vector3D
Amg::Isometry3D getRotateZ3D(double angle)
Rotate the coordinate system by an angle around the z-axis.
The ReadoutGeomCnvAlg converts the Run4 Readout geometry build from the GeoModelXML into the legacy M...
double halfY(const Acts::VolumeBounds &bounds)
Returns the half-Y length for the parsed volume bounds (Trapezoid/ Cuboid).
std::string toString(const MuonGMR4::MuonReadoutElement *re)
double halfZ(const Acts::VolumeBounds &bounds)
Returns the half-Z length for the parsed volume bounds (Trapezoid/ Cuboid).
double halfXhighY(const Acts::VolumeBounds &bounds)
Returns the half-Y length @ posiive Y for the parsed volume bounds (Trapezoid/ Cuboid).
double halfXlowY(const Acts::VolumeBounds &bounds)
Returns the half-X length @ negative Y for the parsed volume bounds (Trapezoid/ Cuboid).
STL namespace.
Helper struct to describe a sub trapezoid that is not aligned with the center of the coordinate syste...
void print(std::ostream &ostr) const
Print the TrapezoidPatch.
Acts::Transform3 toCenter
The transform to move to the outer trapezoid center.
double area() const
Calculates the area in the x-y plane.
TrapezoidPatch(const Acts::Transform3 &trf, std::shared_ptr< const Acts::VolumeBounds > volBounds)
The constructor.
std::shared_ptr< const Acts::VolumeBounds > bounds
Pointer to the volume bounds.