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());