12 #include <GaudiKernel/IMessageSvc.h>
14 #include <type_traits>
23 #include "Acts/Surfaces/detail/LineHelper.hpp"
25 inline std::vector<std::shared_ptr<unsigned>> matchCountVec(
unsigned n) {
26 std::vector<std::shared_ptr<unsigned>>
out{};
28 for (
unsigned p = 0;
p <
n ;++
p) {
29 out.emplace_back(std::make_shared<unsigned>(0));
38 template<
class MeasType>
41 const MeasType& meas) {
43 if constexpr(std::is_same_v<MeasType, xAOD::MdtDriftCircle>) {
46 return sectorTrans * reEle->localToGlobalTrans(gctx, meas.layerHash());
53 template<
typename MeasType>
56 if constexpr (std::is_same_v<MeasType, xAOD::MdtDriftCircle>){
57 return toChamberTrans * meas.localCirclePosition();
58 }
else if constexpr (std::is_same_v<MeasType, xAOD::RpcMeasurement>){
59 return toChamberTrans * meas.localMeasurementPos();
60 }
else if constexpr (std::is_same_v<MeasType, xAOD::TgcStrip>){
61 const auto& stripLay = meas.readoutElement()->sensorLayout(meas.layerHash());
62 return toChamberTrans * stripLay->to3D(meas.template localPosition<1>()[0]*Amg::Vector2D::UnitX(),
64 }
else if constexpr (std::is_same_v<MeasType, xAOD::MMCluster>){
65 return toChamberTrans * (meas.template localPosition<1>()[
Trk::locX] * Amg::Vector3D::UnitX());
66 }
else if constexpr (std::is_same_v<MeasType, xAOD::sTgcMeasurement>){
67 if (meas.channelType() == sTgcIdHelper::sTgcChannelTypes::Strip ||
68 meas.channelType() == sTgcIdHelper::sTgcChannelTypes::Wire) {
69 return toChamberTrans * (meas.template localPosition<1>()[
Trk::locX] * Amg::Vector3D::UnitX());
72 locPos.block<2,1>(0,0) = xAOD::toEigen(meas.template localPosition<2>());
73 return toChamberTrans * locPos;
81 template <
typename PrdType>
82 double sensorHalfLength(
const PrdType& prd) {
83 const auto*
re = prd.readoutElement();
84 if constexpr(std::is_same_v<PrdType, xAOD::MdtDriftCircle>) {
85 return 0.5 *
re->activeTubeLength(prd.measurementHash());
86 }
else if constexpr(std::is_same_v<PrdType, xAOD::RpcMeasurement>) {
87 return 0.5*(prd.measuresPhi() ?
re->stripPhiLength() :
re->stripEtaLength());
88 }
else if constexpr(std::is_same_v<PrdType, xAOD::TgcStrip>) {
89 return 0.5 *
re->sensorLayout(prd.layerHash())->design().stripLength(prd.channelNumber());
90 }
else if constexpr(std::is_same_v<PrdType, xAOD::MMCluster>) {
91 return 0.5*
re->stripLayer(prd.layerHash()).design().stripLength(prd.channelNumber());
92 }
else if constexpr(std::is_same_v<PrdType, xAOD::sTgcMeasurement>) {
93 return 0.5*
re->stripLayer(prd.layerHash()).design().stripLength(prd.channelNumber());
106 return static_cast<int>(
techIdx) <
static_cast<int>(
other.techIdx);
109 return static_cast<int>(
stIdx) <
static_cast<int>(
other.stIdx);
114 return measEta + measPhi + measEtaPhi;
120 std::lock_guard guard{m_mutex};
127 if (sp.measuresEta() && sp.measuresPhi()) {
130 stats.measEta += sp.measuresEta();
131 stats.measPhi += sp.measuresPhi();
136 using KeyVal = std::pair<FieldKey, StatField>;
137 std::vector<KeyVal> sortedstats{};
138 sortedstats.reserve(m_map.size());
140 for (
const auto & [
key,
stats] : m_map){
141 sortedstats.emplace_back(std::make_pair(
key,
stats));
143 std::stable_sort(sortedstats.begin(), sortedstats.end(), [](
const KeyVal&
a,
const KeyVal&
b) {
144 return a.second.allHits() > b.second.allHits();
146 msg<<
MSG::ALWAYS<<
"###########################################################################"<<
endmsg;
147 for (
const auto & [
key,
stats] : sortedstats) {
150 <<
" "<<std::abs(
key.eta)<<(
key.eta < 0 ?
"A" :
"C")
151 <<
" "<<std::setw(8)<<
stats.measEtaPhi
152 <<
" "<<std::setw(8)<<
stats.measEta
155 msg<<
MSG::ALWAYS<<
"###########################################################################"<<
endmsg;
166 m_statCounter->dumpStatisics(msgStream());
168 return StatusCode::SUCCESS;
180 m_statCounter = std::make_unique<SpacePointStatistics>(
m_idHelperSvc.get());
182 return StatusCode::SUCCESS;
187 const std::vector<const xAOD::TgcStrip*>& phiHits)
const {
188 if (etaHits.empty() || phiHits.empty()) {
193 return ((1.*etaHits.size()) / ((1.*
re->numChannels(etaHits[0]->measurementHash())))) <
m_maxOccTgcEta &&
194 ((1.*phiHits.size()) / ((1.*
re->numChannels(phiHits[0]->measurementHash())))) <
m_maxOccTgcPhi;
198 const std::vector<const xAOD::RpcMeasurement*>& phiHits)
const {
199 if (etaHits.empty() || phiHits.empty()) {
210 const std::vector<const xAOD::sTgcMeasurement*>& phiHits)
const {
211 if (etaHits.empty() || phiHits.empty()) {
215 return ((1.*etaHits.size()) / (1.*
re->numChannels(etaHits[0]->measurementHash()))) <
m_maxOccStgcEta &&
216 ((1.*phiHits.size()) / (1.*
re->numChannels(phiHits[0]->measurementHash()))) <
m_maxOccStgcPhi;
220 const std::vector<const xAOD::MMCluster*>& )
const {
223 template <
typename PrdType>
226 const std::vector<const PrdType*>& prdsToFill,
227 std::vector<SpacePoint>& outColl)
const {
228 if (prdsToFill.empty()) {
231 const Amg::Transform3D toSectorTrans = toChamberTransform(gctx, sectorTrans, *prdsToFill.front());
235 outColl.reserve(outColl.size() + prdsToFill.size());
236 for (
const PrdType* prd: prdsToFill) {
237 SpacePoint& newSp = outColl.emplace_back(prd);
238 if constexpr (std::is_same_v<PrdType, xAOD::TgcStrip>) {
239 const bool isStrip = prd->measuresPhi();
240 const auto& stripLay = prd->readoutElement()->sensorLayout(prd->layerHash());
243 toNextSen = toSectorTrans.rotation() * stripLay->to3D(radialDesign.stripNormal(prd->channelNumber()),
isStrip);
244 sensorDir = toSectorTrans.rotation() * stripLay->to3D(radialDesign.stripDir(prd->channelNumber()),
isStrip);
246 toNextSen = toSectorTrans.rotation() * stripLay->to3D(Amg::Vector2D::UnitX(),
isStrip);
247 sensorDir = toSectorTrans.rotation() * stripLay->to3D(Amg::Vector2D::UnitY(),
isStrip);
250 newSp.
setPosition(positionInChamber(*prd, toSectorTrans));
252 auto cov = Acts::filledArray<double,3>(0.);
253 if (prd->numDimensions() == 2) {
254 if constexpr(std::is_same_v<PrdType, xAOD::RpcMeasurement>) {
255 cov[Acts::toUnderlying(
CovIdx::etaCov)] = prd->template localCovariance<2>()(0,0);
256 cov[Acts::toUnderlying(
CovIdx::phiCov)] = prd->template localCovariance<2>()(1,1);
257 }
else if constexpr(std::is_same_v<PrdType, xAOD::sTgcMeasurement>) {
258 cov[Acts::toUnderlying(
CovIdx::phiCov)] = prd->template localCovariance<2>()(0,0);
259 cov[Acts::toUnderlying(
CovIdx::etaCov)] = prd->template localCovariance<2>()(1,1);
279 template <
class ContType>
283 const ContType* measurementCont{
nullptr};
285 if (!measurementCont || measurementCont->empty()){
287 return StatusCode::SUCCESS;
292 using PrdType =
typename ContType::const_value_type;
293 using PrdVec = std::vector<PrdType>;
297 const Amg::Transform3D sectorTrans = viewer.at(0)->readoutElement()->msSector()->globalToLocalTrans(*gctx);
299 if constexpr( std::is_same_v<ContType, xAOD::MdtDriftCircleContainer>){
300 pointsInChamb.
etaHits.reserve(pointsInChamb.
etaHits.capacity() + viewer.size());
301 for (
const PrdType prd : viewer) {
302 Amg::Transform3D toChamberTrans{toChamberTransform(*gctx, sectorTrans, *prd)};
304 sp.setPosition(positionInChamber(*prd, toChamberTrans));
305 sp.setDirection(toChamberTrans.rotation().col(
Amg::z),
306 toChamberTrans.rotation().col(
Amg::y));
307 std::array<double, 3>
cov{Acts::filledArray<double,3>(0.)};
313 sp.setCovariance(std::move(
cov));
317 using EtaPhi2DHits = std::array<PrdVec, 3>;
318 std::vector<EtaPhi2DHits> hitsPerGasGap{};
319 for (
const PrdType prd : viewer) {
321 <<
", hash: "<<prd->identifierHash());
323 unsigned gapIdx = prd->gasGap() -1;
324 if constexpr (std::is_same_v<ContType, xAOD::RpcMeasurementContainer>) {
325 gapIdx = prd->readoutElement()->createHash(0, prd->gasGap(), prd->doubletPhi(),
false);
327 if (hitsPerGasGap.size() <= gapIdx) {
328 hitsPerGasGap.resize(gapIdx + 1);
331 if constexpr(std::is_same_v<ContType, xAOD::sTgcMeasContainer>) {
333 measPhi = prd->channelType() == sTgcIdHelper::sTgcChannelTypes::Wire;
334 }
else if constexpr(!std::is_same_v<ContType, xAOD::MMClusterContainer>) {
336 measPhi = prd->measuresPhi();
339 if (prd->numDimensions() == 2) {
340 hitsPerGasGap[gapIdx][2].push_back(prd);
344 PrdVec& toPush = hitsPerGasGap[gapIdx][measPhi];
345 if (toPush.capacity() == toPush.size()) {
348 toPush.push_back(prd);
351 for (
auto& [etaHits, phiHits, two2DHits] : hitsPerGasGap) {
352 ATH_MSG_DEBUG(
"Found "<<etaHits.size()<<
"/"<<phiHits.size()<<
" 1D and "<<two2DHits.size()<<
" 2D hits in chamber "<<
m_idHelperSvc->toStringDetEl(viewer.at(0)->identify()));
362 std::vector<std::shared_ptr<unsigned>> etaCounts{matchCountVec(etaHits.size())},
363 phiCounts{matchCountVec(phiHits.size())};
364 pointsInChamb.
etaHits.reserve(etaHits.size()*phiHits.size());
366 const Amg::Transform3D toSectorTransEta = toChamberTransform(*gctx,sectorTrans, *etaHits.front());
367 const Amg::Transform3D toSectorTransPhi = toChamberTransform(*gctx,sectorTrans, *phiHits.front());
371 using namespace Acts::detail::LineHelper;
372 for (
unsigned etaP = 0; etaP < etaHits.size(); ++etaP) {
374 for (
unsigned phiP = 0; phiP < phiHits.size(); ++ phiP) {
377 if (!(etaHits[etaP]->bcBitMap() & phiHits[phiP]->bcBitMap())){
380 const auto& stripLay = phiHits[phiP]->readoutElement()->sensorLayout(phiHits[phiP]->layerHash());
382 toNextDir = toSectorTransPhi.rotation() * stripLay->to3D(radialDesign.stripDir(phiHits[phiP]->channelNumber()),
true);
384 SpacePoint& newSp = pointsInChamb.
etaHits.emplace_back(etaHits[etaP], phiHits[phiP]);
387 auto spIsect = lineIntersect(positionInChamber(*etaHits[etaP], toSectorTransEta), sensorDir,
388 positionInChamber(*phiHits[phiP], toSectorTransPhi), toNextDir);
391 auto cov = Acts::filledArray<double, 3>(0.);
392 cov[Acts::toUnderlying(
CovIdx::etaCov)] = etaHits[etaP]->template localCovariance<1>()[0];
393 cov[Acts::toUnderlying(
CovIdx::phiCov)] = phiHits[phiP]->template localCovariance<1>()[0];
399 }
while (viewer.next());
400 return StatusCode::SUCCESS;
411 std::unique_ptr<SpacePointContainer> outContainer = std::make_unique<SpacePointContainer>();
413 for (
auto &[
chamber, hitsPerChamber] : preSortedContainer){
414 ATH_MSG_DEBUG(
"Fill space points for chamber "<<
chamber->identString() <<
" with "<<hitsPerChamber.etaHits.size()
415 <<
" primary and "<<hitsPerChamber.phiHits.size()<<
" phi space points.");
419 ATH_CHECK(writeHandle.record(std::move(outContainer)));
420 return StatusCode::SUCCESS;
426 splittedHits.emplace_back();
428 m_statCounter->addToStat(hitsPerChamber.etaHits);
429 m_statCounter->addToStat(hitsPerChamber.phiHits);
433 splittedHits.erase(std::remove_if(splittedHits.begin(), splittedHits.end(),
435 return bucket.size() <= 1;
436 }), splittedHits.end());
444 std::stringstream spStr{};
445 for (
const std::shared_ptr<SpacePoint>& sp : bucket){
446 spStr<<
"SpacePoint: PrimaryMeas: " <<(*sp)<<std::endl;
448 ATH_MSG_VERBOSE(
"Created a bucket, printing all spacepoints..."<<std::endl<<spStr.str());
451 finalContainer.
push_back(std::make_unique<SpacePointBucket>(std::move(bucket)));
458 auto phiPoint = std::make_shared<SpacePoint>(std::move(sp));
459 const double dY = std::sqrt(phiPoint->covariance()[Acts::toUnderlying(
CovIdx::etaCov)]);
460 const double minY = phiPoint->localPosition().y() - dY;
461 const double maxY = phiPoint->localPosition().y() + dY;
465 if (! (maxY < bucket.coveredMin() || bucket.coveredMax() < minY) ) {
466 bucket.emplace_back(phiPoint);
472 const double firstSpPos,
480 if (sortedPoints.empty() || sortedPoints.back().empty()) {
493 overlap.back()->localPosition().y());
499 const double overlapPos = pointInBucket->localPosition().y() +
500 std::sqrt(pointInBucket->covariance()[Acts::toUnderlying(
CovIdx::etaCov)]);
502 newContainer.insert(newContainer.begin(), pointInBucket);
518 return a.localPosition().
y() <
b.localPosition().y();
521 double firstPointPos =
spacePoints.front().localPosition().y();
526 if (
splitBucket(toSort, firstPointPos, splittedHits)){
528 firstPointPos = splittedHits.back().empty() ? toSort.localPosition().y() : splittedHits.back().front()->localPosition().y();
529 ATH_MSG_VERBOSE(
"New bucket: id " << splittedHits.back().bucketId() <<
" Coverage: " << firstPointPos);
531 std::shared_ptr<SpacePoint> spacePoint = std::make_shared<SpacePoint>(std::move(toSort));
532 splittedHits.back().emplace_back(spacePoint);
536 lastBucket.back()->localPosition().y());