62 Acts::VolumeBoundFactory& volBoundSet) {
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);
71 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.shortHalfX, pars.longHalfX,
72 pars.halfY, pars.halfHeight );
75 const auto& pars = techEle->getParameters();
76 return volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(pars.halfWidth, pars.halfLength, pars.halfThickness);
79 const auto& pars = techEle->getParameters();
80 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.halfWidthShort, pars.halfWidthLong,
81 pars.halfHeight, pars.halfThickness );
84 const auto& pars = techEle->getParameters();
85 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.sHalfChamberLength, pars.lHalfChamberLength,
86 pars.halfChamberHeight, pars.halfChamberTck );
89 const auto& pars = techEle->getParameters();
90 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(pars.halfShortWidth, pars.halfLongWidth,
91 pars.halfHeight, pars.halfThickness );
163 const std::vector<ReObjType>& constituents,
165 Acts::VolumeBoundFactory& volBoundSet,
166 Acts::SurfaceBoundFactory& surfBoundSet,
167 const double margin)
const
168 requires (Acts::PointerConcept<ReObjType>){
171 ATH_MSG_DEBUG(
"Conrstuct a new "<<
typeid(Acts::RemovePointer_t<ReObjType>).name()<<
" object.");
173 for (
const auto& chambEle : constituents) {
175 chambEle->localToGlobalTransform(gctx);
179 GeoTrf::CoordEulerAngles rotAngles = GeoTrf::getCoordRotationAngles(trf);
180 if (std::abs(rotAngles.gamma - 180._degree)< Acts::s_epsilon){
183 if (std::abs(rotAngles.alpha - 180._degree)< Acts::s_epsilon){
187 if (!envelopeBounds) {
188 envelopeBounds = bounds;
194 const std::array<Amg::Vector3D, 8> corners =
cornerPoints(trf, *bounds);
197 if (std::ranges::none_of(corners, [&envelopeBounds](
const Amg::Vector3D& v) {
198 return !envelopeBounds->inside(v);
201 <<(*
boundingBox(chambEle, volBoundSet))<<
" fully contained. ");
204 if (msgLvl(MSG::VERBOSE)) {
205 std::stringstream debugStr{};
209 ATH_MSG_VERBOSE(
toString(chambEle)<<
" corner points "<<GeoTrf::toString(trf,
true)<<std::endl<<debugStr.str());
212 const std::array<Amg::Vector3D, 8> refCorners{
cornerPoints(Amg::Transform3D::Identity(), *envelopeBounds)};
217 for (
unsigned lowZ : {0, 4}) {
218 for (
bool isLeft : {
false,
true}) {
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()};
228 <<
" "<<dirRef.phi() / Gaudi::Units::deg <<
" --- "<<
toString(chambEle)<<
" "
229 <<
Amg::toString(dirCan)<<
", phi: "<<dirCan.phi() / Gaudi::Units::deg);
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);
239 const Amg::Vector3D& pickPos{cornerLowD < 0 || cornerHighD < 0 ?
240 cornerLowD < cornerHighD ? corners[iLow] : corners[iHigh]: refCorners[iLow]};
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;
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());
258 if (msgLvl(MSG::VERBOSE)) {
259 std::stringstream debugStr{};
263 ATH_MSG_VERBOSE(
"#############################################################"<<std::endl<<
264 debugStr.str()<<
"#############################################################");
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());
273 if (std::abs(lHalfX - sHalfX) > Acts::s_epsilon) {
274 envelopeBounds = volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(sHalfX, lHalfX,
halfY,
halfZ);
276 envelopeBounds = volBoundSet.makeBounds<Acts::CuboidVolumeBounds>(sHalfX,
halfY,
halfZ);
282 newCentreTrf = centerShift * newCentreTrf;
287 return std::make_tuple(newCentreTrf.inverse(),
295 auto mdtStationIndex = [
this] (
const std::string& stName) {
298 auto tgcStationIndex = [
this] (
const std::string& stName) {
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")};
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()),
313 int stEta = idHelper.stationEta(detId);
315 stEta = std::abs(stEta);
317 return stEta >= 7 && idHelper.stationName(detId) ==
BIS;
320 if (m_idHelperSvc->hasMDT()) {
321 fillBIS78(m_idHelperSvc->mdtIdHelper());
323 if (m_idHelperSvc->hasRPC()) {
324 fillBIS78(m_idHelperSvc->rpcIdHelper());
327 std::vector<MuonReadoutElement*> allReadOutEles =
mgr.getAllReadoutElements();
329 std::vector<chamberArgs> envelopeCandidates{};
333 std::vector<chamberArgs>::iterator
exist = std::ranges::find_if(envelopeCandidates,
334 [
this, readOutEle, &stIndicesEM](
const chamberArgs& args){
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) {
345 if (m_idHelperSvc->sector(testId) != m_idHelperSvc->sector(refId)) {
348 if (stIndicesEM.count(readOutEle->stationName()) &&
349 stIndicesEM.count(refEle->stationName())) {
354 return readOutEle->chamberIndex() == refEle->chamberIndex();
357 if (exist == envelopeCandidates.end()) {
359 <<
" for "<<m_idHelperSvc->toStringDetEl(readOutEle->identify())
360 <<
", sector: "<<m_idHelperSvc->sector(readOutEle->identify())
362 envelopeCandidates.emplace_back().detEles.push_back(readOutEle);
364 ATH_MSG_VERBOSE(
"Attach "<<m_idHelperSvc->toStringDetEl(readOutEle->identify())
365 <<
", sector: "<<m_idHelperSvc->sector(readOutEle->identify())
367 <<(std::distance(envelopeCandidates.begin(), exist) + 1)<<
". ");
368 exist->detEles.push_back(readOutEle);
372 ActsTrk::GeometryContext gctx{};
375 Acts::VolumeBoundFactory volBoundSet{};
376 Acts::SurfaceBoundFactory surfBoundSet{};
378 for (
chamberArgs& candidate : envelopeCandidates) {
379 std::unordered_set<Identifier> reIds{};
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{};
394 if (BIS78_ids.count(
re->identify())) {
395 stationMap[
re->getMaterialGeom()].push_back(
re);
397 stationMap[
re->getMaterialGeom()->getParent()].push_back(
re);
400 for (
auto& [parent, stationEles ]: stationMap){
401 chamberElements.push_back(std::move(stationEles));
406 std::vector<std::vector<const MuonReadoutElement*>> endcapEles(2);
410 endcapEles.emplace_back(1, sortMe);
416 for (
auto& stationEles : endcapEles) {
417 if (!stationEles.empty()) {
418 chamberElements.push_back(std::move(stationEles));
423 for (
auto& detEles: chamberElements) {
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);
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()};
435 reIds.insert(
re->identify());
436 mgr.getReadoutElement(
re->identify())->setChamberLink(newChamber);
437 ATH_MSG_VERBOSE(
"Chamber element: "<<m_idHelperSvc->toStringDetEl(
re->identify()));
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);
451 sectorArgs.bounds = envelopeBox;
452 sectorArgs.surface = Acts::Surface::makeShared<Acts::PlaneSurface>(toCenter.inverse() * envelopeCentre, envelopePlane);
457 for (
auto & chamber : sectorArgs.chambers){
459 for (
auto & RE :
chamber->readoutEles()){
462 const Amg::Vector3D origin = (globalToSector * chamberToGlobal).translation();
464 sectorArgs.detectorLocs.emplace_back(origin, RE, boundingBox(RE, volBoundSet));
468 auto newSector = std::make_unique<SpectrometerSector>(std::move(sectorArgs));
470 for (
const Identifier& chId : reIds) {
471 mgr.getReadoutElement(chId)->setSectorLink(newSector.get());
473 mgr.addSpectrometerSector(std::move(newSector));
475 return StatusCode::SUCCESS;