Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 11:12:04

0001 /**
0002  *  \class GEMPadDigiClusterProducer
0003  *
0004  *  Produces GEM pad clusters from at most 8 adjacent GEM pads.
0005  *  Clusters are used downstream in the CSC local trigger to build
0006  *  GEM-CSC triggers and in the muon trigger to build EMTF tracks
0007  *
0008  *  Based on documentation provided by the GEM firmware architects
0009  *
0010  *  \author Sven Dildick (TAMU), updated by Giovanni Mocellin (UCDavis)
0011  *
0012  *  *****************************************************
0013  *  ** Notes on chambers and cluster packing algorithm **
0014  *  *****************************************************
0015  *
0016  *  Based on: https://gitlab.cern.ch/emu/0xbefe/-/tree/devel/gem/hdl/cluster_finding/README.org
0017  *  (Andrew Peck, 2020/06/26)
0018  *
0019  *  GE1/1 chamber has 8 iEta partitions and 1 OH
0020  *  GE2/1 chamber has 16 iEta partitions and 4 OH (one per module)
0021  *
0022  *  Both GE1/1 and GE2/1 have 384 strips = 192 pads per iEta partition
0023  *
0024  *  GE1/1 OH has 4 clustering partitions, each covering 2 iEta partitions
0025  *  GE2/1 OH has 4 clustering partitions, each covering 1 iEta partition
0026  *
0027  *  Each clustering partition finds up to 4 clusters per BX, which are
0028  *  then sent to the sorter. The sorting of the clusters favors lower
0029  *  eta partitions and lower pad numbers.
0030  *
0031  *  The first 8 clusters are selected and sent out through optical fibers.
0032  */
0033 
0034 #include "FWCore/Framework/interface/MakerMacros.h"
0035 #include "FWCore/PluginManager/interface/ModuleDef.h"
0036 #include "FWCore/Framework/interface/stream/EDProducer.h"
0037 #include "FWCore/Framework/interface/MakerMacros.h"
0038 #include "FWCore/Framework/interface/ESHandle.h"
0039 #include "FWCore/Framework/interface/ConsumesCollector.h"
0040 #include "FWCore/Framework/interface/Event.h"
0041 #include "FWCore/Framework/interface/EventSetup.h"
0042 
0043 #include "FWCore/Utilities/interface/Exception.h"
0044 #include "FWCore/Utilities/interface/ESGetToken.h"
0045 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0046 #include "FWCore/Utilities/interface/InputTag.h"
0047 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0048 
0049 #include "Geometry/Records/interface/MuonGeometryRecord.h"
0050 #include "Geometry/GEMGeometry/interface/GEMGeometry.h"
0051 
0052 #include "DataFormats/Common/interface/Handle.h"
0053 #include "DataFormats/GEMDigi/interface/GEMPadDigiCollection.h"
0054 #include "DataFormats/GEMDigi/interface/GEMPadDigiClusterCollection.h"
0055 
0056 #include <string>
0057 #include <map>
0058 #include <vector>
0059 
0060 class GEMPadDigiClusterProducer : public edm::stream::EDProducer<> {
0061 public:
0062   typedef std::vector<GEMPadDigiCluster> GEMPadDigiClusters;
0063   typedef std::map<GEMDetId, GEMPadDigiClusters> GEMPadDigiClusterContainer;
0064 
0065   explicit GEMPadDigiClusterProducer(const edm::ParameterSet& ps);
0066 
0067   ~GEMPadDigiClusterProducer() override;
0068 
0069   void beginRun(const edm::Run&, const edm::EventSetup&) override;
0070 
0071   void produce(edm::Event&, const edm::EventSetup&) override;
0072 
0073   static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
0074 
0075 private:
0076   void buildClusters(const GEMPadDigiCollection& pads, GEMPadDigiClusterContainer& out_clusters) const;
0077   void selectClusters(const GEMPadDigiClusterContainer& in_clusters, GEMPadDigiClusterCollection& out) const;
0078   template <class T>
0079   void checkValid(const T& cluster, const GEMDetId& id) const;
0080 
0081   /// Name of input digi Collection
0082   edm::EDGetTokenT<GEMPadDigiCollection> pad_token_;
0083   edm::ESGetToken<GEMGeometry, MuonGeometryRecord> geom_token_;
0084   edm::InputTag pads_;
0085 
0086   unsigned int nPartitionsGE11_;
0087   unsigned int nPartitionsGE21_;
0088   unsigned int maxClustersPartitionGE11_;
0089   unsigned int maxClustersPartitionGE21_;
0090   unsigned int nOHGE11_;
0091   unsigned int nOHGE21_;
0092   unsigned int maxClustersOHGE11_;
0093   unsigned int maxClustersOHGE21_;
0094   unsigned int maxClusterSize_;
0095   bool sendOverflowClusters_;
0096 
0097   const GEMGeometry* geometry_;
0098 };
0099 
0100 GEMPadDigiClusterProducer::GEMPadDigiClusterProducer(const edm::ParameterSet& ps) : geometry_(nullptr) {
0101   pads_ = ps.getParameter<edm::InputTag>("InputCollection");
0102   nPartitionsGE11_ = ps.getParameter<unsigned int>("nPartitionsGE11");
0103   nPartitionsGE21_ = ps.getParameter<unsigned int>("nPartitionsGE21");
0104   maxClustersPartitionGE11_ = ps.getParameter<unsigned int>("maxClustersPartitionGE11");
0105   maxClustersPartitionGE21_ = ps.getParameter<unsigned int>("maxClustersPartitionGE21");
0106   nOHGE11_ = ps.getParameter<unsigned int>("nOHGE11");
0107   nOHGE21_ = ps.getParameter<unsigned int>("nOHGE21");
0108   maxClustersOHGE11_ = ps.getParameter<unsigned int>("maxClustersOHGE11");
0109   maxClustersOHGE21_ = ps.getParameter<unsigned int>("maxClustersOHGE21");
0110   maxClusterSize_ = ps.getParameter<unsigned int>("maxClusterSize");
0111   sendOverflowClusters_ = ps.getParameter<bool>("sendOverflowClusters");
0112 
0113   if (sendOverflowClusters_) {
0114     maxClustersOHGE11_ *= 2;
0115     maxClustersOHGE21_ *= 2;
0116   }
0117 
0118   pad_token_ = consumes<GEMPadDigiCollection>(pads_);
0119   geom_token_ = esConsumes<GEMGeometry, MuonGeometryRecord, edm::Transition::BeginRun>();
0120 
0121   produces<GEMPadDigiClusterCollection>();
0122   consumes<GEMPadDigiCollection>(pads_);
0123 }
0124 
0125 GEMPadDigiClusterProducer::~GEMPadDigiClusterProducer() {}
0126 
0127 void GEMPadDigiClusterProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
0128   edm::ParameterSetDescription desc;
0129   desc.add<edm::InputTag>("InputCollection", edm::InputTag("simMuonGEMPadDigis"));
0130   desc.add<unsigned int>("nPartitionsGE11", 4);           // Number of clusterizer partitions per OH
0131   desc.add<unsigned int>("nPartitionsGE21", 4);           // Number of clusterizer partitions per OH
0132   desc.add<unsigned int>("maxClustersPartitionGE11", 4);  // Maximum number of clusters per clusterizer partition
0133   desc.add<unsigned int>("maxClustersPartitionGE21", 4);  // Maximum number of clusters per clusterizer partition
0134   desc.add<unsigned int>("nOHGE11", 1);                   // Number of OH boards per chamber
0135   desc.add<unsigned int>("nOHGE21", 4);                   // Number of OH boards per chamber
0136   desc.add<unsigned int>("maxClustersOHGE11", 8);         // Maximum number of clusters per OH
0137   desc.add<unsigned int>("maxClustersOHGE21", 8);         // Maximum number of clusters per OH
0138   desc.add<unsigned int>("maxClusterSize", 8);            // Maximum cluster size (number of pads)
0139   desc.add<bool>("sendOverflowClusters", false);
0140 
0141   descriptions.add("simMuonGEMPadDigiClustersDef", desc);
0142 }
0143 
0144 void GEMPadDigiClusterProducer::beginRun(const edm::Run& run, const edm::EventSetup& eventSetup) {
0145   edm::ESHandle<GEMGeometry> hGeom = eventSetup.getHandle(geom_token_);
0146   geometry_ = &*hGeom;
0147 }
0148 
0149 void GEMPadDigiClusterProducer::produce(edm::Event& e, const edm::EventSetup& eventSetup) {
0150   edm::Handle<GEMPadDigiCollection> hpads;
0151   e.getByToken(pad_token_, hpads);
0152 
0153   // Create empty output
0154   std::unique_ptr<GEMPadDigiClusterCollection> pClusters(new GEMPadDigiClusterCollection());
0155 
0156   // build the proto clusters (per partition)
0157   GEMPadDigiClusterContainer proto_clusters;
0158   buildClusters(*(hpads.product()), proto_clusters);
0159 
0160   // sort and select clusters per chamber, per OH, per partition number and per pad number
0161   selectClusters(proto_clusters, *pClusters);
0162 
0163   // store them in the event
0164   e.put(std::move(pClusters));
0165 }
0166 
0167 void GEMPadDigiClusterProducer::buildClusters(const GEMPadDigiCollection& det_pads,
0168                                               GEMPadDigiClusterContainer& proto_clusters) const {
0169   // clear the container
0170   proto_clusters.clear();
0171 
0172   // construct clusters
0173   for (const auto& part : geometry_->etaPartitions()) {
0174     // clusters are not build for ME0
0175     // -> ignore hits from station 0
0176     if (part->isME0())
0177       continue;
0178 
0179     GEMPadDigiClusters all_pad_clusters;
0180 
0181     auto pads = det_pads.get(part->id());
0182     std::vector<uint16_t> cl;
0183     int startBX = 99;
0184 
0185     for (auto d = pads.first; d != pads.second; ++d) {
0186       // check if the input pad is valid
0187       checkValid(*d, part->id());
0188 
0189       // number of eta partitions
0190       unsigned nPart = d->nPartitions();
0191 
0192       if (cl.empty()) {
0193         cl.push_back((*d).pad());
0194       } else {
0195         if ((*d).bx() == startBX and            // same bunch crossing
0196             (*d).pad() == cl.back() + 1         // pad difference is 1
0197             and cl.size() < maxClusterSize_) {  // max 8 in cluster
0198           cl.push_back((*d).pad());
0199         } else {
0200           // put the current cluster in the proto collection
0201           GEMPadDigiCluster pad_cluster(cl, startBX, part->subsystem(), nPart);
0202 
0203           // check if the output cluster is valid
0204           checkValid(pad_cluster, part->id());
0205 
0206           all_pad_clusters.emplace_back(pad_cluster);
0207 
0208           // start a new cluster
0209           cl.clear();
0210           cl.push_back((*d).pad());
0211         }
0212       }
0213       startBX = (*d).bx();
0214     }
0215 
0216     // put the last cluster in the proto collection
0217     if (pads.first != pads.second) {
0218       // number of eta partitions
0219       unsigned nPart = (pads.first)->nPartitions();
0220 
0221       GEMPadDigiCluster pad_cluster(cl, startBX, part->subsystem(), nPart);
0222 
0223       // check if the output cluster is valid
0224       checkValid(pad_cluster, part->id());
0225 
0226       all_pad_clusters.emplace_back(pad_cluster);
0227     }
0228     proto_clusters.emplace(part->id(), all_pad_clusters);
0229 
0230   }  // end of partition loop
0231 }
0232 
0233 void GEMPadDigiClusterProducer::selectClusters(const GEMPadDigiClusterContainer& proto_clusters,
0234                                                GEMPadDigiClusterCollection& out_clusters) const {
0235   for (const auto& ch : geometry_->chambers()) {
0236     const unsigned nOH = ch->id().isGE11() ? nOHGE11_ : nOHGE21_;
0237     const unsigned nPartitions = ch->id().isGE11() ? nPartitionsGE11_ : nPartitionsGE21_;
0238     const unsigned nEtaPerPartition = ch->nEtaPartitions() / (nPartitions * nOH);
0239     const unsigned maxClustersPart = ch->id().isGE11() ? maxClustersPartitionGE11_ : maxClustersPartitionGE21_;
0240     const unsigned maxClustersOH = ch->id().isGE11() ? maxClustersOHGE11_ : maxClustersOHGE21_;
0241 
0242     // loop over OH in this chamber
0243     for (unsigned int iOH = 0; iOH < nOH; iOH++) {
0244       unsigned int nClustersOH = 0;  // Up to 8 clusters per OH
0245                                      // loop over clusterizer partitions
0246       for (unsigned int iPart = 0; iPart < nPartitions; iPart++) {
0247         unsigned int nClustersPart = 0;  // Up to 4 clusters per clustizer partition
0248         // loop over the eta partitions for this clusterizer partition
0249         for (unsigned iEta = 1; iEta <= nEtaPerPartition; iEta++) {
0250           // get the clusters for this eta partition
0251           const GEMDetId& iEtaId =
0252               ch->etaPartition(iEta + iPart * nEtaPerPartition + iOH * nPartitions * nEtaPerPartition)->id();
0253           if (proto_clusters.find(iEtaId) != proto_clusters.end()) {
0254             for (const auto& cluster : proto_clusters.at(iEtaId)) {
0255               if (nClustersPart < maxClustersPart and nClustersOH < maxClustersOH) {
0256                 checkValid(cluster, iEtaId);
0257                 out_clusters.insertDigi(iEtaId, cluster);
0258                 nClustersPart++;
0259                 nClustersOH++;
0260               }
0261             }  // end of loop on clusters in eta
0262           }
0263         }  // end of eta partition loop
0264       }    // end of clusterizer partition loop
0265     }      // end of OH loop
0266   }        // end of chamber loop
0267 }
0268 
0269 template <class T>
0270 void GEMPadDigiClusterProducer::checkValid(const T& tp, const GEMDetId& id) const {
0271   // check if the pad/cluster is valid
0272   // in principle, invalid pads/clusters can appear in the CMS raw data
0273   if (!tp.isValid()) {
0274     edm::LogWarning("GEMPadDigiClusterProducer") << "Invalid " << tp << " in " << id;
0275   }
0276 }
0277 
0278 DEFINE_FWK_MODULE(GEMPadDigiClusterProducer);