82 Acts::VolumeBoundFactory& volBoundSet) {
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);
91 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.shortHalfX, pars.longHalfX,
92 pars.halfY, pars.halfHeight );
95 const auto& pars = techEle->getParameters();
96 return volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(pars.halfWidth, pars.halfLength, pars.halfThickness);
99 const auto& pars = techEle->getParameters();
100 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.halfWidthShort, pars.halfWidthLong,
101 pars.halfHeight, pars.halfThickness );
104 const auto& pars = techEle->getParameters();
105 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.sHalfChamberLength, pars.lHalfChamberLength,
106 pars.halfChamberHeight, pars.halfChamberTck );
109 const auto& pars = techEle->getParameters();
110 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.halfShortWidth, pars.halfLongWidth,
111 pars.halfHeight, pars.halfThickness );
183 const std::vector<ReObjType>& constituents,
185 Acts::VolumeBoundFactory& volBoundSet,
186 Acts::SurfaceBoundFactory& surfBoundSet,
187 const double margin)
const
188 requires (Acts::PointerConcept<ReObjType>){
191 ATH_MSG_DEBUG(
"Conrstuct a new "<<
typeid(Acts::RemovePointer_t<ReObjType>).name()<<
" object.");
193 for (
const auto& chambEle : constituents) {
195 chambEle->localToGlobalTrans(gctx) *
200 GeoTrf::CoordEulerAngles rotAngles = GeoTrf::getCoordRotationAngles(trf);
201 if (std::abs(rotAngles.gamma - 180._degree)< Acts::s_epsilon){
204 if (std::abs(rotAngles.alpha - 180._degree)< Acts::s_epsilon){
208 if (!envelopeBounds) {
209 envelopeBounds = bounds;
215 const std::array<Amg::Vector3D, 8> corners =
cornerPoints(trf, *bounds);
218 if (std::ranges::none_of(corners, [&envelopeBounds](
const Amg::Vector3D& v) {
219 return !envelopeBounds->inside(v);
222 <<(*
boundingBox(chambEle, volBoundSet))<<
" fully contained. ");
225 if (msgLvl(MSG::VERBOSE)) {
226 std::stringstream debugStr{};
230 ATH_MSG_VERBOSE(
toString(chambEle)<<
" corner points "<<GeoTrf::toString(trf,
true)<<std::endl<<debugStr.str());
233 const std::array<Amg::Vector3D, 8> refCorners{
cornerPoints(Amg::Transform3D::Identity(), *envelopeBounds)};
238 for (
unsigned lowZ : {0, 4}) {
239 for (
bool isLeft : {
false,
true}) {
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()};
249 <<
" "<<dirRef.phi() / Gaudi::Units::deg <<
" --- "<<
toString(chambEle)<<
" "
250 <<
Amg::toString(dirCan)<<
", phi: "<<dirCan.phi() / Gaudi::Units::deg);
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);
260 const Amg::Vector3D& pickPos{cornerLowD < 0 || cornerHighD < 0 ?
261 cornerLowD < cornerHighD ? corners[iLow] : corners[iHigh]: refCorners[iLow]};
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;
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());
279 if (msgLvl(MSG::VERBOSE)) {
280 std::stringstream debugStr{};
284 ATH_MSG_VERBOSE(
"#############################################################"<<std::endl<<
285 debugStr.str()<<
"#############################################################");
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());
294 if (std::abs(lHalfX - sHalfX) > Acts::s_epsilon) {
295 envelopeBounds = volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(sHalfX, lHalfX,
halfY,
halfZ);
297 envelopeBounds = volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(sHalfX,
halfY,
halfZ);
303 newCentreTrf = centerShift * newCentreTrf;
308 return std::make_tuple(newCentreTrf.inverse(),
316 auto mdtStationIndex = [
this] (
const std::string& stName) {
319 auto tgcStationIndex = [
this] (
const std::string& stName) {
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")};
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()),
334 int stEta = idHelper.stationEta(detId);
336 stEta = std::abs(stEta);
338 return stEta >= 7 && idHelper.stationName(detId) ==
BIS;
341 if (m_idHelperSvc->hasMDT()) {
342 fillBIS78(m_idHelperSvc->mdtIdHelper());
344 if (m_idHelperSvc->hasRPC()) {
345 fillBIS78(m_idHelperSvc->rpcIdHelper());
348 std::vector<MuonReadoutElement*> allReadOutEles =
mgr.getAllReadoutElements();
350 std::vector<chamberArgs> envelopeCandidates{};
354 std::vector<chamberArgs>::iterator
exist = std::ranges::find_if(envelopeCandidates,
355 [
this, readOutEle, &stIndicesEM](
const chamberArgs& args){
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) {
366 if (m_idHelperSvc->sector(testId) != m_idHelperSvc->sector(refId)) {
369 if (stIndicesEM.count(readOutEle->stationName()) &&
370 stIndicesEM.count(refEle->stationName())) {
375 return readOutEle->chamberIndex() == refEle->chamberIndex();
378 if (exist == envelopeCandidates.end()) {
380 <<
" for "<<m_idHelperSvc->toStringDetEl(readOutEle->identify())
381 <<
", sector: "<<m_idHelperSvc->sector(readOutEle->identify())
383 envelopeCandidates.emplace_back().detEles.push_back(readOutEle);
385 ATH_MSG_VERBOSE(
"Attach "<<m_idHelperSvc->toStringDetEl(readOutEle->identify())
386 <<
", sector: "<<m_idHelperSvc->sector(readOutEle->identify())
388 <<(std::distance(envelopeCandidates.begin(), exist) + 1)<<
". ");
389 exist->detEles.push_back(readOutEle);
393 ActsTrk::GeometryContext gctx{};
396 Acts::VolumeBoundFactory volBoundSet{};
397 Acts::SurfaceBoundFactory surfBoundSet{};
399 for (
chamberArgs& candidate : envelopeCandidates) {
400 std::unordered_set<Identifier> reIds{};
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{};
415 if (BIS78_ids.count(
re->identify())) {
416 stationMap[
re->getMaterialGeom()].push_back(
re);
418 stationMap[
re->getMaterialGeom()->getParent()].push_back(
re);
421 for (
auto& [parent, stationEles ]: stationMap){
422 chamberElements.push_back(std::move(stationEles));
427 std::vector<std::vector<const MuonReadoutElement*>> endcapEles(2);
431 endcapEles.emplace_back(1, sortMe);
437 for (
auto& stationEles : endcapEles) {
438 if (!stationEles.empty()) {
439 chamberElements.push_back(std::move(stationEles));
444 for (
auto& detEles: chamberElements) {
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);
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()};
456 reIds.insert(
re->identify());
457 mgr.getReadoutElement(
re->identify())->setChamberLink(newChamber);
458 ATH_MSG_VERBOSE(
"Chamber element: "<<m_idHelperSvc->toStringDetEl(
re->identify()));
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);
472 sectorArgs.bounds = envelopeBox;
473 sectorArgs.surface = Acts::Surface::makeShared<Acts::PlaneSurface>(toCenter.inverse() * envelopeCentre, envelopePlane);
478 for (
auto & chamber : sectorArgs.chambers){
480 for (
auto & RE :
chamber->readoutEles()){
483 const Amg::Vector3D origin = (globalToSector * chamberToGlobal).translation();
485 sectorArgs.detectorLocs.emplace_back(origin, RE, boundingBox(RE, volBoundSet));
489 auto newSector = std::make_unique<SpectrometerSector>(std::move(sectorArgs));
491 for (
const Identifier& chId : reIds) {
492 mgr.getReadoutElement(chId)->setSectorLink(newSector.get());
494 mgr.addSpectrometerSector(std::move(newSector));
496 return StatusCode::SUCCESS;