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 182 of file ChamberAssembleTool.cxx.

188 {
189
190 VolBoundPtr_t envelopeBounds{};
191 ATH_MSG_DEBUG("Conrstuct a new "<<typeid(Acts::RemovePointer_t<ReObjType>).name()<<" object.");
192 Amg::Transform3D newCentreTrf{Amg::Transform3D::Identity()};
193 for (const auto& chambEle : constituents) {
194 Amg::Transform3D trf = newCentreTrf * toCenter *
195 chambEle->localToGlobalTrans(gctx) *
196 axisRotation(chambEle).inverse();
197 VolBoundPtr_t bounds = boundingBox(chambEle, volBoundSet);
200 GeoTrf::CoordEulerAngles rotAngles = GeoTrf::getCoordRotationAngles(trf);
201 if (std::abs(rotAngles.gamma - 180._degree)< Acts::s_epsilon){
202 trf = trf *Amg::getRotateZ3D(180._degree);
203 }
204 if (std::abs(rotAngles.alpha - 180._degree)< Acts::s_epsilon){
205 trf = trf *Amg::getRotateX3D(180._degree);
206 }
207
208 if (!envelopeBounds) {
209 envelopeBounds = bounds;
210 newCentreTrf = centerTrapezoid(cornerPoints(trf, *bounds)) * newCentreTrf;
211 ATH_MSG_VERBOSE("Envelope "<<toString(chambEle)<<", "<<(*envelopeBounds)<<", transform: "<<Amg::toString(newCentreTrf));
212 continue;
213 }
215 const std::array<Amg::Vector3D, 8> corners = cornerPoints(trf, *bounds);
216
218 if (std::ranges::none_of(corners, [&envelopeBounds](const Amg::Vector3D& v) {
219 return !envelopeBounds->inside(v);
220 })) {
221 ATH_MSG_VERBOSE("Element "<<toString(chambEle)<<" "
222 <<(*boundingBox(chambEle, volBoundSet))<<" fully contained. ");
223 continue;
224 }
225 if (msgLvl(MSG::VERBOSE)) {
226 std::stringstream debugStr{};
227 for (const Amg::Vector3D& corner : corners) {
228 debugStr<<" ***** "<<Amg::toString(corner)<<std::endl;
229 }
230 ATH_MSG_VERBOSE(toString(chambEle)<<" corner points "<<GeoTrf::toString(trf, true)<<std::endl<<debugStr.str());
231 }
233 const std::array<Amg::Vector3D, 8> refCorners{cornerPoints(Amg::Transform3D::Identity(), *envelopeBounds)};
235 std::array<Amg::Vector3D, 8> newTrapBounds{make_array<Amg::Vector3D, 8>(Amg::Vector3D::Zero())};
236
238 for (unsigned lowZ : {0, 4}) {
239 for (bool isLeft : {false, true}) {
240
241 const size_t iHigh = 1 + (!isLeft)*2 + lowZ;
242 const size_t iLow = 0 + (!isLeft)*2 + lowZ;
244 const Amg::Vector3D dirRef{projectIntoXY(refCorners[iHigh] - refCorners[iLow]).unit()};
245 const Amg::Vector3D dirCan{projectIntoXY(corners[iHigh] - corners[iLow]).unit()};
246
247
248 ATH_MSG_VERBOSE((isLeft ? "Left" : "Right")<<" edge "<<Amg::toString(dirRef)
249 <<" "<<dirRef.phi() / Gaudi::Units::deg <<" --- "<<toString(chambEle)<<" "
250 <<Amg::toString(dirCan)<<", phi: "<<dirCan.phi() / Gaudi::Units::deg);
251
253 const Amg::Vector3D& pickDir{(dirRef.phi() > dirCan.phi()) == isLeft ? dirRef : dirCan};
256 const double cornerLowD = trapezoidEdgeDist(refCorners[iLow], pickDir, corners[iLow], isLeft);
257 const double cornerHighD = trapezoidEdgeDist(refCorners[iLow], pickDir, corners[iHigh], isLeft);
258 ATH_MSG_VERBOSE("Distance "<<cornerLowD<<"/ "<<cornerHighD);
260 const Amg::Vector3D& pickPos{cornerLowD < 0 || cornerHighD < 0 ?
261 cornerLowD < cornerHighD ? corners[iLow] : corners[iHigh]: refCorners[iLow]};
262
263 ATH_MSG_VERBOSE("Low points "<<Amg::toString(corners[iLow])<<" - "<<Amg::toString(refCorners[iLow]));
264 ATH_MSG_VERBOSE("High points "<<Amg::toString(corners[iHigh])<<" - "<<Amg::toString(refCorners[iHigh]));
265
267 newTrapBounds[iHigh] = pickPos + Amg::intersect<3>(pickPos, pickDir, Amg::Vector3D::UnitY(),
268 std::max(corners[iHigh].y(), refCorners[iHigh].y())).value_or(0.) * pickDir;
269
270 newTrapBounds[iHigh].z() = lowZ ? std::max(corners[iHigh].z(),refCorners[iHigh].z())
271 : std::min(corners[iHigh].z(), refCorners[iHigh].z());
272 newTrapBounds[iLow] = pickPos + Amg::intersect<3>(pickPos, pickDir, Amg::Vector3D::UnitY(),
273 std::min(corners[iLow].y(), refCorners[iLow].y())).value_or(0.) * pickDir;
274 newTrapBounds[iLow].z() = lowZ ? std::max(corners[iLow].z(), refCorners[iLow].z())
275 : std::min(corners[iLow].z(), refCorners[iLow].z());
276 ATH_MSG_VERBOSE("New end points "<<Amg::toString(newTrapBounds[iLow])<<" - "<<Amg::toString(newTrapBounds[iHigh]));
277 }
278 }
279 if (msgLvl(MSG::VERBOSE)) {
280 std::stringstream debugStr{};
281 for (const Amg::Vector3D& edge : newTrapBounds) {
282 debugStr<<"***** "<<Amg::toString(edge)<<std::endl;
283 }
284 ATH_MSG_VERBOSE("#############################################################"<<std::endl<<
285 debugStr.str()<<"#############################################################");
286 }
288 const double halfY = 0.5*std::max(newTrapBounds[1].y() - newTrapBounds[0].y(),
289 newTrapBounds[3].y() - newTrapBounds[2].y());
290 const double lHalfX = 0.5*std::abs(newTrapBounds[3].x() - newTrapBounds[1].x());
291 const double sHalfX = 0.5*std::abs(newTrapBounds[2].x() - newTrapBounds[0].x());
292 const double halfZ = 0.5*std::abs(newTrapBounds[4].z() - newTrapBounds[0].z());
293 ATH_MSG_VERBOSE("New bounds "<<sHalfX<<"/"<<lHalfX<<", y:"<<halfY<<", "<<halfZ);
294 if (std::abs(lHalfX - sHalfX) > Acts::s_epsilon) {
295 envelopeBounds = volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(sHalfX, lHalfX, halfY, halfZ);
296 } else {
297 envelopeBounds = volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(sHalfX, halfY, halfZ);
298 }
299 ATH_MSG_VERBOSE(toString(chambEle)<<" "<<(*envelopeBounds));
300
302 const Amg::Transform3D centerShift = centerTrapezoid(newTrapBounds);
303 newCentreTrf = centerShift * newCentreTrf;
304 ATH_MSG_VERBOSE("New trapezoid centering "<<Amg::toString(centerShift)<<" combined: "
305 <<Amg::toString(newCentreTrf));
306 }
307 ATH_MSG_DEBUG("Done");
308 return std::make_tuple(newCentreTrf.inverse(),
309 enlargeBounds(*envelopeBounds, margin, volBoundSet),
310 surfaceBounds(*envelopeBounds, surfBoundSet));
311}
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)
Amg::Transform3D axisRotation(const MuonReadoutElement *re)
Orientation of the readout element coordinate system x-axis: Points towards the sky y-axis: Points al...
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 117 of file ChamberAssembleTool.cxx.

