ATLAS Offline Software
Loading...
Searching...
No Matches
MuonGMR4::ChamberAssembleTool Class Reference

Assembly tool to produce the Acts envolpe volumes around the muon stations & also to construct the spectrometer envelope volumes. More...

#include <ChamberAssembleTool.h>

Inheritance diagram for MuonGMR4::ChamberAssembleTool:
Collaboration diagram for MuonGMR4::ChamberAssembleTool:

Public Types

using VolBounds_t = Acts::VolumeBounds
 Abrivation of the volume bounds.
using VolBoundPtr_t = std::shared_ptr<VolBounds_t>
 Abrivation of the Volume bound ptr.
using SurfBoundPtr_t = std::shared_ptr<const Acts::PlanarBounds>
 Abrivation of the surface bounds.
using TrfWithBounds = std::tuple<Amg::Transform3D, VolBoundPtr_t, SurfBoundPtr_t>
 Abrivation of the volume transform together with a set of volume & surface bounds.

Public Member Functions

virtual StatusCode buildReadOutElements (MuonDetectorManager &mgr) override final

Private Types

using ChamberPtr = SpectrometerSector::ChamberPtr

Private Member Functions

template<typename ReObjType>
requires (Acts::PointerConcept<ReObjType>)
TrfWithBounds boundingBox (const ActsTrk::GeometryContext &gctx, const std::vector< ReObjType > &constituents, const Amg::Transform3D &globToLoc, Acts::VolumeBoundFactory &volBoundSet, Acts::SurfaceBoundFactory &surfBoundSet, const double margin) const
 builds the bounding box trapezoidal volume bounds from the set of readout elements Returns a pair of the volume bounds & the transformation to center the volume

Static Private Member Functions

static VolBoundPtr_t boundingBox (const MuonReadoutElement *reEle, Acts::VolumeBoundFactory &boundSet)
 Builds the trapezoidal bounding box enclosing a single readout element.
static VolBoundPtr_t boundingBox (const ChamberPtr &chamber, Acts::VolumeBoundFactory &boundSet)
static std::array< Amg::Vector3D, 4 > cornerPointsPlane (const Amg::Transform3D &localToGlob, const VolBounds_t &bounds)
 Returns the 4 corners of the trapezoid in the x-y plane.
static std::array< Amg::Vector3D, 8 > cornerPoints (const Amg::Transform3D &localToGlob, const VolBounds_t &bounds)
 Returns the 8 corners marking the trapezoid.
static Amg::Transform3D centerTrapezoid (const std::array< Amg::Vector3D, 8 > &cornerPoints)
 Returns the translation transform centering the 8 corner points of the trapezoid.
static double trapezoidEdgeDist (const Amg::Vector3D &linePos, const Amg::Vector3D &lineDir, const Amg::Vector3D &testMe, bool leftEdge)
 Returns the signed distances of an external point to the trapezoidal edge.
static VolBoundPtr_t enlargeBounds (const VolBounds_t &enlargeMe, const double margin, Acts::VolumeBoundFactory &volBoundSet)
 Enlarge the parsed volume bounds by an extra margin attached to all 3 dimensions.
static SurfBoundPtr_t surfaceBounds (const VolBounds_t &volBounds, Acts::SurfaceBoundFactory &surfBoundSet)
 Construct surface bounds which measure equal sizes in halfXlow/halfXhigh & halfY as the parsed volume bounds.

Private Attributes

ServiceHandle< Muon::IMuonIdHelperSvcm_idHelperSvc {this, "IdHelperSvc", "Muon::MuonIdHelperSvc/MuonIdHelperSvc"}
Gaudi::Property< bool > m_isRun4 {this, "run4Layout", false}
 Toggling whether the layout is a R3 or R4 layout.

Detailed Description

Assembly tool to produce the Acts envolpe volumes around the muon stations & also to construct the spectrometer envelope volumes.

Definition at line 29 of file ChamberAssembleTool.h.

Member Typedef Documentation

◆ ChamberPtr

◆ SurfBoundPtr_t

using MuonGMR4::ChamberAssembleTool::SurfBoundPtr_t = std::shared_ptr<const Acts::PlanarBounds>

Abrivation of the surface bounds.

Definition at line 41 of file ChamberAssembleTool.h.

◆ TrfWithBounds

Abrivation of the volume transform together with a set of volume & surface bounds.

Definition at line 43 of file ChamberAssembleTool.h.

◆ VolBoundPtr_t

Abrivation of the Volume bound ptr.

Definition at line 39 of file ChamberAssembleTool.h.

◆ VolBounds_t

using MuonGMR4::ChamberAssembleTool::VolBounds_t = Acts::VolumeBounds

Abrivation of the volume bounds.

Definition at line 37 of file ChamberAssembleTool.h.

Member Function Documentation

◆ boundingBox() [1/3]

