CMS 3D CMS Logo

SiPixelLorentzAnglePCLHarvester.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: CalibTracker/SiPixelLorentzAnglePCLHarvester
4 // Class: SiPixelLorentzAnglePCLHarvester
5 //
12 //
13 // Original Author: mmusich
14 // Created: Sat, 29 May 2021 14:46:19 GMT
15 //
16 //
17 
18 // system includes
19 #include <fmt/format.h>
20 #include <fmt/printf.h>
21 #include <fstream>
22 
23 // user includes
41 
42 /*
43  * Auxilliary struct to store fit results
44  */
45 namespace SiPixelLAHarvest {
46  struct fitResults {
47  public:
49  // set all parameters to default
50  p0 = p1 = p2 = p3 = p4 = p5 = 0.;
51  e0 = e1 = e2 = e3 = e4 = e5 = 0.;
52  chi2 = prob = redChi2 = tan_LA = error_LA = -9999.;
53  ndf = -999;
54  };
55 
56  double p0;
57  double e0;
58  double p1;
59  double e1;
60  double p2;
61  double e2;
62  double p3;
63  double e3;
64  double p4;
65  double e4;
66  double p5;
67  double e5;
68  double chi2;
69  int ndf;
70  double prob;
71  double redChi2;
72  double tan_LA;
73  double error_LA;
74  };
75 } // namespace SiPixelLAHarvest
76 
77 //------------------------------------------------------------------------------
79 public:
81  ~SiPixelLorentzAnglePCLHarvester() override = default;
82  void beginRun(const edm::Run&, const edm::EventSetup&) override;
83 
85 
86 private:
88  void endRun(const edm::Run&, const edm::EventSetup&) override;
89  void findMean(MonitorElement* h_drift_depth_adc_slice_, int i, int i_ring);
90  SiPixelLAHarvest::fitResults fitAndStore(std::shared_ptr<SiPixelLorentzAngle> theLA, int i_idx, int i_lay, int i_mod);
91 
92  // es tokens
97 
98  std::vector<std::string> newmodulelist_;
100  const double fitChi2Cut_;
101  const int minHitsCut_;
103  std::unique_ptr<TF1> f1_;
104  float width_;
105  float theMagField_{0.f};
106 
107  static constexpr float inverseGeVtoTesla_ = 2.99792458e-3f;
108 
111  std::unique_ptr<TrackerTopology> theTrackerTopology_;
112 };
113 
114 //------------------------------------------------------------------------------
116  : geomEsToken_(esConsumes<edm::Transition::BeginRun>()),
117  topoEsTokenBR_(esConsumes<edm::Transition::BeginRun>()),
118  topoEsTokenER_(esConsumes<edm::Transition::EndRun>()),
119  siPixelLAEsToken_(esConsumes<edm::Transition::BeginRun>()),
120  magneticFieldToken_(esConsumes<edm::Transition::BeginRun>()),
121  newmodulelist_(iConfig.getParameter<std::vector<std::string>>("newmodulelist")),
122  dqmDir_(iConfig.getParameter<std::string>("dqmDir")),
123  fitChi2Cut_(iConfig.getParameter<double>("fitChi2Cut")),
124  minHitsCut_(iConfig.getParameter<int>("minHitsCut")),
125  recordName_(iConfig.getParameter<std::string>("record")) {
126  // first ensure DB output service is available
128  if (!poolDbService.isAvailable())
129  throw cms::Exception("SiPixelLorentzAnglePCLHarvester") << "PoolDBService required";
130 }
131 
132 //------------------------------------------------------------------------------
134  // geometry
135  const TrackerGeometry* geom = &iSetup.getData(geomEsToken_);
136  const TrackerTopology* tTopo = &iSetup.getData(topoEsTokenBR_);
137 
138  const MagneticField* magField = &iSetup.getData(magneticFieldToken_);
140 
141  // B-field value
142  // inverseBzAtOriginInGeV() returns the inverse of field z component for this map in GeV
143  // for the conversion please consult https://github.com/cms-sw/cmssw/blob/master/MagneticField/Engine/src/MagneticField.cc#L17
144  // theInverseBzAtOriginInGeV = 1.f / (at0z * 2.99792458e-3f);
145  // ==> at0z = 1.f / (theInverseBzAtOriginInGeV * 2.99792458e-3f)
146 
148 
150  hists_.nlay = geom->numberOfLayers(PixelSubdetector::PixelBarrel);
151  hists_.nModules_.resize(hists_.nlay);
152  hists_.nLadders_.resize(hists_.nlay);
153  for (int i = 0; i < hists_.nlay; i++) {
154  hists_.nModules_[i] = map.getPXBModules(i + 1);
155  hists_.nLadders_[i] = map.getPXBLadders(i + 1);
156  }
157 
158  // list of modules already filled, then return (we already entered here)
159  if (!hists_.BPixnewDetIds_.empty() || !hists_.FPixnewDetIds_.empty())
160  return;
161 
162  if (!newmodulelist_.empty()) {
163  for (auto const& modulename : newmodulelist_) {
164  if (modulename.find("BPix_") != std::string::npos) {
165  PixelBarrelName bn(modulename, true);
166  const auto& detId = bn.getDetId(tTopo);
167  hists_.BPixnewmodulename_.push_back(modulename);
168  hists_.BPixnewDetIds_.push_back(detId.rawId());
169  hists_.BPixnewModule_.push_back(bn.moduleName());
170  hists_.BPixnewLayer_.push_back(bn.layerName());
171  } else if (modulename.find("FPix_") != std::string::npos) {
172  PixelEndcapName en(modulename, true);
173  const auto& detId = en.getDetId(tTopo);
174  hists_.FPixnewmodulename_.push_back(modulename);
175  hists_.FPixnewDetIds_.push_back(detId.rawId());
176  hists_.FPixnewDisk_.push_back(en.diskName());
177  hists_.FPixnewBlade_.push_back(en.bladeName());
178  }
179  }
180  }
181 
182  uint count = 0;
183  for (const auto& id : hists_.BPixnewDetIds_) {
184  LogDebug("SiPixelLorentzAnglePCLHarvester") << id;
185  count++;
186  }
187  LogDebug("SiPixelLorentzAnglePCLHarvester") << "Stored a total of " << count << " new detIds.";
188 
189  // list of modules already filled, return (we already entered here)
190  if (!hists_.detIdsList.empty())
191  return;
192 
193  std::vector<uint32_t> treatedIndices;
194 
195  for (auto det : geom->detsPXB()) {
196  const PixelGeomDetUnit* pixelDet = dynamic_cast<const PixelGeomDetUnit*>(det);
197  width_ = pixelDet->surface().bounds().thickness();
198  const auto& layer = tTopo->pxbLayer(pixelDet->geographicalId());
199  const auto& module = tTopo->pxbModule(pixelDet->geographicalId());
200  int i_index = module + (layer - 1) * hists_.nModules_[layer - 1];
201 
202  uint32_t rawId = pixelDet->geographicalId().rawId();
203 
204  // if the detId is already accounted for in the special class, do not attach it
205  if (std::find(hists_.BPixnewDetIds_.begin(), hists_.BPixnewDetIds_.end(), rawId) != hists_.BPixnewDetIds_.end())
206  continue;
207 
208  if (std::find(treatedIndices.begin(), treatedIndices.end(), i_index) != treatedIndices.end()) {
209  hists_.detIdsList[i_index].push_back(rawId);
210  } else {
211  hists_.detIdsList.insert(std::pair<uint32_t, std::vector<uint32_t>>(i_index, {rawId}));
212  treatedIndices.push_back(i_index);
213  }
214  }
215 
216  count = 0;
217  for (const auto& i : treatedIndices) {
218  for (const auto& id : hists_.detIdsList[i]) {
219  LogDebug("SiPixelLorentzAnglePCLHarvester") << id;
220  count++;
221  };
222  }
223  LogDebug("SiPixelLorentzAnglePCLHarvester") << "Stored a total of " << count << " detIds.";
224 }
225 
226 //------------------------------------------------------------------------------
228  if (!theTrackerTopology_) {
229  theTrackerTopology_ = std::make_unique<TrackerTopology>(isetup.getData(topoEsTokenER_));
230  }
231 }
232 
233 //------------------------------------------------------------------------------
235  // go in the right directory
236  iGetter.cd();
237  iGetter.setCurrentFolder(dqmDir_);
238 
239  // fetch the 2D histograms
240  for (int i_layer = 1; i_layer <= hists_.nlay; i_layer++) {
241  const auto& prefix_ = fmt::sprintf("%s/BPix/BPixLayer%i", dqmDir_, i_layer);
242  for (int i_module = 1; i_module <= hists_.nModules_[i_layer - 1]; i_module++) {
243  int i_index = i_module + (i_layer - 1) * hists_.nModules_[i_layer - 1];
244 
245  hists_.h_drift_depth_[i_index] =
246  iGetter.get(fmt::format("{}/h_drift_depth_layer{}_module{}", prefix_, i_layer, i_module));
247 
248  if (hists_.h_drift_depth_[i_index] == nullptr) {
249  edm::LogError("SiPixelLorentzAnglePCLHarvester::dqmEndJob")
250  << "Failed to retrieve electron drift over depth for layer " << i_layer << ", module " << i_module << ".";
251  continue;
252  }
253 
254  hists_.h_drift_depth_adc_[i_index] =
255  iGetter.get(fmt::format("{}/h_drift_depth_adc_layer{}_module{}", prefix_, i_layer, i_module));
256 
257  hists_.h_drift_depth_adc2_[i_index] =
258  iGetter.get(fmt::format("{}/h_drift_depth_adc2_layer{}_module{}", prefix_, i_layer, i_module));
259 
260  hists_.h_drift_depth_noadc_[i_index] =
261  iGetter.get(fmt::format("{}/h_drift_depth_noadc_layer{}_module{}", prefix_, i_layer, i_module));
262 
263  hists_.h_mean_[i_index] = iGetter.get(fmt::format("{}/h_mean_layer{}_module{}", dqmDir_, i_layer, i_module));
264 
265  hists_.h_drift_depth_[i_index]->divide(
266  hists_.h_drift_depth_adc_[i_index], hists_.h_drift_depth_noadc_[i_index], 1., 1., "");
267  }
268  }
269 
270  // fetch the new modules 2D histograms
271  for (int i = 0; i < (int)hists_.BPixnewDetIds_.size(); i++) {
272  int new_index = i + 1 + hists_.nModules_[hists_.nlay - 1] + (hists_.nlay - 1) * hists_.nModules_[hists_.nlay - 1];
273 
274  hists_.h_drift_depth_[new_index] = iGetter.get(
275  fmt::format("{}/h_BPixnew_drift_depth_{}", dqmDir_ + "/BPix/NewModules", hists_.BPixnewmodulename_[i]));
276 
277  if (hists_.h_drift_depth_[new_index] == nullptr) {
278  edm::LogError("SiPixelLorentzAnglePCLHarvester")
279  << "Failed to retrieve electron drift over depth for new module " << hists_.BPixnewmodulename_[i] << ".";
280  continue;
281  }
282 
283  hists_.h_drift_depth_adc_[new_index] = iGetter.get(
284  fmt::format("{}/h_BPixnew_drift_depth_adc_{}", dqmDir_ + "/BPix/NewModules", hists_.BPixnewmodulename_[i]));
285 
286  hists_.h_drift_depth_adc2_[new_index] = iGetter.get(
287  fmt::format("{}/h_BPixnew_drift_depth_adc2_{}", dqmDir_ + "/BPix/NewModules", hists_.BPixnewmodulename_[i]));
288 
289  hists_.h_drift_depth_noadc_[new_index] = iGetter.get(
290  fmt::format("{}/h_BPixnew_drift_depth_noadc_{}", dqmDir_ + "/BPix/NewModules", hists_.BPixnewmodulename_[i]));
291 
292  hists_.h_mean_[new_index] = iGetter.get(fmt::format("{}/h_BPixnew_mean_{}", dqmDir_, hists_.BPixnewmodulename_[i]));
293 
294  hists_.h_drift_depth_[new_index]->divide(
295  hists_.h_drift_depth_adc_[new_index], hists_.h_drift_depth_noadc_[new_index], 1., 1., "");
296  }
297 
298  hists_.h_bySectOccupancy_ = iGetter.get(fmt::format("{}/h_bySectorOccupancy", dqmDir_ + "/SectorMonitoring"));
299  if (hists_.h_bySectOccupancy_ == nullptr) {
300  edm::LogError("SiPixelLorentzAnglePCLHarvester") << "Failed to retrieve the hit on track occupancy.";
301  return;
302  }
303 
304  int hist_drift_;
305  int hist_depth_;
306  double min_drift_;
307  double max_drift_;
308 
309  if (hists_.h_drift_depth_adc_[1] != nullptr) {
310  hist_drift_ = hists_.h_drift_depth_adc_[1]->getNbinsX();
311  hist_depth_ = hists_.h_drift_depth_adc_[1]->getNbinsY();
312  min_drift_ = hists_.h_drift_depth_adc_[1]->getAxisMin(1);
313  max_drift_ = hists_.h_drift_depth_adc_[1]->getAxisMax(1);
314  } else {
315  hist_drift_ = 100;
316  hist_depth_ = 50;
317  min_drift_ = -500.;
318  max_drift_ = 500.;
319  }
320 
321  iBooker.setCurrentFolder(fmt::format("{}Harvesting", dqmDir_));
322  MonitorElement* h_drift_depth_adc_slice_ =
323  iBooker.book1D("h_drift_depth_adc_slice", "slice of adc histogram", hist_drift_, min_drift_, max_drift_);
324 
325  // book histogram of differences
326  MonitorElement* h_diffLA = iBooker.book1D(
327  "h_diffLA", "difference in #mu_{H}; #Delta #mu_{H}/#mu_{H} (old-new)/old [%];n. modules", 100, -150, 150);
328 
329  // retrieve the number of bins from the other monitoring histogram
330  const auto& maxSect = hists_.h_bySectOccupancy_->getNbinsX();
331  const double lo = -0.5;
332  const double hi = maxSect - 0.5;
333 
334  // this will be booked in the Harvesting folder
335  iBooker.setCurrentFolder(fmt::format("{}Harvesting/SectorMonitoring", dqmDir_));
336  std::string repText = "%s tan#theta_{LA}/B by sector;pixel sector;%s tan(#theta_{LA})/B [1/T]";
338  iBooker.book1D("h_LAbySector_Measured", fmt::sprintf(repText, "measured", "measured"), maxSect, lo, hi);
340  iBooker.book1D("h_LAbySector_Accepted", fmt::sprintf(repText, "accepted", "accepted"), maxSect, lo, hi);
342  iBooker.book1D("h_LAbySector_Rejected", fmt::sprintf(repText, "rejected", "rejected"), maxSect, lo, hi);
343  hists_.h_bySectLA_ = iBooker.book1D("h_LAbySector", fmt::sprintf(repText, "payload", "payload"), maxSect, lo, hi);
345  iBooker.book1D("h_deltaLAbySector", fmt::sprintf(repText, "#Delta", "#Delta"), maxSect, lo, hi);
347  iBooker.book1D("h_bySectorChi2", "Fit #chi^{2}/ndf by sector;pixel sector; fit #chi^{2}/ndf", maxSect, lo, hi);
348 
349  // copy the bin labels from the occupancy histogram
350  for (int bin = 1; bin <= maxSect; bin++) {
351  const auto& binName = hists_.h_bySectOccupancy_->getTH1()->GetXaxis()->GetBinLabel(bin);
355  hists_.h_bySectLA_->setBinLabel(bin, binName);
357  hists_.h_bySectChi2_->setBinLabel(bin, binName);
358  }
359 
360  // this will be booked in the Harvesting folder
361  iBooker.setCurrentFolder(fmt::format("{}Harvesting/LorentzAngleMaps", dqmDir_));
362  for (int i = 0; i < hists_.nlay; i++) {
363  std::string repName = "h2_byLayerLA_%i";
364  std::string repText = "BPix Layer %i tan#theta_{LA}/B;module number;ladder number;tan#theta_{LA}/B [1/T]";
365 
366  hists_.h2_byLayerLA_.emplace_back(iBooker.book2D(fmt::sprintf(repName, i + 1),
367  fmt::sprintf(repText, i + 1),
368  hists_.nModules_[i],
369  0.5,
370  hists_.nModules_[i] + 0.5,
371  hists_.nLadders_[i],
372  0.5,
373  hists_.nLadders_[i] + 0.5));
374 
375  repName = "h2_byLayerDiff_%i";
376  repText = "BPix Layer %i #Delta#mu_{H}/#mu_{H};module number;ladder number;#Delta#mu_{H}/#mu_{H} [%%]";
377  hists_.h2_byLayerDiff_.emplace_back(iBooker.book2D(fmt::sprintf(repName, i + 1),
378  fmt::sprintf(repText, i + 1),
379  hists_.nModules_[i],
380  0.5,
381  hists_.nModules_[i] + 0.5,
382  hists_.nLadders_[i],
383  0.5,
384  hists_.nLadders_[i] + 0.5));
385  }
386 
387  // clang-format off
388  edm::LogPrint("LorentzAngle") << "module" << "\t" << "layer" << "\t"
389  << "offset" << "\t" << "e0" << "\t"
390  << "slope" << "\t" << "e1" << "\t"
391  << "rel.err" << "\t" << "pull" << "\t"
392  << "p2" << "\t" << "e2" << "\t"
393  << "p3" << "\t" << "e3" << "\t"
394  << "p4" << "\t" << "e4" << "\t"
395  << "p5" << "\t" << "e5" << "\t"
396  << "chi2" << "\t" << "prob" << "\t"
397  << "newDetId" << "\t" << "tan(LA)" << "\t"
398  << "Error(LA)" ;
399  // clang-format on
400 
401  // payload to be written out
402  std::shared_ptr<SiPixelLorentzAngle> LorentzAngle = std::make_shared<SiPixelLorentzAngle>();
403 
404  // fill the map of simulation values
405  double p1_simul_newmodule = 0.294044;
406  double p1_simul[hists_.nlay + 1][hists_.nModules_[hists_.nlay - 1]];
407  for (int i_layer = 1; i_layer <= hists_.nlay; i_layer++) {
408  for (int i_module = 1; i_module <= hists_.nModules_[i_layer - 1]; i_module++) {
409  if (i_layer == 1)
410  p1_simul[i_layer - 1][i_module - 1] = 0.436848;
411  else if (i_layer == 2)
412  p1_simul[i_layer - 1][i_module - 1] = 0.25802;
413  else if (i_layer == 3 && i_module <= 4)
414  p1_simul[i_layer - 1][i_module - 1] = 0.29374;
415  else if (i_layer == 3 && i_module >= 5)
416  p1_simul[i_layer - 1][i_module - 1] = 0.31084;
417  else if (i_layer == 4 && i_module <= 4)
418  p1_simul[i_layer - 1][i_module - 1] = 0.29944;
419  else
420  p1_simul[i_layer - 1][i_module - 1] = 0.31426;
421  }
422  }
423  // fictitious n-th layer to store the values of new modules
424  for (int i_module = 1; i_module <= hists_.nModules_[hists_.nlay - 1]; i_module++) {
425  p1_simul[hists_.nlay][i_module - 1] = p1_simul_newmodule;
426  }
427 
428  // loop over "new" BPix modules
429  for (int j = 0; j < (int)hists_.BPixnewDetIds_.size(); j++) {
430  //uint32_t rawId = hists_.BPixnewDetIds_[j];
431  int new_index = j + 1 + hists_.nModules_[hists_.nlay - 1] + (hists_.nlay - 1) * hists_.nModules_[hists_.nlay - 1];
432  if (hists_.h_drift_depth_adc_[new_index] == nullptr)
433  continue;
434  for (int i = 1; i <= hist_depth_; i++) {
435  findMean(h_drift_depth_adc_slice_, i, new_index);
436  }
437 
438  // fit the distributions and store the LA in the payload
439  const auto& res = fitAndStore(LorentzAngle, new_index, hists_.BPixnewLayer_[j], hists_.BPixnewModule_[j]);
440 
441  edm::LogPrint("SiPixelLorentzAngle") << std::setprecision(4) << hists_.BPixnewModule_[j] << "\t"
442  << hists_.BPixnewLayer_[j] << "\t" << res.p0 << "\t" << res.e0 << "\t"
443  << res.p1 << std::setprecision(3) << "\t" << res.e1 << "\t"
444  << res.e1 / res.p1 * 100. << "\t"
445  << (res.p1 - p1_simul[hists_.nlay][0]) / res.e1 << "\t" << res.p2 << "\t"
446  << res.e2 << "\t" << res.p3 << "\t" << res.e3 << "\t" << res.p4 << "\t"
447  << res.e4 << "\t" << res.p5 << "\t" << res.e5 << "\t" << res.chi2 << "\t"
448  << res.prob << "\t" << hists_.BPixnewDetIds_[j] << "\t" << res.tan_LA << "\t"
449  << res.error_LA;
450  } // loop on BPix new modules
451 
452  //loop over modules and layers to fit the lorentz angle
453  for (int i_layer = 1; i_layer <= hists_.nlay; i_layer++) {
454  for (int i_module = 1; i_module <= hists_.nModules_[i_layer - 1]; i_module++) {
455  int i_index = i_module + (i_layer - 1) * hists_.nModules_[i_layer - 1];
456  if (hists_.h_drift_depth_adc_[i_index] == nullptr)
457  continue;
458  //loop over bins in depth (z-local-coordinate) (in order to fit slices)
459  for (int i = 1; i <= hist_depth_; i++) {
460  findMean(h_drift_depth_adc_slice_, i, i_index);
461  } // end loop over bins in depth
462 
463  // fit the distributions and store the LA in the payload
464  const auto& res = fitAndStore(LorentzAngle, i_index, i_layer, i_module);
465 
466  edm::LogPrint("SiPixelLorentzAngle")
467  << std::setprecision(4) << i_module << "\t" << i_layer << "\t" << res.p0 << "\t" << res.e0 << "\t" << res.p1
468  << std::setprecision(3) << "\t" << res.e1 << "\t" << res.e1 / res.p1 * 100. << "\t"
469  << (res.p1 - p1_simul[i_layer - 1][i_module - 1]) / res.e1 << "\t" << res.p2 << "\t" << res.e2 << "\t"
470  << res.p3 << "\t" << res.e3 << "\t" << res.p4 << "\t" << res.e4 << "\t" << res.p5 << "\t" << res.e5 << "\t"
471  << res.chi2 << "\t" << res.prob << "\t"
472  << "null"
473  << "\t" << res.tan_LA << "\t" << res.error_LA;
474  }
475  } // end loop over modules and layers
476 
477  // fill the rest of DetIds not filled above (for the moment FPix)
478  const auto& currentLAMap = currentLorentzAngle_->getLorentzAngles();
479  const auto& newLAMap = LorentzAngle->getLorentzAngles();
480  std::vector<unsigned int> currentLADets;
481  std::vector<unsigned int> newLADets;
482 
483  std::transform(currentLAMap.begin(),
484  currentLAMap.end(),
485  std::back_inserter(currentLADets),
486  [](const std::map<unsigned int, float>::value_type& pair) { return pair.first; });
487 
488  std::transform(newLAMap.begin(),
489  newLAMap.end(),
490  std::back_inserter(newLADets),
491  [](const std::map<unsigned int, float>::value_type& pair) { return pair.first; });
492 
493  std::vector<unsigned int> notCommon;
494  std::set_symmetric_difference(
495  currentLADets.begin(), currentLADets.end(), newLADets.begin(), newLADets.end(), std::back_inserter(notCommon));
496 
497  for (const auto& id : notCommon) {
498  float fPixLorentzAnglePerTesla_ = currentLorentzAngle_->getLorentzAngle(id);
499  if (!LorentzAngle->putLorentzAngle(id, fPixLorentzAnglePerTesla_)) {
500  edm::LogError("SiPixelLorentzAnglePCLHarvester")
501  << "[SiPixelLorentzAnglePCLHarvester::dqmEndJob] filling rest of payload: detid already exists";
502  }
503  }
504 
505  for (const auto& id : newLADets) {
506  float deltaMuHoverMuH = (currentLorentzAngle_->getLorentzAngle(id) - LorentzAngle->getLorentzAngle(id)) /
508  h_diffLA->Fill(deltaMuHoverMuH * 100.f);
509  }
510 
511  bool isPayloadChanged{false};
512  // fill the 2D output Lorentz Angle maps and check if the payload is different from the input one
513  for (const auto& [id, value] : LorentzAngle->getLorentzAngles()) {
514  DetId ID = DetId(id);
515  if (ID.subdetId() == PixelSubdetector::PixelBarrel) {
516  const auto& layer = theTrackerTopology_->pxbLayer(id);
517  const auto& ladder = theTrackerTopology_->pxbLadder(id);
518  const auto& module = theTrackerTopology_->pxbModule(id);
519  hists_.h2_byLayerLA_[layer - 1]->setBinContent(module, ladder, value);
520 
521  float deltaMuHoverMuH =
523  hists_.h2_byLayerDiff_[layer - 1]->setBinContent(module, ladder, deltaMuHoverMuH * 100.f);
524 
525  if (!isPayloadChanged && (deltaMuHoverMuH != 0.f))
526  isPayloadChanged = true;
527  }
528  }
529 
530  if (isPayloadChanged) {
531  // fill the DB object record
533  if (mydbservice.isAvailable()) {
534  try {
535  mydbservice->writeOneIOV(*LorentzAngle, mydbservice->currentTime(), recordName_);
536  } catch (const cond::Exception& er) {
537  edm::LogError("SiPixelLorentzAngleDB") << er.what();
538  } catch (const std::exception& er) {
539  edm::LogError("SiPixelLorentzAngleDB") << "caught std::exception " << er.what();
540  }
541  } else {
542  edm::LogError("SiPixelLorentzAngleDB") << "Service is unavailable";
543  }
544  } else {
545  edm::LogPrint("SiPixelLorentzAngleDB") << __PRETTY_FUNCTION__ << " there is no new valid measurement to append! ";
546  }
547 }
548 
549 //------------------------------------------------------------------------------
550 void SiPixelLorentzAnglePCLHarvester::findMean(MonitorElement* h_drift_depth_adc_slice_, int i, int i_ring) {
551  double nentries = 0;
552  h_drift_depth_adc_slice_->Reset();
553  int hist_drift_ = h_drift_depth_adc_slice_->getNbinsX();
554 
555  // determine sigma and sigma^2 of the adc counts and average adc counts
556  //loop over bins in drift width
557  for (int j = 1; j <= hist_drift_; j++) {
558  if (hists_.h_drift_depth_noadc_[i_ring]->getBinContent(j, i) >= 1) {
559  double adc_error2 = (hists_.h_drift_depth_adc2_[i_ring]->getBinContent(j, i) -
560  hists_.h_drift_depth_adc_[i_ring]->getBinContent(j, i) *
561  hists_.h_drift_depth_adc_[i_ring]->getBinContent(j, i) /
562  hists_.h_drift_depth_noadc_[i_ring]->getBinContent(j, i)) /
563  hists_.h_drift_depth_noadc_[i_ring]->getBinContent(j, i);
564 
565  hists_.h_drift_depth_adc_[i_ring]->setBinError(j, i, sqrt(adc_error2));
566  double error2 = adc_error2 / (hists_.h_drift_depth_noadc_[i_ring]->getBinContent(j, i) - 1.);
567  hists_.h_drift_depth_[i_ring]->setBinError(j, i, sqrt(error2));
568  } else {
569  hists_.h_drift_depth_[i_ring]->setBinError(j, i, 0);
570  hists_.h_drift_depth_adc_[i_ring]->setBinError(j, i, 0);
571  }
572  h_drift_depth_adc_slice_->setBinContent(j, hists_.h_drift_depth_adc_[i_ring]->getBinContent(j, i));
573  h_drift_depth_adc_slice_->setBinError(j, hists_.h_drift_depth_adc_[i_ring]->getBinError(j, i));
574  nentries += hists_.h_drift_depth_noadc_[i_ring]->getBinContent(j, i);
575  } // end loop over bins in drift width
576 
577  double mean = h_drift_depth_adc_slice_->getMean(1);
578  double error = 0;
579  if (nentries != 0) {
580  error = h_drift_depth_adc_slice_->getRMS(1) / std::sqrt(nentries);
581  }
582  hists_.h_mean_[i_ring]->setBinContent(i, mean);
583  hists_.h_mean_[i_ring]->setBinError(i, error);
584 
585  h_drift_depth_adc_slice_->Reset(); // clear again after extracting the parameters
586 }
587 
588 //------------------------------------------------------------------------------
590  std::shared_ptr<SiPixelLorentzAngle> theLAPayload, int i_index, int i_layer, int i_module) {
591  // output results
593 
594  double half_width = width_ * 10000 / 2; // pixel half thickness in units of micro meter
595 
596  f1_ = std::make_unique<TF1>("f1", "[0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + [5]*x*x*x*x*x", 5., 280.);
597  f1_->SetParName(0, "offset");
598  f1_->SetParName(1, "tan#theta_{LA}");
599  f1_->SetParName(2, "quad term");
600  f1_->SetParName(3, "cubic term");
601  f1_->SetParName(4, "quartic term");
602  f1_->SetParName(5, "quintic term");
603 
604  f1_->SetParameter(0, 0);
605  f1_->SetParError(0, 0);
606  f1_->SetParameter(1, 0.4);
607  f1_->SetParError(1, 0);
608  f1_->SetParameter(2, 0.0);
609  f1_->SetParError(2, 0);
610  f1_->SetParameter(3, 0.0);
611  f1_->SetParError(3, 0);
612  f1_->SetParameter(4, 0.0);
613  f1_->SetParError(4, 0);
614  f1_->SetParameter(5, 0.0);
615  f1_->SetParError(5, 0);
616  f1_->SetChisquare(0);
617 
618  hists_.h_mean_[i_index]->getTH1()->Fit(f1_.get(), "ERQ");
619 
620  res.p0 = f1_->GetParameter(0);
621  res.e0 = f1_->GetParError(0);
622  res.p1 = f1_->GetParameter(1);
623  res.e1 = f1_->GetParError(1);
624  res.p2 = f1_->GetParameter(2);
625  res.e2 = f1_->GetParError(2);
626  res.p3 = f1_->GetParameter(3);
627  res.e3 = f1_->GetParError(3);
628  res.p4 = f1_->GetParameter(4);
629  res.e4 = f1_->GetParError(4);
630  res.p5 = f1_->GetParameter(5);
631  res.e5 = f1_->GetParError(5);
632  res.chi2 = f1_->GetChisquare();
633  res.ndf = f1_->GetNDF();
634  res.prob = f1_->GetProb();
635  res.redChi2 = res.ndf > 0. ? res.chi2 / res.ndf : 0.;
636 
637  double f1_halfwidth = res.p0 + res.p1 * half_width + res.p2 * pow(half_width, 2) + res.p3 * pow(half_width, 3) +
638  res.p4 * pow(half_width, 4) + res.p5 * pow(half_width, 5);
639 
640  double f1_zerowidth = res.p0;
641 
642  // tan_LA = (f1(x = half_width) - f1(x = 0)) / (half_width - 0)
643  res.tan_LA = (f1_halfwidth - f1_zerowidth) / half_width;
644  double errsq_LA =
645  (pow(res.e1, 2) + pow((half_width * res.e2), 2) + pow((half_width * half_width * res.e3), 2) +
646  pow((half_width * half_width * half_width * res.e4), 2) +
647  pow((half_width * half_width * half_width * half_width * res.e5), 2)); // Propagation of uncertainty
648  res.error_LA = sqrt(errsq_LA);
649 
650  hists_.h_bySectMeasLA_->setBinContent(i_index, (res.tan_LA / theMagField_));
651  hists_.h_bySectMeasLA_->setBinError(i_index, (res.error_LA / theMagField_));
652  hists_.h_bySectChi2_->setBinContent(i_index, res.redChi2);
653  hists_.h_bySectChi2_->setBinError(i_index, 0.); // no errors
654 
655  int nentries = hists_.h_bySectOccupancy_->getBinContent(i_index); // number of on track hits in that sector
656 
657  bool isNew = (i_index > hists_.nlay * hists_.nModules_[hists_.nlay - 1]);
658  int shiftIdx = i_index - hists_.nlay * hists_.nModules_[hists_.nlay - 1] - 1;
659 
660  LogDebug("SiPixelLorentzAnglePCLHarvester")
661  << " isNew: " << isNew << " i_index: " << i_index << " shift index: " << shiftIdx;
662 
663  const auto& detIdsToFill =
664  isNew ? std::vector<unsigned int>({hists_.BPixnewDetIds_[shiftIdx]}) : hists_.detIdsList[i_index];
665 
666  LogDebug("SiPixelLorentzAnglePCLHarvester")
667  << "index: " << i_index << " i_module: " << i_module << " i_layer: " << i_layer;
668  for (const auto& id : detIdsToFill) {
669  LogDebug("SiPixelLorentzAnglePCLHarvester") << id << ",";
670  }
671 
672  // no errors on the following MEs
673  hists_.h_bySectSetLA_->setBinError(i_index, 0.);
674  hists_.h_bySectRejectLA_->setBinError(i_index, 0.);
675  hists_.h_bySectLA_->setBinError(i_index, 0.);
676  hists_.h_bySectDeltaLA_->setBinError(i_index, 0.);
677 
678  float LorentzAnglePerTesla_;
679  float currentLA = currentLorentzAngle_->getLorentzAngle(detIdsToFill.front());
680  // if the fit quality is OK
681  if ((res.redChi2 != 0.) && (res.redChi2 < fitChi2Cut_) && (nentries > minHitsCut_)) {
682  LorentzAnglePerTesla_ = res.tan_LA / theMagField_;
683  // fill the LA actually written to payload
684  hists_.h_bySectSetLA_->setBinContent(i_index, LorentzAnglePerTesla_);
685  hists_.h_bySectRejectLA_->setBinContent(i_index, 0.);
686  hists_.h_bySectLA_->setBinContent(i_index, LorentzAnglePerTesla_);
687 
688  const auto& deltaLA = (LorentzAnglePerTesla_ - currentLA);
689  hists_.h_bySectDeltaLA_->setBinContent(i_index, deltaLA);
690 
691  for (const auto& id : detIdsToFill) {
692  if (!theLAPayload->putLorentzAngle(id, LorentzAnglePerTesla_)) {
693  edm::LogError("SiPixelLorentzAnglePCLHarvester") << "[SiPixelLorentzAnglePCLHarvester::fitAndStore]: detid ("
694  << i_layer << "," << i_module << ") already exists";
695  }
696  }
697  } else {
698  // just copy the values from the existing payload
699  hists_.h_bySectSetLA_->setBinContent(i_index, 0.);
700  hists_.h_bySectRejectLA_->setBinContent(i_index, (res.tan_LA / theMagField_));
701  hists_.h_bySectLA_->setBinContent(i_index, currentLA);
702  hists_.h_bySectDeltaLA_->setBinContent(i_index, 0.);
703 
704  for (const auto& id : detIdsToFill) {
705  LorentzAnglePerTesla_ = currentLorentzAngle_->getLorentzAngle(id);
706  if (!theLAPayload->putLorentzAngle(id, LorentzAnglePerTesla_)) {
707  edm::LogError("SiPixelLorentzAnglePCLHarvester") << "[SiPixelLorentzAnglePCLHarvester::fitAndStore]: detid ("
708  << i_layer << "," << i_module << ") already exists";
709  }
710  }
711  }
712  // return the struct of fit details
713  return res;
714 }
715 
716 //------------------------------------------------------------------------------
719  desc.setComment("Harvester module of the SiPixel Lorentz Angle PCL monitoring workflow");
720  desc.add<std::vector<std::string>>("newmodulelist", {})->setComment("the list of DetIds for new sensors");
721  desc.add<std::string>("dqmDir", "AlCaReco/SiPixelLorentzAngle")->setComment("the directory of PCL Worker output");
722  desc.add<double>("fitChi2Cut", 20.)->setComment("cut on fit chi2/ndof to accept measurement");
723  desc.add<int>("minHitsCut", 10000)->setComment("cut on minimum number of on-track hits to accept measurement");
724  desc.add<std::string>("record", "SiPixelLorentzAngleRcd")->setComment("target DB record");
725  descriptions.addWithDefaultLabel(desc);
726 }
727 
std::vector< dqm::reco::MonitorElement * > h2_byLayerLA_
void addWithDefaultLabel(ParameterSetDescription const &psetDescription)
ESGetTokenH3DDVariant esConsumes(std::string const &Record, edm::ConsumesCollector &)
Definition: DeDxTools.cc:283
unsigned int pxbLayer(const DetId &id) const
Base exception class for the object to relational access.
Definition: Exception.h:11
virtual void setCurrentFolder(std::string const &fullpath)
Definition: DQMStore.cc:32
void beginRun(const edm::Run &, const edm::EventSetup &) override
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
int bladeName() const
blade id
edm::ESGetToken< TrackerTopology, TrackerTopologyRcd > topoEsTokenBR_
int moduleName() const
module id (index in z)
uint32_t ID
Definition: Definitions.h:24
void findMean(MonitorElement *h_drift_depth_adc_slice_, int i, int i_ring)
SiPixelLorentzAnglePCLHarvester(const edm::ParameterSet &)
SiPixelLAHarvest::fitResults fitAndStore(std::shared_ptr< SiPixelLorentzAngle > theLA, int i_idx, int i_lay, int i_mod)
edm::ESGetToken< TrackerTopology, TrackerTopologyRcd > topoEsTokenER_
const std::map< unsigned int, float > & getLorentzAngles() const
Log< level::Error, false > LogError
static void fillDescriptions(edm::ConfigurationDescriptions &)
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:19
Definition: Electron.h:6
std::unique_ptr< TrackerTopology > theTrackerTopology_
constexpr std::array< uint8_t, layerIndexSize > layer
float inverseBzAtOriginInGeV() const
The inverse of field z component for this map in GeV.
Definition: MagneticField.h:52
void Fill(long long x)
virtual float thickness() const =0
~SiPixelLorentzAnglePCLHarvester() override=default
virtual void Reset()
Remove all data from the ME, keept the empty histogram with all its settings.
edm::ESGetToken< SiPixelLorentzAngle, SiPixelLorentzAngleRcd > siPixelLAEsToken_
virtual double getRMS(int axis=1) const
get RMS of histogram along x, y or z axis (axis=1, 2, 3 respectively)
Definition: EPCuts.h:4
int diskName() const
disk id
T sqrt(T t)
Definition: SSEVec.h:19
std::unordered_map< uint32_t, std::vector< uint32_t > > detIdsList
edm::ESGetToken< TrackerGeometry, TrackerDigiGeometryRecord > geomEsToken_
Hash writeOneIOV(const T &payload, Time_t time, const std::string &recordName)
Transition
Definition: Transition.h:12
double f[11][100]
bool getData(T &iHolder) const
Definition: EventSetup.h:122
Definition: value.py:1
virtual void setBinLabel(int bin, const std::string &label, int axis=1)
set bin label for x, y or z axis (axis=1, 2, 3 respectively)
DetId geographicalId() const
The label of this GeomDet.
Definition: GeomDet.h:64
Log< level::Warning, true > LogPrint
SiPixelLorentzAngleCalibrationHistograms hists_
PXFDetId getDetId()
return DetId
Definition: DetId.h:17
const Plane & surface() const
The nominal surface of the GeomDet.
Definition: GeomDet.h:37
virtual void setBinContent(int binx, double content)
set content of bin (1-D)
constexpr uint32_t rawId() const
get the raw id
Definition: DetId.h:57
int layerName() const
layer id
MonitorElement * book2D(TString const &name, TString const &title, int nchX, double lowX, double highX, int nchY, double lowY, double highY, FUNC onbooking=NOOP())
Definition: DQMStore.h:212
virtual MonitorElement * get(std::string const &fullpath) const
Definition: DQMStore.cc:673
virtual double getMean(int axis=1) const
get mean value of histogram along x, y or z axis (axis=1, 2, 3 respectively)
HLT enums.
virtual int getNbinsX() const
get # of bins in X-axis
bool isAvailable() const
Definition: Service.h:40
virtual void setBinError(int binx, double error)
set uncertainty on content of bin (1-D)
unsigned int pxbModule(const DetId &id) const
MonitorElement * book1D(TString const &name, TString const &title, int const nchX, double const lowX, double const highX, FUNC onbooking=NOOP())
Definition: DQMStore.h:98
char const * what() const noexcept override
Definition: Exception.cc:103
float getLorentzAngle(const uint32_t &) const
edm::ESGetToken< MagneticField, IdealMagneticFieldRecord > magneticFieldToken_
PXBDetId getDetId()
return the DetId
std::vector< dqm::reco::MonitorElement * > h2_byLayerDiff_
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
void endRun(const edm::Run &, const edm::EventSetup &) override
Definition: Run.h:45
void dqmEndJob(DQMStore::IBooker &, DQMStore::IGetter &) override
#define LogDebug(id)
virtual double getBinContent(int binx) const
get content of bin (1-D)
const Bounds & bounds() const
Definition: Surface.h:87
unsigned transform(const HcalDetId &id, unsigned transformCode)