117 {
118 return chamber->bounds();
119}

◆ 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 81 of file ChamberAssembleTool.cxx.

82 {
83
84 switch(chambEle->detectorType()) {
86 const auto* techEle = static_cast<const MdtReadoutElement*>(chambEle);
87 const auto& pars = techEle->getParameters();
88 if (std::abs(pars.shortHalfX - pars.longHalfX) < Acts::s_epsilon) {
89 return volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(pars.shortHalfX, pars.halfY, pars.halfHeight);
90 }
91 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.shortHalfX, pars.longHalfX,
92 pars.halfY, pars.halfHeight );
94 const auto* techEle = static_cast<const RpcReadoutElement*>(chambEle);
95 const auto& pars = techEle->getParameters();
96 return volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(pars.halfWidth, pars.halfLength, pars.halfThickness);
98 const auto* techEle = static_cast<const TgcReadoutElement*>(chambEle);
99 const auto& pars = techEle->getParameters();
100 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.halfWidthShort, pars.halfWidthLong,
101 pars.halfHeight, pars.halfThickness );
103 const auto* techEle = static_cast<const sTgcReadoutElement*>(chambEle);
104 const auto& pars = techEle->getParameters();
105 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.sHalfChamberLength, pars.lHalfChamberLength,
106 pars.halfChamberHeight, pars.halfChamberTck );
108 const auto* techEle = static_cast<const MmReadoutElement*>(chambEle);
109 const auto& pars = techEle->getParameters();
110 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.halfShortWidth, pars.halfLongWidth,
111 pars.halfHeight, pars.halfThickness );
112 } default:
113 THROW_EXCEPTION("Unsupported detector type "<<to_string(chambEle->detectorType()));
114 }
115 return nullptr;
116}
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 313 of file ChamberAssembleTool.cxx.