template<typename ReObjType>
requires (Acts::PointerConcept<ReObjType>)
ChamberAssembleTool::TrfWithBounds MuonGMR4::ChamberAssembleTool::boundingBox ( const ActsTrk::GeometryContext & gctx,
const std::vector< ReObjType > & constituents,
const Amg::Transform3D & globToLoc,
Acts::VolumeBoundFactory & volBoundSet,
Acts::SurfaceBoundFactory & surfBoundSet,
const double margin ) const
private

builds the bounding box trapezoidal volume bounds from the set of readout elements Returns a pair of the volume bounds & the transformation to center the volume

Parameters
gctxGeometry context holding the alignment & global transformations
constituentsList of readout elements around which the bounding box shall be built
globToLocTransformation to go from the global -> local chamber's frame
volBoundSetFactory to create the volume bounds & share them across equivalent volumes
surfBoundSetFactory to create the surface bounds representing the material surfaces & share them across mutliple surfaces
marginExtra margin by which the returned volume bounds are enlarged

Hack to cope with the RPCs which may be rotated by 180 degrees around the x or z-axis in cases, they're upside down.

Check whether the bounds are already embedded in the trapezoid

Everything is contained in the volume

Fetch the edges of the best known trapezoid to extend the dimensions

Reserve space for the new envelope trapezoid

The first 4 indices in the trpezoidal array are the bottom corners

Check the angles of the bounding trapzeoids

On the left edge the trapezoid opening angle needs to be larger while on the right side it's smaller

Calculate the distance to the trapezoidal edge. If it's less than 0, it's not embedded by the trapezoid and the smaller the number the farer it's from the trapezoid

Choose as reference point the one which is farest away from the edge

Extend the trapezoid in the x-y plane

Edge points of the best-known trapezoid

Finally re-center the trapezoid

Definition at line 162 of file ChamberAssembleTool.cxx.

