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());
51 template <
typename PrdType>
52 double sensorHalfLength(
const PrdType& prd) {
53 const auto*
re = prd.readoutElement();
54 if constexpr(std::is_same_v<PrdType, xAOD::MdtDriftCircle>) {
55 return 0.5 *
re->activeTubeLength(prd.measurementHash());
56 }
else if constexpr(std::is_same_v<PrdType, xAOD::RpcMeasurement>) {
57 return 0.5*(prd.measuresPhi() ?
re->stripPhiLength() :
re->stripEtaLength());
58 }
else if constexpr(std::is_same_v<PrdType, xAOD::TgcStrip>) {
59 return 0.5 *
re->sensorLayout(prd.layerHash())->design(prd.measuresPhi()).stripLength(prd.channelNumber());
60 }
else if constexpr(std::is_same_v<PrdType, xAOD::MMCluster>) {
61 return 0.5*
re->stripLayer(prd.layerHash()).design().stripLength(prd.channelNumber());
62 }
else if constexpr(std::is_same_v<PrdType, xAOD::sTgcMeasurement>) {
63 return 0.5*
re->stripLayer(prd.layerHash()).design().stripLength(prd.channelNumber());
76 return static_cast<int>(
techIdx) <
static_cast<int>(
other.techIdx);
79 return static_cast<int>(
stIdx) <
static_cast<int>(
other.stIdx);
84 return measEta + measPhi + measEtaPhi;
90 std::lock_guard guard{m_mutex};
97 if (sp.measuresEta() && sp.measuresPhi()) {
100 stats.measEta += sp.measuresEta();
101 stats.measPhi += sp.measuresPhi();
106 using KeyVal = std::pair<FieldKey, StatField>;
107 std::vector<KeyVal> sortedstats{};
108 sortedstats.reserve(m_map.size());
110 for (
const auto & [
key,
stats] : m_map){
111 sortedstats.emplace_back(std::make_pair(
key,
stats));
113 std::stable_sort(sortedstats.begin(), sortedstats.end(), [](
const KeyVal&
a,
const KeyVal&
b) {
114 return a.second.allHits() > b.second.allHits();
116 msg<<
MSG::ALWAYS<<
"###########################################################################"<<
endmsg;
117 for (
const auto & [
key,
stats] : sortedstats) {
120 <<
" "<<std::abs(
key.eta)<<(
key.eta < 0 ?
"A" :
"C")
121 <<
" "<<std::setw(8)<<
stats.measEtaPhi
122 <<
" "<<std::setw(8)<<
stats.measEta
125 msg<<
MSG::ALWAYS<<
"###########################################################################"<<
endmsg;
136 m_statCounter->dumpStatisics(msgStream());
138 return StatusCode::SUCCESS;
150 m_statCounter = std::make_unique<SpacePointStatistics>(
m_idHelperSvc.get());
152 return StatusCode::SUCCESS;
157 const std::vector<const xAOD::TgcStrip*>& phiHits)
const {
158 if (etaHits.empty() || phiHits.empty()) {
163 return ((1.*etaHits.size()) / ((1.*
re->numChannels(etaHits[0]->measurementHash())))) <
m_maxOccTgcEta &&
164 ((1.*phiHits.size()) / ((1.*
re->numChannels(phiHits[0]->measurementHash())))) <
m_maxOccTgcPhi;
168 const std::vector<const xAOD::RpcMeasurement*>& phiHits)
const {
169 if (etaHits.empty() || phiHits.empty()) {
180 const std::vector<const xAOD::sTgcMeasurement*>& phiHits)
const {
181 if (etaHits.empty() || phiHits.empty()) {
185 return ((1.*etaHits.size()) / (1.*
re->numChannels(etaHits[0]->measurementHash()))) <
m_maxOccStgcEta &&
186 ((1.*phiHits.size()) / (1.*
re->numChannels(phiHits[0]->measurementHash()))) <
m_maxOccStgcPhi;
190 const std::vector<const xAOD::MMCluster*>& )
const {
193 template <
typename PrdType>
196 const std::vector<const PrdType*>& prdsToFill,
197 std::vector<SpacePoint>& outColl)
const {
198 if (prdsToFill.empty()) {
201 const PrdType* refMeas = prdsToFill.front();
202 bool allSpArePhi{
false};
204 const Amg::Transform3D toSectorTrans = toChamberTransform(gctx, sectorTrans, *refMeas);
208 if constexpr(std::is_same_v<PrdType, xAOD::RpcMeasurement> ||
209 std::is_same_v<PrdType, xAOD::TgcStrip>) {
210 allSpArePhi = refMeas->measuresPhi();
211 const auto& stripLayout = refMeas->readoutElement()->sensorLayout(refMeas->layerHash());
212 const auto& design = stripLayout->design(allSpArePhi);
213 sensorDir = toSectorTrans.rotation() * stripLayout->to3D(design.stripDir(), allSpArePhi);
214 toNextSen = toSectorTrans.rotation() * stripLayout->to3D(design.stripNormal(), allSpArePhi);
216 sensorDir = toSectorTrans.rotation().col(
Amg::y);
217 toNextSen = toSectorTrans.rotation().col(
Amg::x);
219 outColl.reserve(outColl.size() + prdsToFill.size());
220 for (
const PrdType* prd: prdsToFill) {
221 SpacePoint& newSp = outColl.emplace_back(prd);
222 if constexpr (std::is_same_v<PrdType, xAOD::TgcStrip>) {
224 const auto& stripLayout = refMeas->readoutElement()->sensorLayout(refMeas->layerHash());
226 toNextSen = toSectorTrans.rotation() * stripLayout->to3D(radialDesign.stripNormal(prd->channelNumber()), allSpArePhi);
227 sensorDir = toSectorTrans.rotation() * stripLayout->to3D(radialDesign.stripDir(prd->channelNumber()), allSpArePhi);
230 newSp.
setPosition(toSectorTrans * prd->localMeasurementPos());
232 auto cov = Acts::filledArray<double,3>(0.);
233 if (prd->numDimensions() == 2) {
234 if constexpr(std::is_same_v<PrdType, xAOD::RpcMeasurement>) {
235 cov[Acts::toUnderlying(
CovIdx::etaCov)] = prd->template localCovariance<2>()(0,0);
236 cov[Acts::toUnderlying(
CovIdx::phiCov)] = prd->template localCovariance<2>()(1,1);
237 }
else if constexpr(std::is_same_v<PrdType, xAOD::sTgcMeasurement>) {
238 cov[Acts::toUnderlying(
CovIdx::phiCov)] = prd->template localCovariance<2>()(0,0);
239 cov[Acts::toUnderlying(
CovIdx::etaCov)] = prd->template localCovariance<2>()(1,1);
259 template <
class ContType>
263 const ContType* measurementCont{
nullptr};
265 if (!measurementCont || measurementCont->empty()){
267 return StatusCode::SUCCESS;
272 using PrdType =
typename ContType::const_value_type;
273 using PrdVec = std::vector<PrdType>;
277 const Amg::Transform3D sectorTrans = viewer.at(0)->readoutElement()->msSector()->globalToLocalTrans(*gctx);
279 if constexpr( std::is_same_v<ContType, xAOD::MdtDriftCircleContainer>) {
280 pointsInChamb.
etaHits.reserve(pointsInChamb.
etaHits.capacity() + viewer.size());
281 for (
const PrdType prd : viewer) {
282 Amg::Transform3D toChamberTrans{toChamberTransform(*gctx, sectorTrans, *prd)};
284 sp.setPosition(toChamberTrans*prd->localMeasurementPos());
285 sp.setDirection(toChamberTrans.rotation().col(
Amg::z),
286 toChamberTrans.rotation().col(
Amg::y));
287 std::array<double, 3>
cov{Acts::filledArray<double,3>(0.)};
293 sp.setCovariance(std::move(
cov));
297 using EtaPhi2DHits = std::array<PrdVec, 3>;
298 std::vector<EtaPhi2DHits> hitsPerGasGap{};
299 for (
const PrdType prd : viewer) {
301 <<
", hash: "<<prd->identifierHash());
303 unsigned gapIdx = prd->gasGap() -1;
304 if constexpr (std::is_same_v<ContType, xAOD::RpcMeasurementContainer>) {
305 gapIdx = prd->readoutElement()->createHash(0, prd->gasGap(), prd->doubletPhi(),
false);
307 if (hitsPerGasGap.size() <= gapIdx) {
308 hitsPerGasGap.resize(gapIdx + 1);
311 if constexpr(std::is_same_v<ContType, xAOD::sTgcMeasContainer>) {
313 measPhi = prd->channelType() == sTgcIdHelper::sTgcChannelTypes::Wire;
314 }
else if constexpr(!std::is_same_v<ContType, xAOD::MMClusterContainer>) {
316 measPhi = prd->measuresPhi();
319 if (prd->numDimensions() == 2) {
320 hitsPerGasGap[gapIdx][2].push_back(prd);
324 PrdVec& toPush = hitsPerGasGap[gapIdx][measPhi];
325 if (toPush.capacity() == toPush.size()) {
328 toPush.push_back(prd);
331 for (
auto& [etaHits, phiHits, two2DHits] : hitsPerGasGap) {
332 ATH_MSG_DEBUG(
"Found "<<etaHits.size()<<
"/"<<phiHits.size()<<
" 1D and "<<two2DHits.size()<<
" 2D hits in chamber "<<
m_idHelperSvc->toStringDetEl(viewer.at(0)->identify()));
342 std::vector<std::shared_ptr<unsigned>> etaCounts{matchCountVec(etaHits.size())},
343 phiCounts{matchCountVec(phiHits.size())};
344 pointsInChamb.
etaHits.reserve(pointsInChamb.
etaHits.size() + etaHits.size()*phiHits.size());
346 const PrdType firstEta{etaHits.front()};
347 const PrdType firstPhi{phiHits.front()};
349 const Amg::Transform3D toSectorTransEta = toChamberTransform(*gctx, sectorTrans, *firstEta);
350 const Amg::Transform3D toSectorTransPhi = toChamberTransform(*gctx, sectorTrans, *firstPhi);
354 if constexpr (std::is_same_v<xAOD::RpcMeasurementContainer, ContType> ||
355 std::is_same_v<xAOD::TgcStripContainer, ContType>) {
356 const auto& stripLayout = firstEta->readoutElement()->sensorLayout(firstEta->layerHash());
357 const auto& design = stripLayout->design();
358 sensorDir = toSectorTransEta.rotation() * stripLayout->to3D(design.stripDir(),
false);
359 toNextDir = toSectorTransEta.rotation() * stripLayout->to3D(design.stripNormal(),
false);
361 toNextDir = toSectorTransEta.rotation().col(
Amg::x);
362 sensorDir = toSectorTransEta.rotation().col(
Amg::y);
364 using namespace Acts::detail::LineHelper;
365 for (
unsigned etaP = 0; etaP < etaHits.size(); ++etaP) {
367 for (
unsigned phiP = 0; phiP < phiHits.size(); ++ phiP) {
369 if constexpr(std::is_same_v<xAOD::TgcStripContainer, ContType>) {
370 if (!(etaHits[etaP]->bcBitMap() & phiHits[phiP]->bcBitMap())){
373 const auto& stripLay = phiHits[phiP]->readoutElement()->sensorLayout(phiHits[phiP]->
layerHash());
375 toNextDir = toSectorTransPhi.rotation() * stripLay->to3D(radialDesign.stripDir(phiHits[phiP]->channelNumber()),
true);
377 SpacePoint& newSp = pointsInChamb.
etaHits.emplace_back(etaHits[etaP], phiHits[phiP]);
380 auto spIsect = lineIntersect(toSectorTransEta*etaHits[etaP]->localMeasurementPos(), sensorDir,
381 toSectorTransPhi*phiHits[phiP]->localMeasurementPos(), toNextDir);
384 auto cov = Acts::filledArray<double, 3>(0.);
385 cov[Acts::toUnderlying(
CovIdx::etaCov)] = etaHits[etaP]->template localCovariance<1>()[0];
386 cov[Acts::toUnderlying(
CovIdx::phiCov)] = phiHits[phiP]->template localCovariance<1>()[0];
393 }
while (viewer.next());
394 return StatusCode::SUCCESS;
405 std::unique_ptr<SpacePointContainer> outContainer = std::make_unique<SpacePointContainer>();
407 for (
auto &[
chamber, hitsPerChamber] : preSortedContainer){
408 ATH_MSG_DEBUG(
"Fill space points for chamber "<<
chamber->identString() <<
" with "<<hitsPerChamber.etaHits.size()
409 <<
" primary and "<<hitsPerChamber.phiHits.size()<<
" phi space points.");
413 ATH_CHECK(writeHandle.record(std::move(outContainer)));
414 return StatusCode::SUCCESS;
420 splittedHits.emplace_back();
422 m_statCounter->addToStat(hitsPerChamber.etaHits);
423 m_statCounter->addToStat(hitsPerChamber.phiHits);
427 splittedHits.erase(std::remove_if(splittedHits.begin(), splittedHits.end(),
429 return bucket.size() <= 1;
430 }), splittedHits.end());
438 std::stringstream spStr{};
439 for (
const std::shared_ptr<SpacePoint>& sp : bucket){
440 spStr<<
"SpacePoint: PrimaryMeas: " <<(*sp)<<std::endl;
442 ATH_MSG_VERBOSE(
"Created a bucket, printing all spacepoints..."<<std::endl<<spStr.str());
445 finalContainer.
push_back(std::make_unique<SpacePointBucket>(std::move(bucket)));
452 auto phiPoint = std::make_shared<SpacePoint>(std::move(sp));
453 const double dY = std::sqrt(phiPoint->covariance()[Acts::toUnderlying(
CovIdx::etaCov)]);
454 const double minY = phiPoint->localPosition().y() - dY;
455 const double maxY = phiPoint->localPosition().y() + dY;
459 if (! (maxY < bucket.coveredMin() || bucket.coveredMax() < minY) ) {
460 bucket.emplace_back(phiPoint);
466 const double firstSpPos,
474 if (sortedPoints.empty() || sortedPoints.back().empty()) {
487 overlap.back()->localPosition().y());
493 const double overlapPos = pointInBucket->localPosition().y() +
494 std::sqrt(pointInBucket->covariance()[Acts::toUnderlying(
CovIdx::etaCov)]);
496 newContainer.insert(newContainer.begin(), pointInBucket);
512 return a.localPosition().
y() <
b.localPosition().y();
515 double firstPointPos =
spacePoints.front().localPosition().y();
520 if (
splitBucket(toSort, firstPointPos, splittedHits)){
522 firstPointPos = splittedHits.back().empty() ? toSort.localPosition().y() : splittedHits.back().front()->localPosition().y();
523 ATH_MSG_VERBOSE(
"New bucket: id " << splittedHits.back().bucketId() <<
" Coverage: " << firstPointPos);
525 std::shared_ptr<SpacePoint> spacePoint = std::make_shared<SpacePoint>(std::move(toSort));
526 splittedHits.back().emplace_back(spacePoint);
530 lastBucket.back()->localPosition().y());