313 {
314 ATH_CHECK(m_idHelperSvc.retrieve());
316 auto mdtStationIndex = [this] (const std::string& stName) {
317 return m_idHelperSvc->hasMDT() ? m_idHelperSvc->mdtIdHelper().stationNameIndex(stName) : -1;
318 };
319 auto tgcStationIndex = [this] (const std::string& stName) {
320 return m_idHelperSvc->hasTGC() ? m_idHelperSvc->tgcIdHelper().stationNameIndex(stName) : -1;
321 };
322
323 const std::unordered_set<int> stIndicesEM{mdtStationIndex("EML"), mdtStationIndex("EMS"),
324 tgcStationIndex("T1E"), tgcStationIndex("T1F"),
325 tgcStationIndex("T2E"), tgcStationIndex("T2F"),
326 tgcStationIndex("T3E"), tgcStationIndex("T3F")};
327
328
329 std::unordered_set<Identifier> BIS78_ids{};
330 auto fillBIS78 = [&BIS78_ids, this](const MuonIdHelper& idHelper) {
331 const int BIS = idHelper.stationNameIndex("BIS");
332 std::copy_if(idHelper.detectorElement_begin(), idHelper.detectorElement_end(), std::inserter(BIS78_ids, BIS78_ids.end()),
333 [&](const Identifier& detId){
334 int stEta = idHelper.stationEta(detId);
335 if (m_isRun4) {
336 stEta = std::abs(stEta);
337 }
338 return stEta >= 7 && idHelper.stationName(detId) == BIS;
339 });
340 };
341 if (m_idHelperSvc->hasMDT()) {
342 fillBIS78(m_idHelperSvc->mdtIdHelper());
343 }
344 if (m_idHelperSvc->hasRPC()) {
345 fillBIS78(m_idHelperSvc->rpcIdHelper());
346 }
347
348 std::vector<MuonReadoutElement*> allReadOutEles = mgr.getAllReadoutElements();
349
350 std::vector<chamberArgs> envelopeCandidates{};
351
353 for (const MuonReadoutElement* readOutEle : allReadOutEles) {
354 std::vector<chamberArgs>::iterator exist = std::ranges::find_if(envelopeCandidates,
355 [this, readOutEle, &stIndicesEM](const chamberArgs& args){
356 const MuonReadoutElement* refEle = args.detEles.front();
357 const Identifier refId = refEle->identify();
358 const Identifier testId = readOutEle->identify();
361 if (Acts::copySign(1, refEle->stationEta()) *
362 Acts::copySign(1, readOutEle->stationEta()) < 0) {
363 return false;
364 }
366 if (m_idHelperSvc->sector(testId) != m_idHelperSvc->sector(refId)) {
367 return false;
368 }
369 if (stIndicesEM.count(readOutEle->stationName()) &&
370 stIndicesEM.count(refEle->stationName())) {
371 return true;
372 }
373 // /// Summarize all readout element in the same sector & layer
375 return readOutEle->chamberIndex() == refEle->chamberIndex();
376 });
378 if (exist == envelopeCandidates.end()) {
379 ATH_MSG_VERBOSE("Open envelope "<<(envelopeCandidates.size()+1)
380 <<" for "<<m_idHelperSvc->toStringDetEl(readOutEle->identify())
381 <<", sector: "<<m_idHelperSvc->sector(readOutEle->identify())
382 <<", chIdx: "<<Muon::MuonStationIndex::chName(readOutEle->chamberIndex()));
383 envelopeCandidates.emplace_back().detEles.push_back(readOutEle);
384 } else {
385 ATH_MSG_VERBOSE("Attach "<<m_idHelperSvc->toStringDetEl(readOutEle->identify())
386 <<", sector: "<<m_idHelperSvc->sector(readOutEle->identify())
387 <<", chIdx: "<<Muon::MuonStationIndex::chName(readOutEle->chamberIndex())<<" to envelope "
388 <<(std::distance(envelopeCandidates.begin(), exist) + 1)<<". ");
389 exist->detEles.push_back(readOutEle);
390 }
391 }
393 ActsTrk::GeometryContext gctx{};
394
395
396 Acts::VolumeBoundFactory volBoundSet{};
397 Acts::SurfaceBoundFactory surfBoundSet{};
398 unsigned candId{0};
399 for (chamberArgs& candidate : envelopeCandidates) {
400 std::unordered_set<Identifier> reIds{};
401
402 ATH_MSG_VERBOSE("New envelope candidate ");
404 SpectrometerSector::defineArgs sectorArgs{};
405 sectorArgs.id = (++candId);
406 using namespace Muon::MuonStationIndex;
407 std::vector<std::vector<const MuonReadoutElement*>> chamberElements{};
408 if (toStationIndex(candidate.detEles.front()->chamberIndex()) != StIndex::EI) {
410 std::map<PVConstLink, std::vector<const MuonReadoutElement*>> stationMap{};
412 for (const MuonReadoutElement* re : candidate.detEles) {
415 if (BIS78_ids.count(re->identify())) {
416 stationMap[re->getMaterialGeom()].push_back(re);
417 } else {
418 stationMap[re->getMaterialGeom()->getParent()].push_back(re);
419 }
420 }
421 for (auto& [parent, stationEles ]: stationMap){
422 chamberElements.push_back(std::move(stationEles));
423 }
424 } else {
427 std::vector<std::vector<const MuonReadoutElement*>> endcapEles(2);
428
429 for (const MuonReadoutElement* sortMe : candidate.detEles){
430 if (sortMe->detectorType() == ActsTrk::DetectorType::Tgc) {
431 endcapEles.emplace_back(1, sortMe);
432 } else {
433 endcapEles[sortMe->detectorType() == ActsTrk::DetectorType::sTgc ||
434 sortMe->detectorType() == ActsTrk::DetectorType::Mm].push_back(sortMe);
435 }
436 }
437 for (auto& stationEles : endcapEles) {
438 if (!stationEles.empty()) {
439 chamberElements.push_back(std::move(stationEles));
440 }
441 }
442 }
443
444 for (auto& detEles: chamberElements) {
445 const MuonReadoutElement* refEle = detEles.front();
446 const Amg::Transform3D toChambCentre = axisRotation(refEle) * refEle->globalToLocalTrans(gctx);
447 ATH_MSG_VERBOSE("New chamber candidate "<<m_idHelperSvc->toStringChamber(refEle->identify()));
448 const auto[chamberCentre, chamberBox, planeBounds] = boundingBox(gctx, detEles, toChambCentre, volBoundSet,
449 surfBoundSet, 0.*Gaudi::Units::cm);
450 chamberArgs chambArgs{};
451 chambArgs.detEles = std::move(detEles);
452 chambArgs.bounds = chamberBox;
453 chambArgs.surface = Acts::Surface::makeShared<Acts::PlaneSurface>(toChambCentre.inverse() * chamberCentre, planeBounds);
454 const Chamber* newChamber {sectorArgs.chambers.emplace_back(std::make_unique<Chamber>(std::move(chambArgs))).get()};
455 for (const MuonReadoutElement* re : newChamber->readoutEles()) {
456 reIds.insert(re->identify());
457 mgr.getReadoutElement(re->identify())->setChamberLink(newChamber);
458 ATH_MSG_VERBOSE("Chamber element: "<<m_idHelperSvc->toStringDetEl(re->identify()));
459
460 }
461 ATH_MSG_VERBOSE("Created new chamber: "<<(*newChamber));
462 }
463 std::ranges::sort(sectorArgs.chambers, [](const SpectrometerSector::ChamberPtr& a,
465 return (*a) < (*b);
466 });
467
468 const Amg::Transform3D toCenter = sectorArgs.chambers.front()->globalToLocalTrans(gctx);
469 const auto [envelopeCentre, envelopeBox, envelopePlane] = boundingBox(gctx, sectorArgs.chambers, toCenter,
470 volBoundSet, surfBoundSet, 2.* Gaudi::Units::cm);
471
472 sectorArgs.bounds = envelopeBox;
473 sectorArgs.surface = Acts::Surface::makeShared<Acts::PlaneSurface>(toCenter.inverse() * envelopeCentre, envelopePlane);
474
475 const Amg::Transform3D globalToSector = sectorArgs.surface->transform(gctx.context()).inverse();
476
478 for (auto & chamber : sectorArgs.chambers){
479 // split by readout elements - MDT multilayers and trigger chambers for the sector
480 for (auto & RE : chamber->readoutEles()){
481 // get the center of the element in the sector frame
482 const Amg::Transform3D& chamberToGlobal{RE->localToGlobalTrans(gctx)};
483 const Amg::Vector3D origin = (globalToSector * chamberToGlobal).translation();
484 // and then add the bounds of the element - this is technology dependent
485 sectorArgs.detectorLocs.emplace_back(origin, RE, boundingBox(RE, volBoundSet));
486 }
487 }
489 auto newSector = std::make_unique<SpectrometerSector>(std::move(sectorArgs));
490
491 for (const Identifier& chId : reIds) {
492 mgr.getReadoutElement(chId)->setSectorLink(newSector.get());
493 }
494 mgr.addSpectrometerSector(std::move(newSector));
495 }
496 return StatusCode::SUCCESS;
497}
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:31