168 {
169
170 VolBoundPtr_t envelopeBounds{};
171 ATH_MSG_DEBUG("Conrstuct a new "<<typeid(Acts::RemovePointer_t<ReObjType>).name()<<" object.");
172 Amg::Transform3D newCentreTrf{Amg::Transform3D::Identity()};
173 for (const auto& chambEle : constituents) {
174 Amg::Transform3D trf = newCentreTrf * toCenter *
175 chambEle->localToGlobalTransform(gctx);
176 VolBoundPtr_t bounds = boundingBox(chambEle, volBoundSet);
179 GeoTrf::CoordEulerAngles rotAngles = GeoTrf::getCoordRotationAngles(trf);
180 if (std::abs(rotAngles.gamma - 180._degree)< Acts::s_epsilon){
181 trf = trf *Amg::getRotateZ3D(180._degree);
182 }
183 if (std::abs(rotAngles.alpha - 180._degree)< Acts::s_epsilon){
184 trf = trf *Amg::getRotateX3D(180._degree);
185 }
186
187 if (!envelopeBounds) {
188 envelopeBounds = bounds;
189 newCentreTrf = centerTrapezoid(cornerPoints(trf, *bounds)) * newCentreTrf;
190 ATH_MSG_VERBOSE("Envelope "<<toString(chambEle)<<", "<<(*envelopeBounds)<<", transform: "<<Amg::toString(newCentreTrf));
191 continue;
192 }
194 const std::array<Amg::Vector3D, 8> corners = cornerPoints(trf, *bounds);
195
197 if (std::ranges::none_of(corners, [&envelopeBounds](const Amg::Vector3D& v) {
198 return !envelopeBounds->inside(v);
199 })) {
200 ATH_MSG_VERBOSE("Element "<<toString(chambEle)<<" "
201 <<(*boundingBox(chambEle, volBoundSet))<<" fully contained. ");
202 continue;
203 }
204 if (msgLvl(MSG::VERBOSE)) {
205 std::stringstream debugStr{};
206 for (const Amg::Vector3D& corner : corners) {
207 debugStr<<" ***** "<<Amg::toString(corner)<<std::endl;
208 }
209 ATH_MSG_VERBOSE(toString(chambEle)<<" corner points "<<GeoTrf::toString(trf, true)<<std::endl<<debugStr.str());
210 }
212 const std::array<Amg::Vector3D, 8> refCorners{cornerPoints(Amg::Transform3D::Identity(), *envelopeBounds)};
214 std::array<Amg::Vector3D, 8> newTrapBounds{make_array<Amg::Vector3D, 8>(Amg::Vector3D::Zero())};
215
217 for (unsigned lowZ : {0, 4}) {
218 for (bool isLeft : {false, true}) {
219
220 const size_t iHigh = 1 + (!isLeft)*2 + lowZ;
221 const size_t iLow = 0 + (!isLeft)*2 + lowZ;
223 const Amg::Vector3D dirRef{projectIntoXY(refCorners[iHigh] - refCorners[iLow]).unit()};
224 const Amg::Vector3D dirCan{projectIntoXY(corners[iHigh] - corners[iLow]).unit()};
225
226
227 ATH_MSG_VERBOSE((isLeft ? "Left" : "Right")<<" edge "<<Amg::toString(dirRef)
228 <<" "<<dirRef.phi() / Gaudi::Units::deg <<" --- "<<toString(chambEle)<<" "
229 <<Amg::toString(dirCan)<<", phi: "<<dirCan.phi() / Gaudi::Units::deg);
230
232 const Amg::Vector3D& pickDir{(dirRef.phi() > dirCan.phi()) == isLeft ? dirRef : dirCan};
235 const double cornerLowD = trapezoidEdgeDist(refCorners[iLow], pickDir, corners[iLow], isLeft);
236 const double cornerHighD = trapezoidEdgeDist(refCorners[iLow], pickDir, corners[iHigh], isLeft);
237 ATH_MSG_VERBOSE("Distance "<<cornerLowD<<"/ "<<cornerHighD);
239 const Amg::Vector3D& pickPos{cornerLowD < 0 || cornerHighD < 0 ?
240 cornerLowD < cornerHighD ? corners[iLow] : corners[iHigh]: refCorners[iLow]};
241
242 ATH_MSG_VERBOSE("Low points "<<Amg::toString(corners[iLow])<<" - "<<Amg::toString(refCorners[iLow]));
243 ATH_MSG_VERBOSE("High points "<<Amg::toString(corners[iHigh])<<" - "<<Amg::toString(refCorners[iHigh]));
244
246 newTrapBounds[iHigh] = pickPos + Amg::intersect<3>(pickPos, pickDir, Amg::Vector3D::UnitY(),
247 std::max(corners[iHigh].y(), refCorners[iHigh].y())).value_or(0.) * pickDir;
248
249 newTrapBounds[iHigh].z() = lowZ ? std::max(corners[iHigh].z(),refCorners[iHigh].z())
250 : std::min(corners[iHigh].z(), refCorners[iHigh].z());
251 newTrapBounds[iLow] = pickPos + Amg::intersect<3>(pickPos, pickDir, Amg::Vector3D::UnitY(),
252 std::min(corners[iLow].y(), refCorners[iLow].y())).value_or(0.) * pickDir;
253 newTrapBounds[iLow].z() = lowZ ? std::max(corners[iLow].z(), refCorners[iLow].z())
254 : std::min(corners[iLow].z(), refCorners[iLow].z());
255 ATH_MSG_VERBOSE("New end points "<<Amg::toString(newTrapBounds[iLow])<<" - "<<Amg::toString(newTrapBounds[iHigh]));
256 }
257 }
258 if (msgLvl(MSG::VERBOSE)) {
259 std::stringstream debugStr{};
260 for (const Amg::Vector3D& edge : newTrapBounds) {
261 debugStr<<"***** "<<Amg::toString(edge)<<std::endl;
262 }
263 ATH_MSG_VERBOSE("#############################################################"<<std::endl<<
264 debugStr.str()<<"#############################################################");
265 }
267 const double halfY = 0.5*std::max(newTrapBounds[1].y() - newTrapBounds[0].y(),
268 newTrapBounds[3].y() - newTrapBounds[2].y());
269 const double lHalfX = 0.5*std::abs(newTrapBounds[3].x() - newTrapBounds[1].x());
270 const double sHalfX = 0.5*std::abs(newTrapBounds[2].x() - newTrapBounds[0].x());
271 const double halfZ = 0.5*std::abs(newTrapBounds[4].z() - newTrapBounds[0].z());
272 ATH_MSG_VERBOSE("New bounds "<<sHalfX<<"/"<<lHalfX<<", y:"<<halfY<<", "<<halfZ);
273 if (std::abs(lHalfX - sHalfX) > Acts::s_epsilon) {
274 envelopeBounds = volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(sHalfX, lHalfX, halfY, halfZ);
275 } else {
276 envelopeBounds = volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(sHalfX, halfY, halfZ);
277 }
278 ATH_MSG_VERBOSE(toString(chambEle)<<" "<<(*envelopeBounds));
279
281 const Amg::Transform3D centerShift = centerTrapezoid(newTrapBounds);
282 newCentreTrf = centerShift * newCentreTrf;
283 ATH_MSG_VERBOSE("New trapezoid centering "<<Amg::toString(centerShift)<<" combined: "
284 <<Amg::toString(newCentreTrf));
285 }
286 ATH_MSG_DEBUG("Done");
287 return std::make_tuple(newCentreTrf.inverse(),
288 enlargeBounds(*envelopeBounds, margin, volBoundSet),
289 surfaceBounds(*envelopeBounds, surfBoundSet));
290}
constexpr std::array< T, N > make_array(const T &def_val)
Helper function to initialize in-place arrays with non-zero values.
Definition ArrayHelper.h:10
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
#define y
#define x
#define z
#define min(a, b)
Definition cfImp.cxx:40
static std::array< Amg::Vector3D, 8 > cornerPoints(const Amg::Transform3D &localToGlob, const VolBounds_t &bounds)
Returns the 8 corners marking the trapezoid.
TrfWithBounds boundingBox(const ActsTrk::GeometryContext &gctx, const std::vector< ReObjType > &constituents, const Amg::Transform3D &globToLoc, Acts::VolumeBoundFactory &volBoundSet, Acts::SurfaceBoundFactory &surfBoundSet, const double margin) const
builds the bounding box trapezoidal volume bounds from the set of readout elements Returns a pair of ...
std::shared_ptr< VolBounds_t > VolBoundPtr_t
Abrivation of the Volume bound ptr.
static SurfBoundPtr_t surfaceBounds(const VolBounds_t &volBounds, Acts::SurfaceBoundFactory &surfBoundSet)
Construct surface bounds which measure equal sizes in halfXlow/halfXhigh & halfY as the parsed volume...
static double trapezoidEdgeDist(const Amg::Vector3D &linePos, const Amg::Vector3D &lineDir, const Amg::Vector3D &testMe, bool leftEdge)
Returns the signed distances of an external point to the trapezoidal edge.
static VolBoundPtr_t enlargeBounds(const VolBounds_t &enlargeMe, const double margin, Acts::VolumeBoundFactory &volBoundSet)
Enlarge the parsed volume bounds by an extra margin attached to all 3 dimensions.
static Amg::Transform3D centerTrapezoid(const std::array< Amg::Vector3D, 8 > &cornerPoints)
Returns the translation transform centering the 8 corner points of the trapezoid.
Amg::Transform3D getRotateX3D(double angle)
get a rotation transformation around X-axis
std::optional< double > intersect(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
Calculates the point B' along the line B that's closest to a second line A.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Amg::Transform3D getRotateZ3D(double angle)
get a rotation transformation around Z-axis
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
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)

