17 #include <Acts/Geometry/CuboidVolumeBounds.hpp>
18 #include <Acts/Geometry/TrapezoidVolumeBounds.hpp>
19 #include <Acts/Surfaces/RectangleBounds.hpp>
20 #include <Acts/Surfaces/TrapezoidBounds.hpp>
21 #include <Acts/Surfaces/PlaneSurface.hpp>
23 #include <Acts/Geometry/Volume.hpp>
25 #include <GeoModelHelpers/TransformToStringConverter.h>
26 #include <GeoModelKernel/GeoDefinitions.h>
29 constexpr
int sign(
int numb) {
30 return numb > 0 ? 1 : (numb == 0 ? 0 : -1);
48 return Amg::Transform3D::Identity();
54 using BoundEnum = Acts::TrapezoidVolumeBounds::BoundValues;
74 const Amg::Vector3D normal = lineDir.cross((leftEdge ? 1. : -1.) *Amg::Vector3D::UnitZ());
75 const Amg::Vector3D closest = linePos + lineDir.dot(testMe - linePos) * lineDir;
76 return normal.dot(testMe - closest);
81 Acts::VolumeBoundFactory& volBoundSet) {
86 const auto&
pars = techEle->getParameters();
87 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(
pars.shortHalfX,
pars.longHalfX,
92 const auto&
pars = techEle->getParameters();
93 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(
pars.halfWidth,
pars.halfWidth,
94 pars.halfLength,
pars.halfThickness);
98 const auto&
pars = techEle->getParameters();
99 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(
pars.halfWidthShort,
pars.halfWidthLong,
100 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 );
110 const auto&
pars = techEle->getParameters();
111 return volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(
pars.halfShortWidth,
pars.halfLongWidth,
112 pars.halfHeight,
pars.halfThickness );
123 std::array<Amg::Vector3D,4> planePoints{
124 localToGlob *
Amg::Vector3D(-bounds.get(BoundEnum::eHalfLengthXnegY), -bounds.get(BoundEnum::eHalfLengthY), 0. ),
125 localToGlob *
Amg::Vector3D(-bounds.get(BoundEnum::eHalfLengthXposY), bounds.get(BoundEnum::eHalfLengthY), 0. ),
126 localToGlob *
Amg::Vector3D(bounds.get(BoundEnum::eHalfLengthXnegY), -bounds.get(BoundEnum::eHalfLengthY), 0. ),
127 localToGlob *
Amg::Vector3D(bounds.get(BoundEnum::eHalfLengthXposY), bounds.get(BoundEnum::eHalfLengthY), 0. ),
135 for (
unsigned int z : {0, 1}){
136 const double sign {
z ? 1. : -1.};
137 const Amg::Vector3D stretch = (
sign * bounds.get(BoundEnum::eHalfLengthZ)) * Amg::Vector3D::UnitZ();
138 for (
unsigned int b = 0;
b < plane.size(); ++
b){
139 toRet[
b +
z * plane.size()] = plane[
b] + stretch;
147 double minX{maxSize}, maxX{-maxSize}, minY{maxSize}, maxY{-maxSize}, minZ{maxSize}, maxZ{-maxSize};
162 const std::vector<const MuonReadoutElement*>& readoutEles,
164 Acts::VolumeBoundFactory& volBoundSet,
165 Acts::SurfaceBoundFactory& surfBoundSet,
166 const double margin)
const {
173 chambEle->localToGlobalTrans(gctx) *
174 axisRotation(chambEle->detectorType()).inverse();
176 if (!envelopeBounds) {
177 envelopeBounds = bounds;
184 GeoTrf::CoordEulerAngles rotAngles = GeoTrf::getCoordRotationAngles(
trf);
185 if (std::abs(rotAngles.gamma - 180.*
Gaudi::Units::deg)< std::numeric_limits<float>::epsilon()){
188 if (std::abs(rotAngles.alpha - 180.*
Gaudi::Units::deg)< std::numeric_limits<float>::epsilon()){
192 const std::array<Amg::Vector3D, 8> corners =
cornerPoints(
trf, *bounds);
194 Acts::Volume volume{Amg::Transform3D::Identity(), envelopeBounds};
196 if (std::ranges::find_if(corners, [&volume](
const Amg::Vector3D&
v) {
197 return !volume.inside(
v);}) == corners.end()) {
199 <<(*
boundingBox(chambEle, volBoundSet))<<
" fully contained. ");
203 std::stringstream debugStr{};
211 const std::array<Amg::Vector3D, 8> refCorners{
cornerPoints(Amg::Transform3D::Identity(), *envelopeBounds)};
213 std::array<Amg::Vector3D, 8> newTrapBounds{make_array<Amg::Vector3D, 8>(
Amg::Vector3D::Zero())};
216 for (
unsigned lowZ : {0, 4}) {
217 for (
bool isLeft : {
false,
true}) {
219 const size_t iHigh = 1 + (!isLeft)*2 + lowZ;
220 const size_t iLow = 0 + (!isLeft)*2 + lowZ;
222 const Amg::Vector3D dirRef{projectIntoXY(refCorners[iHigh] - refCorners[iLow]).unit()};
223 const Amg::Vector3D dirCan{projectIntoXY(corners[iHigh] - corners[iLow]).unit()};
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());
260 std::stringstream debugStr{};
264 ATH_MSG_VERBOSE(
"#############################################################"<<std::endl<<
265 debugStr.str()<<
"#############################################################");
268 const double halfY = 0.5*
std::max(newTrapBounds[1].
y() - newTrapBounds[0].
y(),
269 newTrapBounds[3].
y() - newTrapBounds[2].
y());
270 const double lHalfX = 0.5*(newTrapBounds[3].x() - newTrapBounds[1].x());
271 const double sHalfX = 0.5*(newTrapBounds[2].x() - newTrapBounds[0].x());
272 const double halfZ = 0.5*(newTrapBounds[4].z() - newTrapBounds[0].z());
273 envelopeBounds = volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(sHalfX, lHalfX, halfY, halfZ);
278 newCentreTrf = centerShift * newCentreTrf;
284 volBoundSet.makeBounds<Acts::TrapezoidVolumeBounds>(envelopeBounds->get(BoundEnum::eHalfLengthXnegY)+margin,
285 envelopeBounds->get(BoundEnum::eHalfLengthXposY)+margin,
286 envelopeBounds->get(BoundEnum::eHalfLengthY)+margin,
287 envelopeBounds->get(BoundEnum::eHalfLengthZ)+margin);
289 if (std::abs(envelopeBounds->get(BoundEnum::eHalfLengthXnegY) -
290 envelopeBounds->get(BoundEnum::eHalfLengthXposY)) > margin) {
291 surfToReturn = surfBoundSet.makeBounds<Acts::TrapezoidBounds>(envelopeBounds->get(BoundEnum::eHalfLengthXposY),
292 envelopeBounds->get(BoundEnum::eHalfLengthXnegY),
293 envelopeBounds->get(BoundEnum::eHalfLengthY));
295 const double maxX =
std::max(envelopeBounds->get(BoundEnum::eHalfLengthXnegY),
296 envelopeBounds->get(BoundEnum::eHalfLengthXposY));
297 surfToReturn = surfBoundSet.makeBounds<Acts::RectangleBounds>(maxX, envelopeBounds->get(BoundEnum::eHalfLengthY));
299 return std::make_tuple(newCentreTrf.inverse(), volToReturn, surfToReturn);
307 auto mdtStationIndex = [
this] (
const std::string&
stName) {
310 auto tgcStationIndex = [
this] (
const std::string&
stName) {
314 const std::unordered_set<int> stIndicesEIL{mdtStationIndex(
"EIL"), mdtStationIndex(
"T4E")};
315 const std::unordered_set<int> stIndicesEM{mdtStationIndex(
"EML"), mdtStationIndex(
"EMS"),
316 tgcStationIndex(
"T1E"), tgcStationIndex(
"T1F"),
317 tgcStationIndex(
"T2E"), tgcStationIndex(
"T2F"),
318 tgcStationIndex(
"T3E"), tgcStationIndex(
"T3F")};
325 std::vector<MuonReadoutElement*> allReadOutEles =
mgr.getAllReadoutElements();
327 std::vector<chamberArgs> envelopeCandidates{};
332 [
this, readOutEle, &stIndicesEIL, &stIndicesEM, &BOE_ids](
const chamberArgs&
args){
335 const Identifier testId = readOutEle->identify();
356 if (isNsw(readOutEle) && isNsw(refEle))
return true;
358 if (stIndicesEM.count(readOutEle->stationName()) &&
363 if (stIndicesEIL.count(readOutEle->stationName()) &&
370 if (
exist == envelopeCandidates.end()) {
372 newChamb.
detEles.push_back(readOutEle);
373 envelopeCandidates.push_back(std::move(newChamb));
375 exist->detEles.push_back(readOutEle);
382 Acts::VolumeBoundFactory volBoundSet{};
383 Acts::SurfaceBoundFactory surfBoundSet{};
384 for (
chamberArgs& candidate : envelopeCandidates) {
385 std::unordered_set<Identifier> reIds{};
389 const auto [envelopeCentre, envelopeBox, envelopePlane] =
boundingBox(gctx, candidate.detEles, toCenter,
390 volBoundSet, surfBoundSet);
394 sectorArgs.
bounds = envelopeBox;
395 sectorArgs.surface = Acts::Surface::makeShared<Acts::PlaneSurface>(toCenter.inverse() * envelopeCentre, envelopePlane);
397 if (!isNsw(candidate.detEles.front())) {
399 std::map<PVConstLink, std::vector<const MuonReadoutElement*>> stationMap{};
402 stationMap[
re->getMaterialGeom()->getParent()].push_back(
re);
405 for (
auto& [
parent, detEles]: stationMap) {
409 const auto[chamberCentre, chamberBox, planeBounds] =
boundingBox(gctx, detEles, toChambCentre, volBoundSet,
412 chambArgs.
detEles =std::move(detEles);
413 chambArgs.bounds = chamberBox;
414 chambArgs.surface = Acts::Surface::makeShared<Acts::PlaneSurface>(toChambCentre.inverse() * chamberCentre, planeBounds);
415 const Chamber* newChamber {sectorArgs.chambers.emplace_back(std::make_unique<Chamber>(std::move(chambArgs))).get()};
417 reIds.insert(
re->identify());
418 mgr.getReadoutElement(
re->identify())->setChamberLink(newChamber);
425 const auto[chamberCentre, chamberBox, planeBounds] =
boundingBox(gctx, candidate.detEles, toChambCentre,
428 chambArgs.
detEles = candidate.detEles;
429 chambArgs.bounds = chamberBox;
430 chambArgs.surface = Acts::Surface::makeShared<Acts::PlaneSurface>(toChambCentre.inverse() * chamberCentre, planeBounds);
431 const Chamber* newChamber {sectorArgs.chambers.emplace_back(std::make_unique<Chamber>(std::move(chambArgs))).get()};
433 reIds.insert(
re->identify());
434 mgr.getReadoutElement(
re->identify())->setChamberLink(newChamber);
441 const Amg::Transform3D globalToSector = sectorArgs.surface->transform(gctx.context()).inverse();
444 for (
auto &
chamber : sectorArgs.chambers){
446 for (
auto & RE :
chamber->readoutEles()){
449 const Amg::Vector3D origin = (globalToSector * chamberToGlobal).translation();
451 sectorArgs.detectorLocs.emplace_back(origin, RE,
boundingBox(RE, volBoundSet));
454 auto newSector = std::make_unique<SpectrometerSector>(std::move(sectorArgs));
457 mgr.getReadoutElement(chId)->setSectorLink(newSector.get());
460 mgr.addSpectrometerSector(std::move(newSector));
462 return StatusCode::SUCCESS;