18 #include <Acts/Geometry/TrapezoidVolumeBounds.hpp>
19 #include <Acts/Plugins/GeoModel/GeoModelToDetectorVolume.hpp>
20 #include <GeoModelHelpers/TransformToStringConverter.h>
21 #include <GeoModelKernel/GeoDefinitions.h>
25 constexpr
int sign(
int numb) {
26 return numb > 0 ? 1 : (numb == 0 ? 0 : -1);
44 return Amg::Transform3D::Identity();
50 using BoundEnum = Acts::TrapezoidVolumeBounds::BoundValues;
70 const Amg::Vector3D normal = lineDir.cross((leftEdge ? 1. : -1.) *Amg::Vector3D::UnitZ());
71 const Amg::Vector3D closest = linePos + lineDir.dot(testMe - linePos) * lineDir;
72 return normal.dot(testMe - closest);
75 std::shared_ptr<ChamberAssembleTool::BoundType>
82 const auto&
pars = techEle->getParameters();
88 const auto&
pars = techEle->getParameters();
90 pars.halfLength,
pars.halfThickness );
94 const auto&
pars = techEle->getParameters();
96 pars.halfHeight,
pars.halfThickness );
100 const auto&
pars = techEle->getParameters();
102 pars.halfChamberHeight,
pars.halfChamberTck );
106 const auto&
pars = techEle->getParameters();
108 pars.halfHeight,
pars.halfThickness );
119 std::array<Amg::Vector3D,4> planePoints{
120 localToGlob *
Amg::Vector3D(-bounds.get(BoundEnum::eHalfLengthXnegY), -bounds.get(BoundEnum::eHalfLengthY), 0. ),
121 localToGlob *
Amg::Vector3D(-bounds.get(BoundEnum::eHalfLengthXposY), bounds.get(BoundEnum::eHalfLengthY), 0. ),
122 localToGlob *
Amg::Vector3D(bounds.get(BoundEnum::eHalfLengthXnegY), -bounds.get(BoundEnum::eHalfLengthY), 0. ),
123 localToGlob *
Amg::Vector3D(bounds.get(BoundEnum::eHalfLengthXposY), bounds.get(BoundEnum::eHalfLengthY), 0. ),
131 for (
unsigned int z : {0, 1}){
132 const double sign {
z ? 1. : -1.};
133 const Amg::Vector3D stretch = (
sign * bounds.get(BoundEnum::eHalfLengthZ)) * Amg::Vector3D::UnitZ();
134 for (
unsigned int b = 0;
b < plane.size(); ++
b){
135 toRet[
b +
z * plane.size()] = plane[
b] + stretch;
143 double minX{maxSize}, maxX{-maxSize}, minY{maxSize}, maxY{-maxSize}, minZ{maxSize}, maxZ{-maxSize};
158 const std::vector<const MuonReadoutElement*>& readoutEles,
161 const double margin)
const {
163 std::shared_ptr<BoundType> envelopeBounds{};
168 chambEle->localToGlobalTrans(gctx) *
169 axisRotation(chambEle->detectorType()).inverse();
170 std::shared_ptr<BoundType> bounds =
boundingBox(chambEle, boundSet);
171 if (!envelopeBounds) {
172 envelopeBounds = bounds;
179 GeoTrf::CoordEulerAngles rotAngles = GeoTrf::getCoordRotationAngles(
trf);
180 if (std::abs(rotAngles.gamma - 180.*
Gaudi::Units::deg)< std::numeric_limits<float>::epsilon()){
183 if (std::abs(rotAngles.alpha - 180.*
Gaudi::Units::deg)< std::numeric_limits<float>::epsilon()){
187 const std::array<Amg::Vector3D, 8> corners =
cornerPoints(
trf, *bounds);
189 Acts::Volume volume{Amg::Transform3D::Identity(), envelopeBounds};
191 if (std::ranges::find_if(corners, [&volume](
const Amg::Vector3D&
v) {
192 return !volume.inside(
v);}) == corners.end()) {
194 <<(*
boundingBox(chambEle, boundSet))<<
" fully contained. ");
198 std::stringstream debugStr{};
206 const std::array<Amg::Vector3D, 8> refCorners{
cornerPoints(Amg::Transform3D::Identity(), *envelopeBounds)};
208 std::array<Amg::Vector3D, 8> newTrapBounds{make_array<Amg::Vector3D, 8>(
Amg::Vector3D::Zero())};
211 for (
unsigned lowZ : {0, 4}) {
212 for (
bool isLeft : {
false,
true}) {
214 const size_t iHigh = 1 + (!isLeft)*2 + lowZ;
215 const size_t iLow = 0 + (!isLeft)*2 + lowZ;
217 const Amg::Vector3D dirRef{projectIntoXY(refCorners[iHigh] - refCorners[iLow]).unit()};
218 const Amg::Vector3D dirCan{projectIntoXY(corners[iHigh] - corners[iLow]).unit()};
227 const Amg::Vector3D& pickDir{(dirRef.phi() > dirCan.phi()) == isLeft ? dirRef : dirCan};
230 const double cornerLowD =
trapezoidEdgeDist(refCorners[iLow], pickDir, corners[iLow], isLeft);
231 const double cornerHighD =
trapezoidEdgeDist(refCorners[iLow], pickDir, corners[iHigh], isLeft);
234 const Amg::Vector3D& pickPos{cornerLowD < 0 || cornerHighD < 0 ?
235 cornerLowD < cornerHighD ? corners[iLow] : corners[iHigh]: refCorners[iLow]};
241 newTrapBounds[iHigh] = pickPos + Amg::intersect<3>(pickPos, pickDir, Amg::Vector3D::UnitY(),
242 std::max(corners[iHigh].
y(), refCorners[iHigh].
y())).value_or(0.) * pickDir;
244 newTrapBounds[iHigh].z() = lowZ ?
std::max(corners[iHigh].
z(),refCorners[iHigh].
z())
245 :
std::min(corners[iHigh].
z(), refCorners[iHigh].
z());
246 newTrapBounds[iLow] = pickPos + Amg::intersect<3>(pickPos, pickDir, Amg::Vector3D::UnitY(),
247 std::min(corners[iLow].
y(), refCorners[iLow].
y())).value_or(0.) * pickDir;
248 newTrapBounds[iLow].z() = lowZ ?
std::max(corners[iLow].
z(), refCorners[iLow].
z())
249 :
std::min(corners[iLow].
z(), refCorners[iLow].
z());
255 std::stringstream debugStr{};
259 ATH_MSG_VERBOSE(
"#############################################################"<<std::endl<<
260 debugStr.str()<<
"#############################################################");
263 const double halfY = 0.5*
std::max(newTrapBounds[1].
y() - newTrapBounds[0].
y(),
264 newTrapBounds[3].
y() - newTrapBounds[2].
y());
265 const double lHalfX = 0.5*(newTrapBounds[3].x() - newTrapBounds[1].x());
266 const double sHalfX = 0.5*(newTrapBounds[2].x() - newTrapBounds[0].x());
267 const double halfZ = 0.5*(newTrapBounds[4].z() - newTrapBounds[0].z());
268 envelopeBounds = boundSet.
make_bounds(sHalfX, lHalfX, halfY, halfZ);
273 newCentreTrf = centerShift * newCentreTrf;
278 envelopeBounds = boundSet.
make_bounds(envelopeBounds->get(BoundEnum::eHalfLengthXnegY)+margin,
279 envelopeBounds->get(BoundEnum::eHalfLengthXposY)+margin,
280 envelopeBounds->get(BoundEnum::eHalfLengthY)+margin,
281 envelopeBounds->get(BoundEnum::eHalfLengthZ)+margin);
282 return std::make_pair(envelopeBounds, newCentreTrf.inverse());
290 auto mdtStationIndex = [
this] (
const std::string& stName) {
293 auto tgcStationIndex = [
this] (
const std::string& stName) {
297 const std::unordered_set<int> stIndicesEIL{mdtStationIndex(
"EIL"), mdtStationIndex(
"T4E")};
298 const std::unordered_set<int> stIndicesEM{mdtStationIndex(
"EML"), mdtStationIndex(
"EMS"),
299 tgcStationIndex(
"T1E"), tgcStationIndex(
"T1F"),
300 tgcStationIndex(
"T2E"), tgcStationIndex(
"T2F"),
301 tgcStationIndex(
"T3E"), tgcStationIndex(
"T3F")};
308 std::vector<MuonReadoutElement*> allReadOutEles =
mgr.getAllReadoutElements();
310 std::vector<chamberArgs> envelopeCandidates{};
315 [
this, readOutEle, &stIndicesEIL, &stIndicesEM, &BOE_ids](
const chamberArgs&
args){
318 const Identifier testId = readOutEle->identify();
338 if (isNsw(readOutEle) && isNsw(refEle))
return true;
340 if (stIndicesEM.count(readOutEle->stationName()) &&
345 if (stIndicesEIL.count(readOutEle->stationName()) &&
352 if (
exist == envelopeCandidates.end()) {
354 newChamb.
detEles.push_back(readOutEle);
355 envelopeCandidates.push_back(std::move(newChamb));
357 exist->detEles.push_back(readOutEle);
365 for (
chamberArgs& candidate : envelopeCandidates) {
366 std::unordered_set<Identifier> reIds{};
370 const auto [envelopeBox, envelopeCentre] =
boundingBox(gctx, candidate.detEles, toCenter, boundSet);
374 sectorArgs.
bounds = envelopeBox;
375 sectorArgs.locToGlobTrf = toCenter.inverse() * envelopeCentre;
377 if (!isNsw(candidate.detEles.front())) {
379 std::map<PVConstLink, std::vector<const MuonReadoutElement*>> stationMap{};
382 stationMap[
re->getMaterialGeom()->getParent()].push_back(
re);
385 for (
auto& [
parent, detEles]: stationMap) {
391 chambArgs.
detEles =std::move(detEles);
392 chambArgs.bounds = chamberBox;
393 chambArgs.locToGlobTrf = toChambCentre.inverse() * chamberCentre;
394 const Chamber* newChamber {sectorArgs.chambers.emplace_back(std::make_unique<Chamber>(std::move(chambArgs))).get()};
396 reIds.insert(
re->identify());
397 mgr.getReadoutElement(
re->identify())->setChamberLink(newChamber);
406 chambArgs.
detEles = candidate.detEles;
407 chambArgs.bounds = chamberBox;
408 chambArgs.locToGlobTrf = toChambCentre.inverse() * chamberCentre;
409 const Chamber* newChamber {sectorArgs.chambers.emplace_back(std::make_unique<Chamber>(std::move(chambArgs))).get()};
411 reIds.insert(
re->identify());
412 mgr.getReadoutElement(
re->identify())->setChamberLink(newChamber);
419 auto globalToSector = sectorArgs.locToGlobTrf.inverse();
422 for (
auto &
chamber : sectorArgs.chambers){
424 for (
auto & RE :
chamber->readoutEles()){
426 auto chamberToGlobal = RE->localToGlobalTrans(gctx);
428 origin = globalToSector * chamberToGlobal * origin;
432 sectorArgs.detectorLocs.emplace_back(origin.y() -
MDT->getParameters().halfY,
433 origin.y() +
MDT->getParameters().halfY,
434 origin.z() -
MDT->getParameters().halfHeight,
435 origin.z() +
MDT->getParameters().halfHeight,
440 sectorArgs.detectorLocs.emplace_back(origin.y() -
RPC->getParameters().halfLength,
441 origin.y() +
RPC->getParameters().halfLength,
442 origin.z() -
RPC->getParameters().halfThickness,
443 origin.z() +
RPC->getParameters().halfThickness,
448 sectorArgs.detectorLocs.emplace_back(origin.y() -
TGC->getParameters().halfHeight,
449 origin.y() +
TGC->getParameters().halfHeight,
450 origin.z() -
TGC->getParameters().halfThickness,
451 origin.z() +
TGC->getParameters().halfThickness,
456 sectorArgs.detectorLocs.emplace_back(origin.y() -
MM->getParameters().halfHeight,
457 origin.y() +
MM->getParameters().halfHeight,
458 origin.z() -
MM->getParameters().halfThickness,
459 origin.z() +
MM->getParameters().halfThickness,
464 auto newSector = std::make_unique<SpectrometerSector>(std::move(sectorArgs));
467 mgr.getReadoutElement(chId)->setSectorLink(newSector.get());
470 mgr.addSpectrometerSector(std::move(newSector));
472 return StatusCode::SUCCESS;