◆ boundingBox() [2/3]

VolBoundPtr_t MuonGMR4::ChamberAssembleTool::boundingBox ( const ChamberPtr & chamber,
Acts::VolumeBoundFactory & boundSet )
staticprivate

Definition at line 97 of file ChamberAssembleTool.cxx.

97 {
98 return chamber->bounds();
99}

◆ boundingBox() [3/3]

VolBoundPtr_t MuonGMR4::ChamberAssembleTool::boundingBox ( const MuonReadoutElement * reEle,
Acts::VolumeBoundFactory & boundSet )
staticprivate

Builds the trapezoidal bounding box enclosing a single readout element.

Parameters
reElePointer to the readout element to fetch the bounds from
boundSetCache of create bounds to share the same bounds across multiple volumes

Definition at line 61 of file ChamberAssembleTool.cxx.

62 {
63
64 switch(chambEle->detectorType()) {
66 const auto* techEle = static_cast<const MdtReadoutElement*>(chambEle);
67 const auto& pars = techEle->getParameters();
68 if (std::abs(pars.shortHalfX - pars.longHalfX) < Acts::s_epsilon) {
69 return volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(pars.shortHalfX, pars.halfY, pars.halfHeight);
70 }
71 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.shortHalfX, pars.longHalfX,
72 pars.halfY, pars.halfHeight );
74 const auto* techEle = static_cast<const RpcReadoutElement*>(chambEle);
75 const auto& pars = techEle->getParameters();
76 return volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(pars.halfWidth, pars.halfLength, pars.halfThickness);
78 const auto* techEle = static_cast<const TgcReadoutElement*>(chambEle);
79 const auto& pars = techEle->getParameters();
80 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.halfWidthShort, pars.halfWidthLong,
81 pars.halfHeight, pars.halfThickness );
83 const auto* techEle = static_cast<const sTgcReadoutElement*>(chambEle);
84 const auto& pars = techEle->getParameters();
85 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.sHalfChamberLength, pars.lHalfChamberLength,
86 pars.halfChamberHeight, pars.halfChamberTck );
88 const auto* techEle = static_cast<const MmReadoutElement*>(chambEle);
89 const auto& pars = techEle->getParameters();
90 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.halfShortWidth, pars.halfLongWidth,
91 pars.halfHeight, pars.halfThickness );
92 } default:
93 THROW_EXCEPTION("Unsupported detector type "<<to_string(chambEle->detectorType()));
94 }
95 return nullptr;
96}
static std::string to_string(const std::vector< T > &v)
@ Mm
Maybe not needed in the migration.
@ Tgc
Resitive Plate Chambers.
@ sTgc
Micromegas (NSW)
@ Rpc
Monitored Drift Tubes.
@ Mdt
MuonSpectrometer.
#define THROW_EXCEPTION(MESSAGE)
Definition throwExcept.h:10