◆ 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 142 of file ChamberAssembleTool.cxx.

142 {
143
144 static constexpr double maxSize = 200._km;
145 double minX{maxSize}, maxX{-maxSize}, minY{maxSize}, maxY{-maxSize}, minZ{maxSize}, maxZ{-maxSize};
146 for (const Amg::Vector3D& corner : corners) {
147 minX = std::min(corner.x(), minX); maxX = std::max(corner.x(), maxX);
148 minY = std::min(corner.y(), minY); maxY = std::max(corner.y(), maxY);
149 minZ = std::min(corner.z(), minZ); maxZ = std::max(corner.z(), maxZ);
150 }
151 return Amg::getTranslate3D(-0.5*(minX + maxX), -0.5*(minY + maxY), -0.5*(minZ + maxZ));
152}
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 130 of file ChamberAssembleTool.cxx.

131 {
132 std::array<Amg::Vector3D, 8> toRet{make_array<Amg::Vector3D,8>(Amg::Vector3D::Zero())};
133 const std::array<Amg::Vector3D, 4> plane = cornerPointsPlane(localToGlob, bounds);
134 for (unsigned int z : {0, 1}) {
135 const Amg::Vector3D stretch = halfZ(bounds) * (z ? 1. : -1.) * Amg::Vector3D::UnitZ();
136 for (unsigned int b = 0; b < plane.size(); ++b){
137 toRet[b + z * plane.size()] = plane[b] + stretch;
138 }
139 }
140 return toRet;
141}
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 122 of file ChamberAssembleTool.cxx.

