CMS 3D CMS Logo

HGCalSimCluster.cc
Go to the documentation of this file.
1 // HGCal Trigger
6 
7 // HGCalClusters and detId
11 
12 // PF Cluster definition
15 
16 
17 // Consumes
20 
21 //
23 
24 // Energy calibration
26 
28 
32 
33 
34 
35 // Print out something before crashing or throwing exceptions
36 #include <iostream>
37 #include <string>
38 
39 
40 /* Original Author: Andrea Carlo Marini
41  * Original Date: 23 Aug 2016
42  *
43  * This backend algorithm is supposed to use the sim cluster information to handle an
44  * optimal clustering algorithm, benchmark the performances of the enconding ...
45  * as well as performing benchmarks on cluster shapes
46  */
47 
48 
49 namespace HGCalTriggerBackend{
50 
51  template<typename FECODEC, typename DATA>
52  class HGCalTriggerSimCluster : public Algorithm<FECODEC>
53  {
54  private:
55  std::unique_ptr<l1t::HGCalClusterBxCollection> cluster_product_;
56  // handle
58  // calibration handle
61 
62  // variables that needs to be init, in the right order
63  // energy calibration
67 
68  // token
70  // Digis
72 
73  // add to cluster shapes, once per trigger cell
74  void addToClusterShapes(std::unordered_map<uint64_t,std::pair<int,l1t::HGCalCluster> >& cluster_container, uint64_t pid,int pdgid,float energy,float eta, float phi, float r=0.0){
75  auto pair = cluster_container.emplace(pid, std::pair<int,l1t::HGCalCluster>(0,l1t::HGCalCluster() ) ) ;
76  auto iterator = pair.first;
77  iterator -> second . second . shapes().Add( energy,eta,phi,r); // last is r, for 3d clusters
78  }
79  // add to cluster
80  void addToCluster(std::unordered_map<uint64_t,std::pair<int,l1t::HGCalCluster> >& cluster_container, uint64_t pid,int pdgid,float energy,float eta, float phi)
81  {
82 
83  auto pair = cluster_container.emplace(pid, std::pair<int,l1t::HGCalCluster>(0,l1t::HGCalCluster() ) ) ;
84  auto iterator = pair.first;
86  p4.SetPt ( iterator -> second . second . pt() ) ;
87  p4.SetEta( iterator -> second . second . eta() ) ;
88  p4.SetPhi( iterator -> second . second . phi() ) ;
89  p4.SetM ( iterator -> second . second . mass() ) ;
91  float t = std::exp (- eta);
92  pp4.SetPt ( energy * (2*t)/(1+t*t) ) ;
93  pp4.SetEta( eta ) ;
94  pp4.SetPhi( phi ) ;
95  pp4.SetM ( 0 ) ;
96  p4 += pp4;
97  iterator -> second . second . setP4(p4);
98  //iterator -> second . second . shapes().Add( energy,eta,phi,r); // last is r, for 3d clusters
99  return ;
100  }
101 
103  protected:
105 
106  public:
107  // Constructor
108  //
115 
116  //Consumes tokens
118  Algorithm<FECODEC>(conf,cc),
119  HGCalEESensitive_(conf.getParameter<std::string>("HGCalEESensitive_tag")),
120  HGCalHESiliconSensitive_(conf.getParameter<std::string>("HGCalHESiliconSensitive_tag")),
121  calibration_(conf.getParameterSet("calib_parameters"))
122  {
123  sim_token_ = cc.consumes< std::vector< SimCluster > >(conf.getParameter<edm::InputTag>("simcollection"));
124  inputee_ = cc.consumes<edm::PCaloHitContainer>( conf.getParameter<edm::InputTag>("simhitsee"));
125  inputfh_ = cc.consumes<edm::PCaloHitContainer>( conf.getParameter<edm::InputTag>("simhitsfh"));
126  // inputbh_ = cc.consumes<edm::PCaloHitContainer>(conf.getParameter<edm::InputTag>("g4SimHits:HGCHitsHEback"));
127  edm::LogWarning("HGCalTriggerSimCluster") <<"WARNING: BH simhits not loaded";
128  }
129 
130  // setProduces
132  {
134  }
135 
136  // putInEvent
137  void putInEvent(edm::Event& evt) final
138  {
139  evt.put(std::move(cluster_product_),name());
140  }
141 
142  //reset
143  void reset() final
144  {
145  cluster_product_.reset( new l1t::HGCalClusterBxCollection );
146  }
147 
148  // run, actual algorithm
150  const edm::EventSetup& es,
151  edm::Event&evt
152  ) override
153  {
154  //0.5. Get Digis, construct a map, detid -> energy
155 
157  evt.getByToken(inputee_,ee_simhits_h);
158 
160  evt.getByToken(inputfh_,fh_simhits_h);
161 
163  //evt.getByToken(inputbh_,bh_simhits_h);
164 
165 
166  if (not ee_simhits_h.isValid()){
167  throw cms::Exception("ContentError")<<"[HGCalTriggerSimCluster]::[run]::[ERROR] EE Digis from HGC not available";
168  }
169  if (not fh_simhits_h.isValid()){
170  throw cms::Exception("ContentError")<<"[HGCalTriggerSimCluster]::[run]::[ERROR] FH Digis from HGC not available";
171  }
172 
173  std::unordered_map<uint64_t, double> hgc_simhit_energy;
174 
175  edm::ESHandle<HGCalTopology> topo_ee, topo_fh;
176  es.get<IdealGeometryRecord>().get("HGCalEESensitive",topo_ee);
177  es.get<IdealGeometryRecord>().get("HGCalHESiliconSensitive",topo_fh);
178 
179  if (ee_simhits_h.isValid())
180  {
181  int layer=0,cell=0, sec=0, subsec=0, zp=0,subdet=0;
182  ForwardSubdetector mysubdet;
183  for (const auto& simhit : *ee_simhits_h)
184  {
185  HGCalTestNumbering::unpackHexagonIndex(simhit.id(), subdet, zp, layer, sec, subsec, cell);
186  mysubdet = (ForwardSubdetector)(subdet);
187  std::pair<int,int> recoLayerCell = topo_ee->dddConstants().simToReco(cell,layer,sec,topo_ee->detectorType());
188  cell = recoLayerCell.first;
189  layer = recoLayerCell.second;
190  if (layer<0 || cell<0) {
191  continue;
192  }
193  unsigned recoCell = HGCalDetId(mysubdet,zp,layer,subsec,sec,cell);
194 
195  hgc_simhit_energy[recoCell] += simhit.energy();
196  }
197  }
198  if (fh_simhits_h.isValid())
199  {
200  int layer=0,cell=0, sec=0, subsec=0, zp=0,subdet=0;
201  ForwardSubdetector mysubdet;
202  for (const auto& simhit : *fh_simhits_h)
203  {
204  HGCalTestNumbering::unpackHexagonIndex(simhit.id(), subdet, zp, layer, sec, subsec, cell);
205  mysubdet = (ForwardSubdetector)(subdet);
206  std::pair<int,int> recoLayerCell = topo_fh->dddConstants().simToReco(cell,layer,sec,topo_fh->detectorType());
207  cell = recoLayerCell.first;
208  layer = recoLayerCell.second;
209  if (layer<0 || cell<0) {
210  continue;
211  }
212  unsigned recoCell = HGCalDetId(mysubdet,zp,layer,subsec,sec,cell);
213  hgc_simhit_energy[recoCell] += simhit.energy();
214  }
215  }
216 
217  if (bh_simhits_h.isValid() )
218  {
219  throw cms::Exception("Not Implemented")<<"HGCalTriggerSimCluster: BH simhits not implemnted";
220 
221  }
222 
223  //1. construct a cluster container that hosts the cluster per truth-particle
224  std::unordered_map<uint64_t,std::pair<int,l1t::HGCalCluster> > cluster_container;// PID-> bx,cluster
225  evt.getByToken(sim_token_,sim_handle_);
226 
227  if (not sim_handle_.isValid()){
228  throw cms::Exception("ContentError")<<"[HGCalTriggerSimCluster]::[run]::[ERROR] Sim Cluster collection for HGC sim clustering not available";
229  }
230  // calibration
231  es.get<IdealGeometryRecord>().get(HGCalEESensitive_, hgceeTopoHandle_);
232  es.get<IdealGeometryRecord>().get(HGCalHESiliconSensitive_, hgchefTopoHandle_);
233 
234  // 1.5. pre-process the sim cluster to have easy accessible information
235  // I want a map cell-> [ (pid, fraction), ...
236  std::unordered_map<uint32_t, std::vector<std::pair< uint64_t, float > > > simclusters;
237  for (auto& cluster : *sim_handle_)
238  {
239  auto pid= cluster.particleId(); // not pdgId
240  const auto& hf = cluster.hits_and_fractions();
241  for (const auto & p : hf )
242  {
243  simclusters[p.first].push_back( std::pair<uint64_t, float>( pid,p.second) ) ;
244  }
245  }
246 
247  //2. run on the digits,
248  for( const auto& digi : coll )
249  {
250  DATA data;
251  digi.decode(codec_,data);
252  //2.A get the trigger-cell information energy/id
253  //const HGCTriggerDetId& moduleId = digi.getDetId<HGCTriggerDetId>(); // this is a module Det Id
254 
255  // there is a loss of generality here, due to the restriction imposed by the data formats
256  // it will work if inside a module there is a data.payload with an ordered list of all the energies
257  // one may think to add on top of it a wrapper if this stop to be the case for some of the data classes
258  for(const auto& triggercell : data.payload)
259  {
260  if(triggercell.hwPt()<=0) continue;
261 
262  const HGCalDetId tcellId(triggercell.detId());
263  // calbration
264 
265  l1t::HGCalTriggerCell calibratedtriggercell(triggercell);
266  calibration_.calibrateInGeV(calibratedtriggercell);
267  //uint32_t digiEnergy = data.payload;
268  //auto digiEnergy=triggercell.p4().E();
269  // using calibrated energy instead
270  auto calibratedDigiEnergy=calibratedtriggercell.p4().E();
271  double eta=triggercell.p4().Eta();
272  double phi=triggercell.p4().Phi();
273  double z = triggercell.position().z(); // may be useful for cluster shapes
274  //2.B get the HGCAL-base-cell associated to it / geometry
275 
276  // normalization loop
277  double norm=0.0;
278  map<unsigned, double> energy_for_cluster_shapes;
279 
280  for(const auto& cell : geometry_->getCellsFromTriggerCell( tcellId()) ) // HGCcell -- unsigned
281  {
282  HGCalDetId cellId(cell);
283 
284  //2.C0 find energy of the hgc cell. default is very small value
285  double hgc_energy=1.0e-10; //average if not found / bh
286  const auto &it = hgc_simhit_energy.find(cell);
287  if (it != hgc_simhit_energy.end()) { hgc_energy = it->second; }
288 
289  //2.C get the particleId and energy fractions
290  const auto & iterator= simclusters.find(cellId);
291  if (iterator == simclusters.end() ) continue;
292  const auto & particles = iterator->second;
293  for ( const auto& p: particles )
294  {
295  const auto & pid= p.first;
296  const auto & fraction=p.second;
297  norm += fraction * hgc_energy;
298  energy_for_cluster_shapes[pid] += calibratedDigiEnergy *fraction *hgc_energy; // norm will be done later, with the above norm
299  }
300  }
301 
302  // second loop counting the energy
303  for(const auto& cell : geometry_->getCellsFromTriggerCell( tcellId()) ) // HGCcell -- unsigned
304  {
305  HGCalDetId cellId(cell);
306  double hgc_energy=1.0e-10; // 1 -> average if not found / bh
307  const auto &it = hgc_simhit_energy.find(cell);
308  if (it != hgc_simhit_energy.end()) { hgc_energy = it->second; }
309  //2.C get the particleId and energy fractions
310  const auto & iterator= simclusters.find(cellId);
311  if (iterator == simclusters.end() ) continue;
312  const auto & particles = iterator->second;
313  for ( const auto& p: particles )
314  {
315  const auto & pid= p.first;
316  const auto & fraction=p.second;
317  //auto energy = fraction * calibratedDigiEnergy/norm;
318  auto energy = fraction * hgc_energy* calibratedDigiEnergy/norm; // THIS IS WHAT I WANT
319  //#warning FIXME_ENERGY
320  //auto energy = fraction * hgc_energy* hgc_energy/norm;
321 
322  //2.D add to the corresponding cluster
323  //eta/phi are the position of the trigger cell, to consider degradation
324  addToCluster(cluster_container, pid, 0,energy,eta,phi ) ;
325  }
326  }
327 
328  // third loop, cluster shapes to ensure the correct counts
329  for(const auto& iterator :energy_for_cluster_shapes)
330  {
331  double energy = iterator.second / norm;
332  unsigned pid = iterator.first;
333  addToClusterShapes(cluster_container, pid, 0,energy,eta,phi,z ) ;// only one for trigger cell
334  }
335  } //end of for-loop
336  }
337 
338  //3. Push the clusters in the cluster_product_
339  for (auto& p : cluster_container)
340  {
341  //std::unordered_map<uint64_t,std::pair<int,l1t::HGCalCluster> >
342  cluster_product_->push_back(p.second.first,p.second.second); // bx,cluster
343  }
344 
345  } // end run
346 
347 
348  }; // end class
349 
350 }// namespace
351 
352 
353 // define plugins, template needs to be spelled out here, in order to allow the compiler to compile, and the factory to be populated
354 //
357 
360 
EDGetTokenT< ProductType > consumes(edm::InputTag const &tag)
HGCalTriggerSimCluster(const edm::ParameterSet &conf, edm::ConsumesCollector &cc)
T getParameter(std::string const &) const
HGCalTriggerBackend::HGCalTriggerSimCluster< HGCalTriggerCellBestChoiceCodec, HGCalTriggerCellBestChoiceDataPayload > HGCalTriggerSimClusterBestChoice
const HGCalTriggerGeometryBase * geometry_
std::vector< PCaloHit > PCaloHitContainer
ROOT::Math::LorentzVector< ROOT::Math::PtEtaPhiM4D< double > > PtEtaPhiMLorentzVectorD
Lorentz vector with cartesian internal representation.
Definition: LorentzVector.h:10
virtual geom_set getCellsFromTriggerCell(const unsigned cell_det_id) const =0
HGCalTriggerCellCalibration calibration_
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:579
HGCalTriggerBackend::HGCalTriggerSimCluster< HGCalTriggerCellThresholdCodec, HGCalTriggerCellThresholdDataPayload > HGCalTriggerSimClusterThreshold
ParameterSet const & getParameterSet(ParameterSetID const &id)
bool detectorType() const
edm::EDGetTokenT< std::vector< SimCluster > > sim_token_
edm::ESHandle< HGCalTopology > hgchefTopoHandle_
ForwardSubdetector
return((rh^lh)&mask)
U second(std::pair< T, U > const &p)
std::pair< int, int > simToReco(int cell, int layer, int mod, bool half) const
double p4[4]
Definition: TauolaWrapper.h:92
void addToCluster(std::unordered_map< uint64_t, std::pair< int, l1t::HGCalCluster > > &cluster_container, uint64_t pid, int pdgid, float energy, float eta, float phi)
bool isValid() const
Definition: HandleBase.h:74
edm::Handle< std::vector< SimCluster > > sim_handle_
void run(const l1t::HGCFETriggerDigiCollection &coll, const edm::EventSetup &es, edm::Event &evt) override
JetCorrectorParametersCollection coll
Definition: classes.h:10
unsigned long long uint64_t
Definition: Time.h:15
const HGCalDDDConstants & dddConstants() const
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:82
void addToClusterShapes(std::unordered_map< uint64_t, std::pair< int, l1t::HGCalCluster > > &cluster_container, uint64_t pid, int pdgid, float energy, float eta, float phi, float r=0.0)
T get() const
Definition: EventSetup.h:63
#define DEFINE_EDM_PLUGIN(factory, type, name)
std::unique_ptr< l1t::HGCalClusterBxCollection > cluster_product_
void setProduces(edm::stream::EDProducer<> &prod) const final
void calibrateInGeV(l1t::HGCalTriggerCell &)
static void unpackHexagonIndex(const uint32_t &idx, int &subdet, int &z, int &lay, int &wafer, int &celltyp, int &cell)
def move(src, dest)
Definition: eostools.py:510
edm::ESHandle< HGCalTopology > hgceeTopoHandle_