◆ buildReadOutElements()

StatusCode MuonGMR4::ChamberAssembleTool::buildReadOutElements ( MuonDetectorManager & mgr)
finaloverridevirtual

TGC T4E chambers & Mdt EIL chambers are glued together

Group chambers by sectors && station layer.

Check that the two readout elements are on the same side. Exception BOG eta 0 -> attributes to positive sectors

The two readout elements shall be located in the same sector

into a single chamber

If no chamber has been found, then create a new one

Find the chamber middle and create the geometry from that

Define the spectrometer sector

Define the chamber envelopes

Sort the readout elements by common parent volume

The BIS 7/8 chamber needs to be comparted into 4 subvolumes, each containing a single readout element to minimize the impact from the overlap between BIS78 & EIL-4 (TGC)

We need to ensure that the EIL 4/5 are split into a separate volume w.r.t. the New Small Wheel

now, build simplified 2D representations of the sorted chambers we collected.

Now construct the sector volume from the chamber envelopes

Definition at line 292 of file ChamberAssembleTool.cxx.

292 {
293 ATH_CHECK(m_idHelperSvc.retrieve());
295 auto mdtStationIndex = [this] (const std::string& stName) {
296 return m_idHelperSvc->hasMDT() ? m_idHelperSvc->mdtIdHelper().stationNameIndex(stName) : -1;
297 };
298 auto tgcStationIndex = [this] (const std::string& stName) {
299 return m_idHelperSvc->hasTGC() ? m_idHelperSvc->tgcIdHelper().stationNameIndex(stName) : -1;
300 };
301
302 const std::unordered_set<int> stIndicesEM{mdtStationIndex("EML"), mdtStationIndex("EMS"),
303 tgcStationIndex("T1E"), tgcStationIndex("T1F"),
304 tgcStationIndex("T2E"), tgcStationIndex("T2F"),
305 tgcStationIndex("T3E"), tgcStationIndex("T3F")};
306
307
308 std::unordered_set<Identifier> BIS78_ids{};
309 auto fillBIS78 = [&BIS78_ids, this](const MuonIdHelper& idHelper) {
310 const int BIS = idHelper.stationNameIndex("BIS");
311 std::copy_if(idHelper.detectorElement_begin(), idHelper.detectorElement_end(), std::inserter(BIS78_ids, BIS78_ids.end()),
312 [&](const Identifier& detId){
313 int stEta = idHelper.stationEta(detId);
314 if (m_isRun4) {
315 stEta = std::abs(stEta);
316 }
317 return stEta >= 7 && idHelper.stationName(detId) == BIS;
318 });
319 };
320 if (m_idHelperSvc->hasMDT()) {
321 fillBIS78(m_idHelperSvc->mdtIdHelper());
322 }
323 if (m_idHelperSvc->hasRPC()) {
324 fillBIS78(m_idHelperSvc->rpcIdHelper());
325 }
326
327 std::vector<MuonReadoutElement*> allReadOutEles = mgr.getAllReadoutElements();
328
329 std::vector<chamberArgs> envelopeCandidates{};
330
332 for (const MuonReadoutElement* readOutEle : allReadOutEles) {
333 std::vector<chamberArgs>::iterator exist = std::ranges::find_if(envelopeCandidates,
334 [this, readOutEle, &stIndicesEM](const chamberArgs& args){
335 const MuonReadoutElement* refEle = args.detEles.front();
336 const Identifier refId = refEle->identify();
337 const Identifier testId = readOutEle->identify();
340 if (Acts::copySign(1, refEle->stationEta()) *
341 Acts::copySign(1, readOutEle->stationEta()) < 0) {
342 return false;
343 }
345 if (m_idHelperSvc->sector(testId) != m_idHelperSvc->sector(refId)) {
346 return false;
347 }
348 if (stIndicesEM.count(readOutEle->stationName()) &&
349 stIndicesEM.count(refEle->stationName())) {
350 return true;
351 }
352 // /// Summarize all readout element in the same sector & layer
354 return readOutEle->chamberIndex() == refEle->chamberIndex();
355 });
357 if (exist == envelopeCandidates.end()) {
358 ATH_MSG_VERBOSE("Open envelope "<<(envelopeCandidates.size()+1)
359 <<" for "<<m_idHelperSvc->toStringDetEl(readOutEle->identify())
360 <<", sector: "<<m_idHelperSvc->sector(readOutEle->identify())
361 <<", chIdx: "<<Muon::MuonStationIndex::chName(readOutEle->chamberIndex()));
362 envelopeCandidates.emplace_back().detEles.push_back(readOutEle);
363 } else {
364 ATH_MSG_VERBOSE("Attach "<<m_idHelperSvc->toStringDetEl(readOutEle->identify())
365 <<", sector: "<<m_idHelperSvc->sector(readOutEle->identify())
366 <<", chIdx: "<<Muon::MuonStationIndex::chName(readOutEle->chamberIndex())<<" to envelope "
367 <<(std::distance(envelopeCandidates.begin(), exist) + 1)<<". ");
368 exist->detEles.push_back(readOutEle);
369 }
370 }
372 ActsTrk::GeometryContext gctx{};
373
374
375 Acts::VolumeBoundFactory volBoundSet{};
376 Acts::SurfaceBoundFactory surfBoundSet{};
377 unsigned candId{0};
378 for (chamberArgs& candidate : envelopeCandidates) {
379 std::unordered_set<Identifier> reIds{};
380
381 ATH_MSG_VERBOSE("New envelope candidate ");
383 SpectrometerSector::defineArgs sectorArgs{};
384 sectorArgs.id = (++candId);
385 using namespace Muon::MuonStationIndex;
386 std::vector<std::vector<const MuonReadoutElement*>> chamberElements{};
387 if (toStationIndex(candidate.detEles.front()->chamberIndex()) != StIndex::EI) {
389 std::map<PVConstLink, std::vector<const MuonReadoutElement*>> stationMap{};
391 for (const MuonReadoutElement* re : candidate.detEles) {
394 if (BIS78_ids.count(re->identify())) {
395 stationMap[re->getMaterialGeom()].push_back(re);
396 } else {
397 stationMap[re->getMaterialGeom()->getParent()].push_back(re);
398 }
399 }
400 for (auto& [parent, stationEles ]: stationMap){
401 chamberElements.push_back(std::move(stationEles));
402 }
403 } else {
406 std::vector<std::vector<const MuonReadoutElement*>> endcapEles(2);
407
408 for (const MuonReadoutElement* sortMe : candidate.detEles){
409 if (sortMe->detectorType() == ActsTrk::DetectorType::Tgc) {
410 endcapEles.emplace_back(1, sortMe);
411 } else {
412 endcapEles[sortMe->detectorType() == ActsTrk::DetectorType::sTgc ||
413 sortMe->detectorType() == ActsTrk::DetectorType::Mm].push_back(sortMe);
414 }
415 }
416 for (auto& stationEles : endcapEles) {
417 if (!stationEles.empty()) {
418 chamberElements.push_back(std::move(stationEles));
419 }
420 }
421 }
422
423 for (auto& detEles: chamberElements) {
424 const MuonReadoutElement* refEle = detEles.front();
425 const Amg::Transform3D toChambCentre = refEle->globalToLocalTransform(gctx);
426 ATH_MSG_VERBOSE("New chamber candidate "<<m_idHelperSvc->toStringChamber(refEle->identify()));
427 const auto[chamberCentre, chamberBox, planeBounds] = boundingBox(gctx, detEles, toChambCentre, volBoundSet,
428 surfBoundSet, 0.*Gaudi::Units::cm);
429 chamberArgs chambArgs{};
430 chambArgs.detEles = std::move(detEles);
431 chambArgs.bounds = chamberBox;
432 chambArgs.surface = Acts::Surface::makeShared<Acts::PlaneSurface>(toChambCentre.inverse() * chamberCentre, planeBounds);
433 const Chamber* newChamber {sectorArgs.chambers.emplace_back(std::make_unique<Chamber>(std::move(chambArgs))).get()};
434 for (const MuonReadoutElement* re : newChamber->readoutEles()) {
435 reIds.insert(re->identify());
436 mgr.getReadoutElement(re->identify())->setChamberLink(newChamber);
437 ATH_MSG_VERBOSE("Chamber element: "<<m_idHelperSvc->toStringDetEl(re->identify()));
438
439 }
440 ATH_MSG_VERBOSE("Created new chamber: "<<(*newChamber));
441 }
442 std::ranges::sort(sectorArgs.chambers, [](const SpectrometerSector::ChamberPtr& a,
444 return (*a) < (*b);
445 });
446
447 const Amg::Transform3D toCenter = sectorArgs.chambers.front()->globalToLocalTransform(gctx);
448 const auto [envelopeCentre, envelopeBox, envelopePlane] = boundingBox(gctx, sectorArgs.chambers, toCenter,
449 volBoundSet, surfBoundSet, 2.* Gaudi::Units::cm);
450
451 sectorArgs.bounds = envelopeBox;
452 sectorArgs.surface = Acts::Surface::makeShared<Acts::PlaneSurface>(toCenter.inverse() * envelopeCentre, envelopePlane);
453
454 const Amg::Transform3D globalToSector = sectorArgs.surface->localToGlobalTransform(gctx.context()).inverse();
455
457 for (auto & chamber : sectorArgs.chambers){
458 // split by readout elements - MDT multilayers and trigger chambers for the sector
459 for (auto & RE : chamber->readoutEles()){
460 // get the center of the element in the sector frame
461 const Amg::Transform3D& chamberToGlobal{RE->localToGlobalTransform(gctx)};
462 const Amg::Vector3D origin = (globalToSector * chamberToGlobal).translation();
463 // and then add the bounds of the element - this is technology dependent
464 sectorArgs.detectorLocs.emplace_back(origin, RE, boundingBox(RE, volBoundSet));
465 }
466 }
468 auto newSector = std::make_unique<SpectrometerSector>(std::move(sectorArgs));
469
470 for (const Identifier& chId : reIds) {
471 mgr.getReadoutElement(chId)->setSectorLink(newSector.get());
472 }
473 mgr.addSpectrometerSector(std::move(newSector));
474 }
475 return StatusCode::SUCCESS;
476}
const boost::regex re(r_e)
#define ATH_CHECK
Evaluate an expression and check for errors.
static Double_t a
@ BIS
Definition RegSelEnums.h:11
Acts::GeometryContext context() const
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
GeoModel::TransientConstSharedPtr< Chamber > ChamberPtr
Chamber::defineArgs chamberArgs
StIndex toStationIndex(ChIndex index)
convert ChIndex into StIndex
const std::string & stName(StIndex index)
convert StIndex into a string
const std::string & chName(ChIndex index)
convert ChIndex into a string
Chamber
Define chamber types and locations.
ReadoutSet detEles
List of associated readout elements.
Definition Chamber.h:36