123 {
124 std::array<Amg::Vector3D,4> planePoints{localToGlob * Amg::Vector3D(-halfXlowY(bounds), - halfY(bounds), 0.),
125 localToGlob * Amg::Vector3D(-halfXhighY(bounds), halfY(bounds), 0.),
126 localToGlob * Amg::Vector3D( halfXlowY(bounds), -halfY(bounds), 0.),
127 localToGlob * Amg::Vector3D( halfXhighY(bounds), halfY(bounds), 0.)};
128 return planePoints;
129}
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 155 of file ChamberAssembleTool.cxx.

157 {
158 if (enlargeMe.type() == Acts::VolumeBounds::BoundsType::eCuboid) {
159 return volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(halfXlowY(enlargeMe) + 0.5*margin,
160 halfY(enlargeMe) + 0.5*margin,
161 halfZ(enlargeMe) + 0.5*margin);
162 } else if (enlargeMe.type() == Acts::VolumeBounds::BoundsType::eTrapezoid) {
163 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(halfXlowY(enlargeMe) + 0.5*margin,
164 halfXhighY(enlargeMe) + 0.5*margin,
165 halfY(enlargeMe) + 0.5*margin,
166 halfZ(enlargeMe) + 0.5*margin);
167 }
168 return nullptr;
169}

◆ 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 171 of file ChamberAssembleTool.cxx.

172 {
173 if (volBounds.type() == Acts::VolumeBounds::BoundsType::eCuboid) {
174 return surfBoundSet.makeBounds<Acts::RectangleBounds>(halfXlowY(volBounds), halfY(volBounds));
175 } else if (volBounds.type() == Acts::VolumeBounds::BoundsType::eTrapezoid) {
176 return surfBoundSet.makeBounds<Acts::TrapezoidBounds>(halfXlowY(volBounds) , halfXhighY(volBounds) , halfY(volBounds));
177 }
178 return nullptr;
179}

◆ 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 70 of file ChamberAssembleTool.cxx.

73 {
75 const Amg::Vector3D normal = lineDir.cross((leftEdge ? 1. : -1.) *Amg::Vector3D::UnitZ());
76 const Amg::Vector3D closest = linePos + lineDir.dot(testMe - linePos) * lineDir;
77 return normal.dot(testMe - closest);
78}

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: