Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-09-07 04:36:52

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/global/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::global::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 produce(edm::StreamID, edm::Event&, const edm::EventSetup&) const override;
0070 
0071   static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
0072 
0073 private:
0074   GEMPadDigiClusterContainer buildClusters(const GEMPadDigiCollection& pads, const GEMGeometry&) const;
0075   GEMPadDigiClusterCollection selectClusters(const GEMPadDigiClusterContainer& in_clusters, const GEMGeometry&) const;
0076   template <class T>
0077   void checkValid(const T& cluster, const GEMDetId& id) const;
0078 
0079   /// Name of input digi Collection
0080   edm::EDGetTokenT<GEMPadDigiCollection> pad_token_;
0081   edm::EDPutTokenT<GEMPadDigiClusterCollection> put_token_;
0082   edm::ESGetToken<GEMGeometry, MuonGeometryRecord> geom_token_;
0083   edm::InputTag pads_;
0084 
0085   unsigned int nPartitionsGE11_;
0086   unsigned int nPartitionsGE21_;
0087   unsigned int maxClustersPartitionGE11_;
0088   unsigned int maxClustersPartitionGE21_;
0089   unsigned int nOHGE11_;
0090   unsigned int nOHGE21_;
0091   unsigned int maxClustersOHGE11_;
0092   unsigned int maxClustersOHGE21_;
0093   unsigned int maxClusterSize_;
0094   bool sendOverflowClusters_;
0095 };
0096 
0097 GEMPadDigiClusterProducer::GEMPadDigiClusterProducer(const edm::ParameterSet& ps) {
0098   pads_ = ps.getParameter<edm::InputTag>("InputCollection");
0099   nPartitionsGE11_ = ps.getParameter<unsigned int>("nPartitionsGE11");
0100   nPartitionsGE21_ = ps.getParameter<unsigned int>("nPartitionsGE21");
0101   maxClustersPartitionGE11_ = ps.getParameter<unsigned int>("maxClustersPartitionGE11");
0102   maxClustersPartitionGE21_ = ps.getParameter<unsigned int>("maxClustersPartitionGE21");
0103   nOHGE11_ = ps.getParameter<unsigned int>("nOHGE11");
0104   nOHGE21_ = ps.getParameter<unsigned int>("nOHGE21");
0105   maxClustersOHGE11_ = ps.getParameter<unsigned int>("maxClustersOHGE11");
0106   maxClustersOHGE21_ = ps.getParameter<unsigned int>("maxClustersOHGE21");
0107   maxClusterSize_ = ps.getParameter<unsigned int>("maxClusterSize");
0108   sendOverflowClusters_ = ps.getParameter<bool>("sendOverflowClusters");
0109 
0110   if (sendOverflowClusters_) {
0111     maxClustersOHGE11_ *= 2;
0112     maxClustersOHGE21_ *= 2;
0113   }
0114 
0115   pad_token_ = consumes<GEMPadDigiCollection>(pads_);
0116   geom_token_ = esConsumes<GEMGeometry, MuonGeometryRecord>();
0117 
0118   put_token_ = produces<GEMPadDigiClusterCollection>();
0119 }
0120 
0121 GEMPadDigiClusterProducer::~GEMPadDigiClusterProducer() {}
0122 
0123 void GEMPadDigiClusterProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
0124   edm::ParameterSetDescription desc;
0125   desc.add<edm::InputTag>("InputCollection", edm::InputTag("simMuonGEMPadDigis"));
0126   desc.add<unsigned int>("nPartitionsGE11", 4);           // Number of clusterizer partitions per OH
0127   desc.add<unsigned int>("nPartitionsGE21", 4);           // Number of clusterizer partitions per OH
0128   desc.add<unsigned int>("maxClustersPartitionGE11", 4);  // Maximum number of clusters per clusterizer partition
0129   desc.add<unsigned int>("maxClustersPartitionGE21", 4);  // Maximum number of clusters per clusterizer partition
0130   desc.add<unsigned int>("nOHGE11", 1);                   // Number of OH boards per chamber
0131   desc.add<unsigned int>("nOHGE21", 4);                   // Number of OH boards per chamber
0132   desc.add<unsigned int>("maxClustersOHGE11", 8);         // Maximum number of clusters per OH
0133   desc.add<unsigned int>("maxClustersOHGE21", 8);         // Maximum number of clusters per OH
0134   desc.add<unsigned int>("maxClusterSize", 8);            // Maximum cluster size (number of pads)
0135   desc.add<bool>("sendOverflowClusters", false);
0136 
0137   descriptions.add("simMuonGEMPadDigiClustersDef", desc);
0138 }
0139 
0140 void GEMPadDigiClusterProducer::produce(edm::StreamID, edm::Event& e, const edm::EventSetup& eventSetup) const {
0141   auto const& geometry = eventSetup.getData(geom_token_);
0142 
0143   auto const& pads = e.get(pad_token_);
0144 
0145   // build the proto clusters (per partition)
0146   GEMPadDigiClusterContainer proto_clusters = buildClusters(pads, geometry);
0147 
0148   // sort and select clusters per chamber, per OH, per partition number and per pad number
0149   e.emplace(put_token_, selectClusters(proto_clusters, geometry));
0150 }
0151 
0152 GEMPadDigiClusterProducer::GEMPadDigiClusterContainer GEMPadDigiClusterProducer::buildClusters(
0153     const GEMPadDigiCollection& det_pads, const GEMGeometry& geometry) const {
0154   GEMPadDigiClusterContainer proto_clusters;
0155 
0156   // construct clusters
0157   for (const auto& part : geometry.etaPartitions()) {
0158     // clusters are not build for ME0
0159     // -> ignore hits from station 0
0160     if (part->isME0())
0161       continue;
0162 
0163     GEMPadDigiClusters all_pad_clusters;
0164 
0165     auto pads = det_pads.get(part->id());
0166     std::vector<uint16_t> cl;
0167     int startBX = 99;
0168 
0169     for (auto d = pads.first; d != pads.second; ++d) {
0170       // check if the input pad is valid
0171       checkValid(*d, part->id());
0172 
0173       // number of eta partitions
0174       unsigned nPart = d->nPartitions();
0175 
0176       if (cl.empty()) {
0177         cl.push_back((*d).pad());
0178       } else {
0179         if ((*d).bx() == startBX and            // same bunch crossing
0180             (*d).pad() == cl.back() + 1         // pad difference is 1
0181             and cl.size() < maxClusterSize_) {  // max 8 in cluster
0182           cl.push_back((*d).pad());
0183         } else {
0184           // put the current cluster in the proto collection
0185           GEMPadDigiCluster pad_cluster(cl, startBX, part->subsystem(), nPart);
0186 
0187           // check if the output cluster is valid
0188           checkValid(pad_cluster, part->id());
0189 
0190           all_pad_clusters.emplace_back(pad_cluster);
0191 
0192           // start a new cluster
0193           cl.clear();
0194           cl.push_back((*d).pad());
0195         }
0196       }
0197       startBX = (*d).bx();
0198     }
0199 
0200     // put the last cluster in the proto collection
0201     if (pads.first != pads.second) {
0202       // number of eta partitions
0203       unsigned nPart = (pads.first)->nPartitions();
0204 
0205       GEMPadDigiCluster pad_cluster(cl, startBX, part->subsystem(), nPart);
0206 
0207       // check if the output cluster is valid
0208       checkValid(pad_cluster, part->id());
0209 
0210       all_pad_clusters.emplace_back(pad_cluster);
0211     }
0212     proto_clusters.emplace(part->id(), all_pad_clusters);
0213 
0214   }  // end of partition loop
0215   return proto_clusters;
0216 }
0217 
0218 GEMPadDigiClusterCollection GEMPadDigiClusterProducer::selectClusters(const GEMPadDigiClusterContainer& proto_clusters,
0219                                                                       const GEMGeometry& geometry) const {
0220   GEMPadDigiClusterCollection out_clusters;
0221   for (const auto& ch : geometry.chambers()) {
0222     const unsigned nOH = ch->id().isGE11() ? nOHGE11_ : nOHGE21_;
0223     const unsigned nPartitions = ch->id().isGE11() ? nPartitionsGE11_ : nPartitionsGE21_;
0224     const unsigned nEtaPerPartition = ch->nEtaPartitions() / (nPartitions * nOH);
0225     const unsigned maxClustersPart = ch->id().isGE11() ? maxClustersPartitionGE11_ : maxClustersPartitionGE21_;
0226     const unsigned maxClustersOH = ch->id().isGE11() ? maxClustersOHGE11_ : maxClustersOHGE21_;
0227 
0228     // loop over OH in this chamber
0229     for (unsigned int iOH = 0; iOH < nOH; iOH++) {
0230       unsigned int nClustersOH = 0;  // Up to 8 clusters per OH
0231                                      // loop over clusterizer partitions
0232       for (unsigned int iPart = 0; iPart < nPartitions; iPart++) {
0233         unsigned int nClustersPart = 0;  // Up to 4 clusters per clustizer partition
0234         // loop over the eta partitions for this clusterizer partition
0235         for (unsigned iEta = 1; iEta <= nEtaPerPartition; iEta++) {
0236           // get the clusters for this eta partition
0237           const GEMDetId& iEtaId =
0238               ch->etaPartition(iEta + iPart * nEtaPerPartition + iOH * nPartitions * nEtaPerPartition)->id();
0239           if (proto_clusters.find(iEtaId) != proto_clusters.end()) {
0240             for (const auto& cluster : proto_clusters.at(iEtaId)) {
0241               if (nClustersPart < maxClustersPart and nClustersOH < maxClustersOH) {
0242                 checkValid(cluster, iEtaId);
0243                 out_clusters.insertDigi(iEtaId, cluster);
0244                 nClustersPart++;
0245                 nClustersOH++;
0246               }
0247             }  // end of loop on clusters in eta
0248           }
0249         }  // end of eta partition loop
0250       }  // end of clusterizer partition loop
0251     }  // end of OH loop
0252   }  // end of chamber loop
0253   return out_clusters;
0254 }
0255 
0256 template <class T>
0257 void GEMPadDigiClusterProducer::checkValid(const T& tp, const GEMDetId& id) const {
0258   // check if the pad/cluster is valid
0259   // in principle, invalid pads/clusters can appear in the CMS raw data
0260   if (!tp.isValid()) {
0261     edm::LogWarning("GEMPadDigiClusterProducer") << "Invalid " << tp << " in " << id;
0262   }
0263 }
0264 
0265 DEFINE_FWK_MODULE(GEMPadDigiClusterProducer);