◆ centerTrapezoid()

Amg::Transform3D MuonGMR4::ChamberAssembleTool::centerTrapezoid ( const std::array< Amg::Vector3D, 8 > & cornerPoints)
staticprivate

Returns the translation transform centering the 8 corner points of the trapezoid.

The centre is defined as the centre point of the surrounding box

Parameters
cornerPointsArray to all 8 corner points of the trapezoid

Definition at line 122 of file ChamberAssembleTool.cxx.

122 {
123
124 static constexpr double maxSize = 200._km;
125 double minX{maxSize}, maxX{-maxSize}, minY{maxSize}, maxY{-maxSize}, minZ{maxSize}, maxZ{-maxSize};
126 for (const Amg::Vector3D& corner : corners) {
127 minX = std::min(corner.x(), minX); maxX = std::max(corner.x(), maxX);
128 minY = std::min(corner.y(), minY); maxY = std::max(corner.y(), maxY);
129 minZ = std::min(corner.z(), minZ); maxZ = std::max(corner.z(), maxZ);
130 }
131 return Amg::getTranslate3D(-0.5*(minX + maxX), -0.5*(minY + maxY), -0.5*(minZ + maxZ));
132}
Amg::Transform3D getTranslate3D(const double X, const double Y, const double Z)
: Returns a shift transformation along an arbitrary axis

