85 Acts::VolumeBoundFactory& volBoundSet) {
90 const auto& pars = techEle->getParameters();
91 if (std::abs(pars.shortHalfX - pars.longHalfX) < Acts::s_epsilon) {
92 return volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(pars.shortHalfX, pars.halfY, pars.halfHeight);
94 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.shortHalfX, pars.longHalfX,
95 pars.halfY, pars.halfHeight );
98 const auto& pars = techEle->getParameters();
99 return volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(pars.halfWidth, pars.halfLength, pars.halfThickness);
102 const auto& pars = techEle->getParameters();
103 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.halfWidthShort, pars.halfWidthLong,
104 pars.halfHeight, pars.halfThickness );
107 const auto& pars = techEle->getParameters();
108 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.sHalfChamberLength, pars.lHalfChamberLength,
109 pars.halfChamberHeight, pars.halfChamberTck );
112 const auto& pars = techEle->getParameters();
113 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.halfShortWidth, pars.halfLongWidth,
114 pars.halfHeight, pars.halfThickness );
186 const std::vector<ReObjType>& constituents,
188 Acts::VolumeBoundFactory& volBoundSet,
189 Acts::SurfaceBoundFactory& surfBoundSet,
190 const double margin)
const
191 requires (Acts::PointerConcept<ReObjType>){
194 ATH_MSG_DEBUG(
"Conrstuct a new "<<
typeid(Acts::RemovePointer_t<ReObjType>).name()<<
" object.");
196 for (
const auto& chambEle : constituents) {
198 chambEle->localToGlobalTrans(gctx) *
203 GeoTrf::CoordEulerAngles rotAngles = GeoTrf::getCoordRotationAngles(trf);
204 if (std::abs(rotAngles.gamma - 180._degree)< Acts::s_epsilon){
207 if (std::abs(rotAngles.alpha - 180._degree)< Acts::s_epsilon){
211 if (!envelopeBounds) {
212 envelopeBounds = bounds;
218 const std::array<Amg::Vector3D, 8> corners =
cornerPoints(trf, *bounds);
221 if (std::ranges::none_of(corners, [&envelopeBounds](
const Amg::Vector3D& v) {
222 return !envelopeBounds->inside(v);
225 <<(*
boundingBox(chambEle, volBoundSet))<<
" fully contained. ");
228 if (msgLvl(MSG::VERBOSE)) {
229 std::stringstream debugStr{};
233 ATH_MSG_VERBOSE(
toString(chambEle)<<
" corner points "<<GeoTrf::toString(trf,
true)<<std::endl<<debugStr.str());
236 const std::array<Amg::Vector3D, 8> refCorners{
cornerPoints(Amg::Transform3D::Identity(), *envelopeBounds)};
241 for (
unsigned lowZ : {0, 4}) {
242 for (
bool isLeft : {
false,
true}) {
244 const size_t iHigh = 1 + (!isLeft)*2 + lowZ;
245 const size_t iLow = 0 + (!isLeft)*2 + lowZ;
247 const Amg::Vector3D dirRef{projectIntoXY(refCorners[iHigh] - refCorners[iLow]).unit()};
248 const Amg::Vector3D dirCan{projectIntoXY(corners[iHigh] - corners[iLow]).unit()};
252 <<
" "<<dirRef.phi() / Gaudi::Units::deg <<
" --- "<<
toString(chambEle)<<
" "
253 <<
Amg::toString(dirCan)<<
", phi: "<<dirCan.phi() / Gaudi::Units::deg);
256 const Amg::Vector3D& pickDir{(dirRef.phi() > dirCan.phi()) == isLeft ? dirRef : dirCan};
259 const double cornerLowD =
trapezoidEdgeDist(refCorners[iLow], pickDir, corners[iLow], isLeft);
260 const double cornerHighD =
trapezoidEdgeDist(refCorners[iLow], pickDir, corners[iHigh], isLeft);
263 const Amg::Vector3D& pickPos{cornerLowD < 0 || cornerHighD < 0 ?
264 cornerLowD < cornerHighD ? corners[iLow] : corners[iHigh]: refCorners[iLow]};
270 newTrapBounds[iHigh] = pickPos +
Amg::intersect<3>(pickPos, pickDir, Amg::Vector3D::UnitY(),
271 std::max(corners[iHigh].
y(), refCorners[iHigh].
y())).value_or(0.) * pickDir;
273 newTrapBounds[iHigh].z() = lowZ ? std::max(corners[iHigh].
z(),refCorners[iHigh].
z())
274 : std::min(corners[iHigh].
z(), refCorners[iHigh].
z());
275 newTrapBounds[iLow] = pickPos +
Amg::intersect<3>(pickPos, pickDir, Amg::Vector3D::UnitY(),
276 std::min(corners[iLow].
y(), refCorners[iLow].
y())).value_or(0.) * pickDir;
277 newTrapBounds[iLow].z() = lowZ ? std::max(corners[iLow].
z(), refCorners[iLow].
z())
278 : std::min(corners[iLow].
z(), refCorners[iLow].
z());
282 if (msgLvl(MSG::VERBOSE)) {
283 std::stringstream debugStr{};
287 ATH_MSG_VERBOSE(
"#############################################################"<<std::endl<<
288 debugStr.str()<<
"#############################################################");
291 const double halfY = 0.5*std::max(newTrapBounds[1].
y() - newTrapBounds[0].
y(),
292 newTrapBounds[3].
y() - newTrapBounds[2].
y());
293 const double lHalfX = 0.5*std::abs(newTrapBounds[3].
x() - newTrapBounds[1].
x());
294 const double sHalfX = 0.5*std::abs(newTrapBounds[2].
x() - newTrapBounds[0].
x());
295 const double halfZ = 0.5*std::abs(newTrapBounds[4].
z() - newTrapBounds[0].
z());
297 if (std::abs(lHalfX - sHalfX) > Acts::s_epsilon) {
298 envelopeBounds = volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(sHalfX, lHalfX,
halfY,
halfZ);
300 envelopeBounds = volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(sHalfX,
halfY,
halfZ);
306 newCentreTrf = centerShift * newCentreTrf;
311 return std::make_tuple(newCentreTrf.inverse(),
319 auto mdtStationIndex = [
this] (
const std::string& stName) {
322 auto tgcStationIndex = [
this] (
const std::string& stName) {
326 const std::unordered_set<int> stIndicesEM{mdtStationIndex(
"EML"), mdtStationIndex(
"EMS"),
327 tgcStationIndex(
"T1E"), tgcStationIndex(
"T1F"),
328 tgcStationIndex(
"T2E"), tgcStationIndex(
"T2F"),
329 tgcStationIndex(
"T3E"), tgcStationIndex(
"T3F")};
332 std::unordered_set<Identifier> BIS78_ids{};
333 auto fillBIS78 = [&BIS78_ids,
this](
const MuonIdHelper& idHelper) {
334 const int BIS = idHelper.stationNameIndex(
"BIS");
335 std::copy_if(idHelper.detectorElement_begin(), idHelper.detectorElement_end(), std::inserter(BIS78_ids, BIS78_ids.end()),
337 int stEta = idHelper.stationEta(detId);
339 stEta = std::abs(stEta);
341 return stEta >= 7 && idHelper.stationName(detId) ==
BIS;
344 if (m_idHelperSvc->hasMDT()) {
345 fillBIS78(m_idHelperSvc->mdtIdHelper());
347 if (m_idHelperSvc->hasRPC()) {
348 fillBIS78(m_idHelperSvc->rpcIdHelper());
351 std::vector<MuonReadoutElement*> allReadOutEles =
mgr.getAllReadoutElements();
353 std::vector<chamberArgs> envelopeCandidates{};
357 std::vector<chamberArgs>::iterator
exist = std::ranges::find_if(envelopeCandidates,
358 [
this, readOutEle, &stIndicesEM](
const chamberArgs& args){
360 const Identifier refId = refEle->identify();
361 const Identifier testId = readOutEle->identify();
364 if (
sign(refEle->stationEta()) *
sign(readOutEle->stationEta()) <0) {
368 if (m_idHelperSvc->sector(testId) != m_idHelperSvc->sector(refId)) {
371 if (stIndicesEM.count(readOutEle->stationName()) &&
372 stIndicesEM.count(refEle->stationName())) {
377 return readOutEle->chamberIndex() == refEle->chamberIndex();
380 if (exist == envelopeCandidates.end()) {
382 <<
" for "<<m_idHelperSvc->toStringDetEl(readOutEle->identify())
383 <<
", sector: "<<m_idHelperSvc->sector(readOutEle->identify())
385 envelopeCandidates.emplace_back().detEles.push_back(readOutEle);
387 ATH_MSG_VERBOSE(
"Attach "<<m_idHelperSvc->toStringDetEl(readOutEle->identify())
388 <<
", sector: "<<m_idHelperSvc->sector(readOutEle->identify())
390 <<(std::distance(envelopeCandidates.begin(), exist) + 1)<<
". ");
391 exist->detEles.push_back(readOutEle);
395 ActsTrk::GeometryContext gctx{};
398 Acts::VolumeBoundFactory volBoundSet{};
399 Acts::SurfaceBoundFactory surfBoundSet{};
401 for (
chamberArgs& candidate : envelopeCandidates) {
402 std::unordered_set<Identifier> reIds{};
407 sectorArgs.
id = (++candId);
408 using namespace Muon::MuonStationIndex;
409 std::vector<std::vector<const MuonReadoutElement*>> chamberElements{};
410 if (
toStationIndex(candidate.detEles.front()->chamberIndex()) != StIndex::EI) {
412 std::map<PVConstLink, std::vector<const MuonReadoutElement*>> stationMap{};
417 if (BIS78_ids.count(
re->identify())) {
418 stationMap[
re->getMaterialGeom()].push_back(
re);
420 stationMap[
re->getMaterialGeom()->getParent()].push_back(
re);
423 for (
auto& [parent, stationEles ]: stationMap){
424 chamberElements.push_back(std::move(stationEles));
429 std::vector<std::vector<const MuonReadoutElement*>> endcapEles(2);
433 endcapEles.emplace_back(1, sortMe);
439 for (
auto& stationEles : endcapEles) {
440 if (!stationEles.empty()) {
441 chamberElements.push_back(std::move(stationEles));
446 for (
auto& detEles: chamberElements) {
449 ATH_MSG_VERBOSE(
"New chamber candidate "<<m_idHelperSvc->toStringChamber(refEle->identify()));
450 const auto[chamberCentre, chamberBox, planeBounds] = boundingBox(gctx, detEles, toChambCentre, volBoundSet,
451 surfBoundSet, 0.*Gaudi::Units::cm);
453 chambArgs.detEles = std::move(detEles);
454 chambArgs.bounds = chamberBox;
455 chambArgs.surface = Acts::Surface::makeShared<Acts::PlaneSurface>(toChambCentre.inverse() * chamberCentre, planeBounds);
456 const Chamber* newChamber {sectorArgs.chambers.emplace_back(std::make_unique<Chamber>(std::move(chambArgs))).get()};
458 reIds.insert(
re->identify());
459 mgr.getReadoutElement(
re->identify())->setChamberLink(newChamber);
460 ATH_MSG_VERBOSE(
"Chamber element: "<<m_idHelperSvc->toStringDetEl(
re->identify()));
470 const Amg::Transform3D toCenter = sectorArgs.chambers.front()->globalToLocalTrans(gctx);
471 const auto [envelopeCentre, envelopeBox, envelopePlane] = boundingBox(gctx, sectorArgs.chambers, toCenter,
472 volBoundSet, surfBoundSet, 2.* Gaudi::Units::cm);
474 sectorArgs.bounds = envelopeBox;
475 sectorArgs.surface = Acts::Surface::makeShared<Acts::PlaneSurface>(toCenter.inverse() * envelopeCentre, envelopePlane);
480 for (
auto & chamber : sectorArgs.chambers){
482 for (
auto & RE :
chamber->readoutEles()){
485 const Amg::Vector3D origin = (globalToSector * chamberToGlobal).translation();
487 sectorArgs.detectorLocs.emplace_back(origin, RE, boundingBox(RE, volBoundSet));
491 auto newSector = std::make_unique<SpectrometerSector>(std::move(sectorArgs));
493 for (
const Identifier& chId : reIds) {
494 mgr.getReadoutElement(chId)->setSectorLink(newSector.get());
496 mgr.addSpectrometerSector(std::move(newSector));
498 return StatusCode::SUCCESS;