12 #include <GaudiKernel/IMessageSvc.h>
14 #include <type_traits>
21 inline std::vector<std::shared_ptr<unsigned>> matchCountVec(
unsigned int n) {
22 std::vector<std::shared_ptr<unsigned>>
out{};
24 for (
unsigned int p = 0;
p <
n ;++
p) {
25 out.emplace_back(std::make_shared<unsigned>(0));
33 template<
class MeasType>
36 const MeasType* meas)
const{
38 if constexpr(std::is_same_v<MeasType, xAOD::MdtDriftCircle>) {
39 hash = meas->measurementHash();
41 hash = meas->layerHash();
47 template<
class MeasType>
50 if constexpr (std::is_same_v<MeasType, xAOD::MdtDriftCircle>){
51 return toChamberTrans * meas->localCirclePosition();
52 }
else if constexpr (std::is_same_v<MeasType, xAOD::RpcMeasurement>){
53 return toChamberTrans * meas->localMeasurementPos();
54 }
else if constexpr (std::is_same_v<MeasType, xAOD::TgcStrip>){
55 const auto& stripLay = meas->readoutElement()->sensorLayout(meas->layerHash());
56 return toChamberTrans * stripLay->to3D(meas->template localPosition<1>()[0]*Amg::Vector2D::UnitX(),
58 }
else if constexpr (std::is_same_v<MeasType, xAOD::MMCluster>){
59 return toChamberTrans * (meas->template localPosition<1>()[
Trk::locX] * Amg::Vector3D::UnitX());
61 else if constexpr (std::is_same_v<MeasType, xAOD::sTgcMeasurement>){
62 if (meas->channelType() == sTgcIdHelper::sTgcChannelTypes::Strip ||
63 meas->channelType() == sTgcIdHelper::sTgcChannelTypes::Wire) {
64 return toChamberTrans * (meas->template localPosition<1>()[
Trk::locX] * Amg::Vector3D::UnitX());
67 locPos.block<2,1>(0,0) = xAOD::toEigen(meas->template localPosition<2>());
68 return toChamberTrans * locPos;
74 template<
class MeasType>
77 if constexpr (std::is_same_v<MeasType, xAOD::MdtDriftCircle>){
78 return toChamberTrans.linear() * Amg::Vector3D::UnitZ();
80 else if constexpr (std::is_same_v<MeasType, xAOD::RpcMeasurement> or
81 std::is_same_v<MeasType, xAOD::MMCluster> or
82 std::is_same_v<MeasType, xAOD::sTgcMeasurement>){
83 return toChamberTrans.linear() * Amg::Vector3D::UnitY();
85 else if constexpr (std::is_same_v<MeasType, xAOD::TgcStrip>) {
86 const auto& stripLay = meas->readoutElement()->sensorLayout(meas->layerHash());
87 if (meas->measuresPhi()) {
89 return toChamberTrans.linear() * stripLay->to3D(sDesign.stripDir(meas->channelNumber()),
true);
91 return toChamberTrans.linear() * stripLay->to3D(stripLay->design().stripDir(),
false);
97 template<
class MeasType>
100 if constexpr (std::is_same_v<MeasType, xAOD::MdtDriftCircle>){
101 return toChamberTrans.linear() * Amg::Vector3D::UnitY();
103 else if constexpr (std::is_same_v<MeasType, xAOD::RpcMeasurement> or
104 std::is_same_v<MeasType, xAOD::MMCluster> or
105 std::is_same_v<MeasType, xAOD::sTgcMeasurement>){
106 return toChamberTrans.linear() * Amg::Vector3D::UnitX();
108 else if constexpr (std::is_same_v<MeasType, xAOD::TgcStrip>) {
109 const auto& stripLay = meas->readoutElement()->sensorLayout(meas->layerHash());
110 if (meas->measuresPhi()) {
112 return toChamberTrans.linear() * stripLay->to3D(sDesign.stripNormal(meas->channelNumber()),
true);
114 return toChamberTrans.linear() * stripLay->to3D(stripLay->design().stripNormal(),
false);
120 template<
class MeasType>
126 if (primaryMeas->numDimensions() == 1) {
127 uvcov(0,0) = primaryMeas->template localCovariance<1>()[0];
129 if constexpr (std::is_same_v<MeasType, xAOD::MdtDriftCircle>) {
130 uvcov(1,1) = 0.5* primaryMeas->readoutElement()->activeTubeLength(primaryMeas->measurementHash());
132 else if constexpr (std::is_same_v<MeasType, xAOD::RpcMeasurement>) {
133 if (primaryMeas->numDimensions() == 1) {
135 uvcov(1,1) = strip->measuresPhi() ? 0.5* strip->readoutElement()->stripPhiLength(): 0.5* strip->readoutElement()->stripEtaLength();
138 else if constexpr (std::is_same_v<MeasType, xAOD::TgcStrip>){
139 if (primaryMeas->measuresPhi()) {
140 uvcov(1,1) = 0.5 * primaryMeas->readoutElement()->stripLayout(primaryMeas->layerHash()).stripLength(primaryMeas->channelNumber());
142 uvcov(1,1) = 0.5 * primaryMeas->readoutElement()->wireGangLayout(primaryMeas->layerHash()).stripLength(primaryMeas->channelNumber());
145 else if constexpr (std::is_same_v<MeasType, xAOD::MMCluster>){
146 uvcov(1,1) = 0.5 * primaryMeas->readoutElement()->stripLayer(primaryMeas->measurementHash()).design().stripLength(primaryMeas->channelNumber());
148 else if constexpr (std::is_same_v<MeasType, xAOD::sTgcMeasurement>){
149 switch (primaryMeas->channelType()) {
150 case sTgcIdHelper::sTgcChannelTypes::Strip:
151 uvcov(1,1) = 0.5 * primaryMeas->readoutElement()->stripDesign(primaryMeas->measurementHash()).stripLength(primaryMeas->channelNumber());
153 case sTgcIdHelper::sTgcChannelTypes::Wire:
154 uvcov(1,1) = 0.5 * primaryMeas->readoutElement()->wireDesign(primaryMeas->measurementHash()).stripLength(primaryMeas->channelNumber());
157 case sTgcIdHelper::sTgcChannelTypes::Pad:
163 uvcov(1,1) =
std::pow(uvcov(1,1), 2);
165 else if (primaryMeas->numDimensions() == 2){
169 uvcov = xAOD::toEigen(primaryMeas->template localCovariance<2>());
171 else THROW_EXCEPTION(
"Unexpected numDimension for PRD: " << m_idHelperSvc->toString(primaryMeas->identify()));
173 Jac.col(0) = nor.block<2,1>(0,0).
unit();
174 Jac.col(1) =
dir.block<2,1>(0,0).
unit();
176 return Jac * uvcov * Jac.inverse();
185 if (primaryMeas->numDimensions() != 1) {
188 uvcov(0,0) = primaryMeas->localCovariance<1>()[0];
189 uvcov(1,1) = secondaryMeas->localCovariance<1>()[0];
190 Jac.col(0) = nor1.block<2,1>(0,0).
unit();
191 Jac.col(1) = nor2.block<2,1>(0,0).
unit();
192 return Jac * uvcov * Jac.inverse();
195 template<
class MeasType>
197 const MeasType* primaryMeas,
199 pointColl.emplace_back(primaryMeas);
205 sp.setCovariance(computeCov(primaryMeas,sp.directionInChamber(),sp.normalInChamber()));
210 template<
class MeasType>
212 const MeasType* primaryMeas,
213 const MeasType* secondaryMeas,
216 pointColl.emplace_back(primaryMeas, secondaryMeas);
225 sp.setPosition(pos1 + Amg::intersect<3>(pos2,dir2, pos1, sp.directionInChamber()).value_or(0) * sp.directionInChamber());
228 sp.setCovariance(computeCov(primaryMeas,
230 sp.normalInChamber(),
238 return static_cast<int>(
techIdx) <
static_cast<int>(
other.techIdx);
241 return static_cast<int>(
stIdx) <
static_cast<int>(
other.stIdx);
246 return measEta + measPhi + measEtaPhi;
251 void SpacePointMakerAlg::SpacePointStatistics::addToStat(
const std::vector<SpacePoint>&
spacePoints){
252 std::lock_guard guard{m_mutex};
255 key.stIdx = m_idHelperSvc->stationIndex(sp.identify());
256 key.techIdx = m_idHelperSvc->technologyIndex(sp.identify());
257 key.eta = m_idHelperSvc->stationEta(sp.identify());
259 if (sp.measuresEta() && sp.measuresPhi()) {
262 stats.measEta += sp.measuresEta();
263 stats.measPhi += sp.measuresPhi();
267 void SpacePointMakerAlg::SpacePointStatistics::dumpStatisics(MsgStream&
msg)
const {
268 using KeyVal = std::pair<FieldKey, StatField>;
269 std::vector<KeyVal> sortedstats{};
270 sortedstats.reserve(m_map.size());
272 for (
const auto & [
key,
stats] : m_map){
273 sortedstats.emplace_back(std::make_pair(
key,
stats));
275 std::stable_sort(sortedstats.begin(), sortedstats.end(), [](
const KeyVal&
a,
const KeyVal&
b) {
276 return a.second.allHits() > b.second.allHits();
278 msg<<
MSG::ALWAYS<<
"###########################################################################"<<
endmsg;
279 for (
const auto & [
key,
stats] : sortedstats) {
282 <<
" "<<std::abs(
key.eta)<<(
key.eta < 0 ?
"A" :
"C")
283 <<
" "<<std::setw(8)<<
stats.measEtaPhi
284 <<
" "<<std::setw(8)<<
stats.measEta
287 msg<<
MSG::ALWAYS<<
"###########################################################################"<<
endmsg;
294 m_statCounter->dumpStatisics(msgStream());
296 return StatusCode::SUCCESS;
300 ATH_CHECK(m_mdtKey.initialize(!m_mdtKey.empty()));
301 ATH_CHECK(m_rpcKey.initialize(!m_rpcKey.empty()));
302 ATH_CHECK(m_tgcKey.initialize(!m_tgcKey.empty()));
303 ATH_CHECK(m_mmKey.initialize(!m_mmKey.empty()));
304 ATH_CHECK(m_stgcKey.initialize(!m_stgcKey.empty()));
307 if (m_doStat) m_statCounter = std::make_unique<SpacePointStatistics>(m_idHelperSvc.get());
308 return StatusCode::SUCCESS;
312 bool SpacePointMakerAlg::passOccupancy2D(
const std::vector<const xAOD::TgcStrip*>& etaHits,
313 const std::vector<const xAOD::TgcStrip*>& phiHits)
const {
314 if (etaHits.empty() || phiHits.empty()) {
318 ATH_MSG_VERBOSE(
"Collected "<<etaHits.size()<<
"/"<<phiHits.size()<<
" hits in "<<m_idHelperSvc->toStringGasGap(etaHits[0]->identify()));
319 return ((1.*etaHits.size()) / ((1.*
re->numChannels(etaHits[0]->measurementHash())))) < m_maxOccTgcEta &&
320 ((1.*phiHits.size()) / ((1.*
re->numChannels(phiHits[0]->measurementHash())))) < m_maxOccTgcPhi;
323 bool SpacePointMakerAlg::passOccupancy2D(
const std::vector<const xAOD::RpcMeasurement*>& etaHits,
324 const std::vector<const xAOD::RpcMeasurement*>& phiHits)
const {
325 if (etaHits.empty() || phiHits.empty()) {
329 ATH_MSG_VERBOSE(
"Collected "<<etaHits.size()<<
"/"<<phiHits.size()<<
" hits in "<<m_idHelperSvc->toStringGasGap(etaHits[0]->identify()));
330 return ((1.*etaHits.size()) / (1.*
re->nEtaStrips())) < m_maxOccRpcEta &&
331 ((1.*phiHits.size()) / (1.*
re->nPhiStrips())) < m_maxOccRpcPhi;
335 bool SpacePointMakerAlg::passOccupancy2D(
const std::vector<const xAOD::sTgcMeasurement*>& etaHits,
336 const std::vector<const xAOD::sTgcMeasurement*>& phiHits)
const {
337 if (etaHits.empty() || phiHits.empty()) {
341 return ((1.*etaHits.size()) / (1.*
re->numChannels(etaHits[0]->measurementHash()))) < m_maxOccStgcEta &&
342 ((1.*phiHits.size()) / (1.*
re->numChannels(phiHits[0]->measurementHash()))) < m_maxOccStgcPhi;
345 template <
class ContType>
346 StatusCode SpacePointMakerAlg::loadContainerAndSort(
const EventContext& ctx,
349 const ContType* measurementCont{
nullptr};
351 if (!measurementCont || measurementCont->empty()){
353 return StatusCode::SUCCESS;
358 using PrdType =
typename ContType::const_value_type;
359 using PrdVec = std::vector<PrdType>;
364 const Amg::Transform3D& sectorTrans = viewer.at(0)->readoutElement()->msSector()->globalToLocalTrans(*gctx);
365 ATH_MSG_DEBUG(
"Fill space points for chamber "<<m_idHelperSvc->toStringDetEl(viewer.at(0)->identify()));
366 if constexpr( std::is_same_v<ContType, xAOD::MdtDriftCircleContainer> ||
367 std::is_same_v<ContType, xAOD::MMClusterContainer>) {
369 pointsInChamb.
etaHits.reserve(pointsInChamb.
etaHits.capacity() + viewer.size());
370 for (
const PrdType prd: viewer) {
371 ATH_MSG_VERBOSE(
"Create space point from "<<m_idHelperSvc->toString(prd->identify())
372 <<
", hash: "<<prd->identifierHash());
374 Amg::Transform3D toChamberTrans{ toChamberTransform(*gctx, sectorTrans,prd)};
375 fillSpacePoint(pointsInChamb.
etaHits, prd, toChamberTrans);
379 using EtaPhiHits = std::array<PrdVec, 2>;
380 std::vector<EtaPhiHits> hitsPerGasGap{};
381 for (
const PrdType prd : viewer) {
382 ATH_MSG_VERBOSE(
"Create space point from "<<m_idHelperSvc->toString(prd->identify())<<
", hash: "<<prd->identifierHash());
384 unsigned int gapIdx = prd->gasGap() -1;
385 if constexpr (std::is_same_v<ContType, xAOD::RpcMeasurementContainer>) {
386 gapIdx = prd->readoutElement()->createHash(0, prd->gasGap(), prd->doubletPhi(),
false);
390 if constexpr(std::is_same_v<ContType, xAOD::sTgcMeasContainer>) {
392 if (prd->channelType() == sTgcIdHelper::sTgcChannelTypes::Pad) {
393 Amg::Transform3D toChamberTrans{ toChamberTransform(*gctx, sectorTrans, prd)};
394 fillSpacePoint(pointsInChamb.
etaHits, prd, toChamberTrans);
398 measPhi = prd->channelType() == sTgcIdHelper::sTgcChannelTypes::Wire;
401 measPhi = prd->measuresPhi();
404 if (hitsPerGasGap.size() <= gapIdx) {
405 hitsPerGasGap.resize(gapIdx + 1);
408 PrdVec& toPush = hitsPerGasGap[gapIdx][measPhi];
409 if (toPush.capacity() == toPush.size()) {
410 toPush.reserve(toPush.size() + m_capacityBucket);
412 toPush.push_back(prd);
415 for (
auto& [etaHits, phiHits] : hitsPerGasGap) {
418 if (!etaHits.empty()){
419 toChamberTrans_eta = toChamberTransform(*gctx, sectorTrans, etaHits.at(0));
421 if (!phiHits.empty()){
422 toChamberTrans_phi = toChamberTransform(*gctx, sectorTrans, phiHits.at(0));
425 if (!passOccupancy2D(etaHits, phiHits)) {
426 ATH_MSG_VERBOSE(
"Occupancy cut not passed "<<etaHits.size()<<
", "<<phiHits.size());
427 pointsInChamb.
etaHits.reserve(pointsInChamb.
etaHits.size() + etaHits.size());
428 pointsInChamb.
phiHits.reserve(pointsInChamb.
phiHits.size() + phiHits.size());
429 for (
const PrdType etaPrd : etaHits) {
431 fillSpacePoint(pointsInChamb.
etaHits, etaPrd, toChamberTrans_eta);
436 for (
const PrdType phiPrd : phiHits) {
437 fillSpacePoint(pointsInChamb.
phiHits, phiPrd, toChamberTrans_phi);
443 std::vector<std::shared_ptr<unsigned>> etaCounts{matchCountVec(etaHits.size())},
444 phiCounts{matchCountVec(phiHits.size())};
445 pointsInChamb.
etaHits.reserve(etaHits.size()*phiHits.size());
447 for (
unsigned int etaP = 0; etaP < etaHits.size(); ++etaP) {
449 for (
unsigned int phiP = 0; phiP < phiHits.size(); ++ phiP) {
452 if (!(etaHits[etaP]->bcBitMap() & phiHits[phiP]->bcBitMap())){
456 fillSpacePoint(pointsInChamb.
etaHits, etaHits[etaP], phiHits[phiP], toChamberTrans_eta, toChamberTrans_phi);
459 ATH_MSG_VERBOSE(
"Create new spacepoint from "<<m_idHelperSvc->toString(etaHits[etaP]->identify())
460 <<
" & "<<m_idHelperSvc->toString(phiHits[phiP]->identify())<<
" at "<<
Amg::toString(sp.positionInChamber()));
461 sp.setInstanceCounts(etaCounts[etaP], phiCounts[phiP]);
463 if (!(*etaCounts[etaP])) {
464 fillSpacePoint(pointsInChamb.
etaHits, etaHits[etaP], toChamberTrans_eta);
470 for (
unsigned int phiP = 0; phiP < phiHits.size(); ++ phiP){
471 if (!(*phiCounts[phiP])) {
472 fillSpacePoint(pointsInChamb.
phiHits, phiHits[phiP], toChamberTrans_phi);
477 }
while (viewer.next());
478 return StatusCode::SUCCESS;
484 ATH_CHECK(loadContainerAndSort(ctx, m_mdtKey, preSortedContainer));
485 ATH_CHECK(loadContainerAndSort(ctx, m_rpcKey, preSortedContainer));
486 ATH_CHECK(loadContainerAndSort(ctx, m_tgcKey, preSortedContainer));
487 ATH_CHECK(loadContainerAndSort(ctx, m_mmKey, preSortedContainer));
488 ATH_CHECK(loadContainerAndSort(ctx, m_stgcKey, preSortedContainer));
489 std::unique_ptr<SpacePointContainer> outContainer = std::make_unique<SpacePointContainer>();
491 for (
auto &[
chamber, hitsPerChamber] : preSortedContainer){
493 distributePointsAndStore(std::move(hitsPerChamber), *outContainer);
496 ATH_CHECK(writeHandle.record(std::move(outContainer)));
497 return StatusCode::SUCCESS;
503 splittedHits.emplace_back();
505 m_statCounter->addToStat(hitsPerChamber.etaHits);
506 m_statCounter->addToStat(hitsPerChamber.phiHits);
509 distributePrimaryPoints(std::move(hitsPerChamber.etaHits), splittedHits);
510 splittedHits.erase(std::remove_if(splittedHits.begin(), splittedHits.end(),
512 return bucket.size() <= 1;
513 }), splittedHits.end());
514 distributePhiPoints(std::move(hitsPerChamber.phiHits), splittedHits);
521 std::stringstream spStr{};
522 for (
const std::shared_ptr<SpacePoint>& sp : bucket){
523 spStr<<
"SpacePoint: PrimaryMeas: " << m_idHelperSvc->toString(sp->identify()) <<
" SecondaryMeas: "
524 <<(sp->secondaryMeasurement() ? m_idHelperSvc->toString(
xAOD::identify(sp->secondaryMeasurement())) :
" None ")
525 <<
" Pos: " <<
Amg::toString(sp->positionInChamber())<<std::endl;
527 ATH_MSG_VERBOSE(
"Created a bucket, printing all spacepoints..."<<std::endl<<spStr.str());
531 finalContainer.
push_back(std::make_unique<SpacePointBucket>(std::move(bucket)));
535 void SpacePointMakerAlg::distributePhiPoints(std::vector<SpacePoint>&&
spacePoints,
538 auto phiPoint = std::make_shared<SpacePoint>(std::move(sp));
539 const double minY = phiPoint->positionInChamber().y() - phiPoint->uncertainty().y();
540 const double maxY = phiPoint->positionInChamber().y() + phiPoint->uncertainty().y();
544 if (! (maxY < bucket.coveredMin() || bucket.coveredMax() < minY) ) {
545 bucket.emplace_back(phiPoint);
550 bool SpacePointMakerAlg::splitBucket(
const SpacePoint& spacePoint,
551 const double firstSpPos,
555 if (spY - firstSpPos > m_maxBucketLength){
559 if (sortedPoints.empty() || sortedPoints.back().empty()) {
562 return spY - sortedPoints.back().back()->positionInChamber().y() > m_spacePointWindow;
564 void SpacePointMakerAlg::newBucket(
const SpacePoint& refSpacePoint,
572 overlap.back()->positionInChamber().y());
578 const double overlapPos = pointInBucket->positionInChamber().y() + pointInBucket->uncertainty()[
Amg::y];
579 if (refBound - overlapPos < m_spacePointOverlap) {
580 newContainer.insert(newContainer.begin(), pointInBucket);
588 void SpacePointMakerAlg::distributePrimaryPoints(std::vector<SpacePoint>&&
spacePoints,
596 return a.positionInChamber().
y() <
b.positionInChamber().y();
599 double firstPointPos =
spacePoints.front().positionInChamber().y();
602 ATH_MSG_VERBOSE(
"Add new primary space point "<<m_idHelperSvc->toString(toSort.identify())<<
", "
605 if (splitBucket(toSort, firstPointPos, splittedHits)){
606 newBucket(toSort, splittedHits);
607 firstPointPos = splittedHits.back().empty() ? toSort.positionInChamber().y() : splittedHits.back().front()->positionInChamber().y();
608 ATH_MSG_VERBOSE(
"New bucket: id " << splittedHits.back().bucketId() <<
" Coverage: " << firstPointPos);
610 std::shared_ptr<SpacePoint> spacePoint = std::make_shared<SpacePoint>(std::move(toSort));
611 splittedHits.back().emplace_back(spacePoint);
614 lastBucket.
setCoveredRange(lastBucket.front()->positionInChamber().y(),
615 lastBucket.back()->positionInChamber().y());