◆ cornerPoints()

std::array< Amg::Vector3D, 8 > MuonGMR4::ChamberAssembleTool::cornerPoints ( const Amg::Transform3D & localToGlob,
const VolBounds_t & bounds )
staticprivate

Returns the 8 corners marking the trapezoid.

Parameters
localToGlobTransform from the trapezoid restframe -> chambers frame
boundsReference to the trapezoidal bounds defining the volume

Definition at line 110 of file ChamberAssembleTool.cxx.

111 {
112 std::array<Amg::Vector3D, 8> toRet{make_array<Amg::Vector3D,8>(Amg::Vector3D::Zero())};
113 const std::array<Amg::Vector3D, 4> plane = cornerPointsPlane(localToGlob, bounds);
114 for (unsigned int z : {0, 1}) {
115 const Amg::Vector3D stretch = halfZ(bounds) * (z ? 1. : -1.) * Amg::Vector3D::UnitZ();
116 for (unsigned int b = 0; b < plane.size(); ++b){
117 toRet[b + z * plane.size()] = plane[b] + stretch;
118 }
119 }
120 return toRet;
121}
static std::array< Amg::Vector3D, 4 > cornerPointsPlane(const Amg::Transform3D &localToGlob, const VolBounds_t &bounds)
Returns the 4 corners of the trapezoid in the x-y plane.

◆ cornerPointsPlane()

std::array< Amg::Vector3D, 4 > MuonGMR4::ChamberAssembleTool::cornerPointsPlane ( const Amg::Transform3D & localToGlob,
const VolBounds_t & bounds )
staticprivate

Returns the 4 corners of the trapezoid in the x-y plane.

Parameters
localToGlobTransform from the trapezoid restframe -> chambers frame
boundsReference to the trapezoidal bounds defining the volume

Definition at line 102 of file ChamberAssembleTool.cxx.

103 {
104 std::array<Amg::Vector3D,4> planePoints{localToGlob * Amg::Vector3D(-halfXlowY(bounds), - halfY(bounds), 0.),
105 localToGlob * Amg::Vector3D(-halfXhighY(bounds), halfY(bounds), 0.),
106 localToGlob * Amg::Vector3D( halfXlowY(bounds), -halfY(bounds), 0.),
107 localToGlob * Amg::Vector3D( halfXhighY(bounds), halfY(bounds), 0.)};
108 return planePoints;
109}
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)

◆ enlargeBounds()

VolBoundPtr_t MuonGMR4::ChamberAssembleTool::enlargeBounds ( const VolBounds_t & enlargeMe,
const double margin,
Acts::VolumeBoundFactory & volBoundSet )
staticprivate

Enlarge the parsed volume bounds by an extra margin attached to all 3 dimensions.

Parameters
enlargeMeBounds which are intended to be enlarged
marginAmount by which the total length of the bounds should grow
volBoundsSetBound factory to assign equivalent bounds to multiple volumes

Definition at line 135 of file ChamberAssembleTool.cxx.

137 {
138 if (enlargeMe.type() == Acts::VolumeBounds::BoundsType::eCuboid) {
139 return volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(halfXlowY(enlargeMe) + 0.5*margin,
140 halfY(enlargeMe) + 0.5*margin,
141 halfZ(enlargeMe) + 0.5*margin);
142 } else if (enlargeMe.type() == Acts::VolumeBounds::BoundsType::eTrapezoid) {
143 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(halfXlowY(enlargeMe) + 0.5*margin,
144 halfXhighY(enlargeMe) + 0.5*margin,
145 halfY(enlargeMe) + 0.5*margin,
146 halfZ(enlargeMe) + 0.5*margin);
147 }
148 return nullptr;
149}

◆ surfaceBounds()

ChamberAssembleTool::SurfBoundPtr_t MuonGMR4::ChamberAssembleTool::surfaceBounds ( const VolBounds_t & volBounds,
Acts::SurfaceBoundFactory & surfBoundSet )
staticprivate

Construct surface bounds which measure equal sizes in halfXlow/halfXhigh & halfY as the parsed volume bounds.

Parameters
volBoundsBounds which are mapped to surface bounds
surfBoundSetBound factory to assign equivalent bounds to multiple surfaces

Definition at line 151 of file ChamberAssembleTool.cxx.

152 {
153 if (volBounds.type() == Acts::VolumeBounds::BoundsType::eCuboid) {
154 return surfBoundSet.makeBounds<Acts::RectangleBounds>(halfXlowY(volBounds), halfY(volBounds));
155 } else if (volBounds.type() == Acts::VolumeBounds::BoundsType::eTrapezoid) {
156 return surfBoundSet.makeBounds<Acts::TrapezoidBounds>(halfXlowY(volBounds) , halfXhighY(volBounds) , halfY(volBounds));
157 }
158 return nullptr;
159}

◆ trapezoidEdgeDist()

double MuonGMR4::ChamberAssembleTool::trapezoidEdgeDist ( const Amg::Vector3D & linePos,
const Amg::Vector3D & lineDir,
const Amg::Vector3D & testMe,
bool leftEdge )
staticprivate

Returns the signed distances of an external point to the trapezoidal edge.

Distances > 0 indicate that the point is inside the boundaries and outside otherwise

Parameters
linePosArbitrary point on the trapezoidal edge
lineDirDirection of the trapezoidal edge
testMeExternal point to measure the distance
leftEdgeSwitch indicating whether the edge is on the left & right side

Construct the normal pointing inwards

Definition at line 50 of file ChamberAssembleTool.cxx.

53 {
55 const Amg::Vector3D normal = lineDir.cross((leftEdge ? 1. : -1.) *Amg::Vector3D::UnitZ());
56 const Amg::Vector3D closest = linePos + lineDir.dot(testMe - linePos) * lineDir;
57 return normal.dot(testMe - closest);
58}

Member Data Documentation

◆ m_idHelperSvc

ServiceHandle<Muon::IMuonIdHelperSvc> MuonGMR4::ChamberAssembleTool::m_idHelperSvc {this, "IdHelperSvc", "Muon::MuonIdHelperSvc/MuonIdHelperSvc"}
private

Definition at line 112 of file ChamberAssembleTool.h.

112{this, "IdHelperSvc", "Muon::MuonIdHelperSvc/MuonIdHelperSvc"};

◆ m_isRun4

Gaudi::Property<bool> MuonGMR4::ChamberAssembleTool::m_isRun4 {this, "run4Layout", false}
private

Toggling whether the layout is a R3 or R4 layout.

If true, the BIS eta: -7 chambers are split into the individual readout elements.

Definition at line 115 of file ChamberAssembleTool.h.

115{this, "run4Layout", false};

The documentation for this class was generated from the following files: