CMS 3D CMS Logo

CTPPSProtonReconstructionEfficiencyEstimatorData.cc
Go to the documentation of this file.
1 /****************************************************************************
2  * Authors:
3  * Jan Kašpar
4  * Mauricio Thiel
5  ****************************************************************************/
6 
14 
20 
22 
27 
28 #include "TFile.h"
29 #include "TH1D.h"
30 #include "TH2D.h"
31 #include "TProfile.h"
32 #include "TF1.h"
33 #include "TGraph.h"
34 
35 #include <map>
36 #include <string>
37 #include <sstream>
38 #include <utility>
39 
40 //----------------------------------------------------------------------------------------------------
41 
43 public:
45 
46  static void fillDescriptions(edm::ConfigurationDescriptions &descriptions);
47 
48 private:
49  void analyze(const edm::Event &, const edm::EventSetup &) override;
50  void endJob() override;
51 
54 
58  const bool useNewLHCInfo_;
61 
63 
65 
66  unsigned int n_prep_events_;
67 
68  unsigned int n_exp_prot_max_;
69 
70  std::vector<double> n_sigmas_;
71 
73 
74  unsigned int verbosity_;
75 
77 
78  struct ArmData {
79  unsigned int rpId_N, rpId_F;
80 
81  std::shared_ptr<const TSpline3> s_x_to_xi_N;
82 
83  unsigned int n_events_with_tracks;
84 
85  std::unique_ptr<TH1D> h_de_x, h_de_y;
86  std::unique_ptr<TH2D> h2_de_y_vs_de_x;
87 
90 
91  std::vector<double> n_sigmas;
92 
93  unsigned int n_exp_prot_max;
94 
95  struct EffPlots {
96  std::unique_ptr<TProfile> p_eff1_vs_x_N;
97  std::unique_ptr<TProfile> p_eff1_vs_xi_N;
98 
99  std::unique_ptr<TProfile> p_eff2_vs_x_N;
100  std::unique_ptr<TProfile> p_eff2_vs_xi_N;
101 
102  std::unique_ptr<TProfile> p_fr_match_unique, p_fr_match_non_unique;
104 
106  : p_eff1_vs_x_N(new TProfile("", ";x_{N} (mm);efficiency", 50, 0., 25.)),
107  p_eff1_vs_xi_N(new TProfile("", ";#xi_{si,N};efficiency", 50, 0., 0.25)),
108 
109  p_eff2_vs_x_N(new TProfile("", ";x_{N} (mm);efficiency", 50, 0., 25.)),
110  p_eff2_vs_xi_N(new TProfile("", ";#xi_{si,N};efficiency", 50, 0., 0.25)),
111 
112  p_fr_match_unique(new TProfile("", ";x_{N} (mm);fraction", 50, 0., 25.)),
113  p_fr_match_non_unique(new TProfile("", ";x_{N} (mm);fraction", 50, 0., 25.)),
114 
115  p_fr_signature_0(new TProfile("", ";x_{N} (mm);fraction", 50, 0., 25.)),
116  p_fr_signature_1(new TProfile("", ";x_{N} (mm);fraction", 50, 0., 25.)),
117  p_fr_signature_2(new TProfile("", ";x_{N} (mm);fraction", 50, 0., 25.)),
118  p_fr_signature_12(new TProfile("", ";x_{N} (mm);fraction", 50, 0., 25.)) {}
119 
120  void write() const {
121  p_eff1_vs_x_N->Write("p_eff1_vs_x_N");
122  p_eff1_vs_xi_N->Write("p_eff1_vs_xi_N");
123 
124  p_eff2_vs_x_N->Write("p_eff2_vs_x_N");
125  p_eff2_vs_xi_N->Write("p_eff2_vs_xi_N");
126 
127  p_fr_match_unique->Write("p_fr_match_unique");
128  p_fr_match_non_unique->Write("p_fr_match_non_unique");
129 
130  p_fr_signature_0->Write("p_fr_signature_0");
131  p_fr_signature_1->Write("p_fr_signature_1");
132  p_fr_signature_2->Write("p_fr_signature_2");
133  p_fr_signature_12->Write("p_fr_signature_12");
134  }
135  };
136 
137  // (n exp protons, index in n_sigmas) --> plots
138  // n exp protons = 0 --> no condition (summary case)
139  std::map<unsigned int, std::map<unsigned int, EffPlots>> effPlots;
140 
143 
144  h_de_x(new TH1D("", ";x_{F} - x_{N} (mm)", 200, -1., +1.)),
145  h_de_y(new TH1D("", ";y_{F} - y_{N} (mm)", 200, -1., +1.)),
146  h2_de_y_vs_de_x(new TH2D("", ";x_{F} - x_{N} (mm);y_{F} - y_{N} (mm)", 100, -1., +1., 100, -1., +1.)),
147 
148  de_x_mean(0.),
149  de_x_sigma(0.),
150  de_y_mean(0.),
151  de_y_sigma(0.) {
152  for (unsigned int nep = 0; nep <= n_exp_prot_max; ++nep) {
153  for (unsigned int nsi = 0; nsi < n_sigmas.size(); ++nsi) {
154  effPlots[nep][nsi] = EffPlots();
155  }
156  }
157  }
158 
159  void write() const {
160  h_de_x->Write("h_de_x");
161  h_de_y->Write("h_de_y");
162  h2_de_y_vs_de_x->Write("h2_de_y_vs_de_x");
163 
164  char buf[100];
165 
166  for (const auto &n_si : n_sigmas) {
167  sprintf(buf, "g_de_y_vs_de_x_n_si=%.1f", n_si);
168  TGraph *g = new TGraph();
169  g->SetName(buf);
170 
171  g->SetPoint(0, de_x_mean - n_si * de_x_sigma, de_y_mean - n_si * de_y_sigma);
172  g->SetPoint(1, de_x_mean + n_si * de_x_sigma, de_y_mean - n_si * de_y_sigma);
173  g->SetPoint(2, de_x_mean + n_si * de_x_sigma, de_y_mean + n_si * de_y_sigma);
174  g->SetPoint(3, de_x_mean - n_si * de_x_sigma, de_y_mean + n_si * de_y_sigma);
175  g->SetPoint(4, de_x_mean - n_si * de_x_sigma, de_y_mean - n_si * de_y_sigma);
176 
177  g->Write();
178  }
179 
180  TDirectory *d_top = gDirectory;
181 
182  for (const auto &nep_p : effPlots) {
183  if (nep_p.first == 0)
184  sprintf(buf, "exp prot all");
185  else
186  sprintf(buf, "exp prot %u", nep_p.first);
187 
188  TDirectory *d_nep = d_top->mkdir(buf);
189 
190  for (const auto &nsi_p : nep_p.second) {
191  sprintf(buf, "nsi = %.1f", n_sigmas[nsi_p.first]);
192 
193  TDirectory *d_nsi = d_nep->mkdir(buf);
194 
195  gDirectory = d_nsi;
196 
197  nsi_p.second.write();
198  }
199  }
200 
201  gDirectory = d_top;
202  }
203 
205  const LHCInterpolatedOpticalFunctionsSet *of = nullptr;
206 
207  for (const auto &p : ofc) {
208  CTPPSDetId rpId(p.first);
209  unsigned int decRPId = rpId.arm() * 100 + rpId.station() * 10 + rpId.rp();
210 
211  if (decRPId == rpId_N) {
212  of = &p.second;
213  break;
214  }
215  }
216 
217  if (!of) {
218  edm::LogError("ArmData::UpdateOptics") << "Cannot find optical functions for RP " << rpId_N;
219  return;
220  }
221 
222  std::vector<double> xiValues =
223  of->getXiValues(); // local copy made since the TSpline constructor needs non-const parameters
224  std::vector<double> xDValues = of->getFcnValues()[LHCOpticalFunctionsSet::exd];
225  s_x_to_xi_N = std::make_shared<TSpline3>("", xDValues.data(), xiValues.data(), xiValues.size());
226  }
227  };
228 
229  std::map<unsigned int, ArmData> data_;
230 
231  std::unique_ptr<TF1> ff_;
232 };
233 
234 //----------------------------------------------------------------------------------------------------
235 
236 using namespace std;
237 using namespace edm;
238 
239 //----------------------------------------------------------------------------------------------------
240 
242  const edm::ParameterSet &iConfig)
243  : tokenTracks_(consumes<CTPPSLocalTrackLiteCollection>(iConfig.getParameter<edm::InputTag>("tagTracks"))),
244 
245  tokenRecoProtonsMultiRP_(
246  consumes<reco::ForwardProtonCollection>(iConfig.getParameter<InputTag>("tagRecoProtonsMultiRP"))),
247 
248  lhcInfoToken_(esConsumes(ESInputTag("", iConfig.getParameter<std::string>("lhcInfoLabel")))),
249  lhcInfoPerLSToken_(esConsumes(ESInputTag("", iConfig.getParameter<std::string>("lhcInfoPerLSLabel")))),
250  lhcInfoPerFillToken_(esConsumes(ESInputTag("", iConfig.getParameter<std::string>("lhcInfoPerFillLabel")))),
251  useNewLHCInfo_(iConfig.getParameter<bool>("useNewLHCInfo")),
252 
253  opticsESToken_(esConsumes(ESInputTag("", iConfig.getParameter<std::string>("opticsLabel")))),
254  ppsAssociationCutsToken_(
255  esConsumes(ESInputTag("", iConfig.getParameter<std::string>("ppsAssociationCutsLabel")))),
256 
257  pixelDiscardBXShiftedTracks_(iConfig.getParameter<bool>("pixelDiscardBXShiftedTracks")),
258 
259  localAngleXMin_(iConfig.getParameter<double>("localAngleXMin")),
260  localAngleXMax_(iConfig.getParameter<double>("localAngleXMax")),
261  localAngleYMin_(iConfig.getParameter<double>("localAngleYMin")),
262  localAngleYMax_(iConfig.getParameter<double>("localAngleYMax")),
263 
264  n_prep_events_(iConfig.getParameter<unsigned int>("n_prep_events")),
265  n_exp_prot_max_(iConfig.getParameter<unsigned int>("n_exp_prot_max")),
266  n_sigmas_(iConfig.getParameter<std::vector<double>>("n_sigmas")),
267 
268  outputFile_(iConfig.getParameter<string>("outputFile")),
269 
270  verbosity_(iConfig.getUntrackedParameter<unsigned int>("verbosity")),
271 
272  ff_(new TF1("ff", "[0] * exp(- (x-[1])*(x-[1]) / 2 / [2]/[2]) + [4]")) {
273  data_[0].n_exp_prot_max = n_exp_prot_max_;
274  data_[0].n_sigmas = n_sigmas_;
275  data_[0].rpId_N = iConfig.getParameter<unsigned int>("rpId_45_N");
276  data_[0].rpId_F = iConfig.getParameter<unsigned int>("rpId_45_F");
277 
278  data_[1].n_exp_prot_max = n_exp_prot_max_;
279  data_[1].n_sigmas = n_sigmas_;
280  data_[1].rpId_N = iConfig.getParameter<unsigned int>("rpId_56_N");
281  data_[1].rpId_F = iConfig.getParameter<unsigned int>("rpId_56_F");
282 }
283 
284 //----------------------------------------------------------------------------------------------------
285 
288 
289  desc.add<edm::InputTag>("tagTracks", edm::InputTag())->setComment("input tag for local lite tracks");
290  desc.add<edm::InputTag>("tagRecoProtonsMultiRP", edm::InputTag())->setComment("input tag for multi-RP reco protons");
291 
292  desc.add<std::string>("lhcInfoLabel", "")->setComment("label of the LHCInfo record");
293  desc.add<std::string>("lhcInfoPerLSLabel", "")->setComment("label of the LHCInfoPerLS record");
294  desc.add<std::string>("lhcInfoPerFillLabel", "")->setComment("label of the LHCInfoPerFill record");
295  desc.add<bool>("useNewLHCInfo", false)->setComment("flag whether to use new LHCInfoPer* records or old LHCInfo");
296  desc.add<string>("opticsLabel", "")->setComment("label of optics data");
297  desc.add<string>("ppsAssociationCutsLabel", "")->setComment("label of PPSAssociationCuts data");
298 
299  desc.add<bool>("pixelDiscardBXShiftedTracks", false)
300  ->setComment("whether to discard pixel tracks built from BX-shifted planes");
301 
302  desc.add<double>("localAngleXMin", -0.03)->setComment("minimal accepted value of local horizontal angle (rad)");
303  desc.add<double>("localAngleXMax", +0.03)->setComment("maximal accepted value of local horizontal angle (rad)");
304  desc.add<double>("localAngleYMin", -0.04)->setComment("minimal accepted value of local vertical angle (rad)");
305  desc.add<double>("localAngleYMax", +0.04)->setComment("maximal accepted value of local vertical angle (rad)");
306 
307  desc.add<unsigned int>("n_prep_events", 1000)
308  ->setComment("number of preparatory events (to determine de x and de y window)");
309 
310  desc.add<unsigned int>("n_exp_prot_max", 5)->setComment("maximum number of expected protons per event and per arm");
311 
312  desc.add<std::vector<double>>("n_sigmas", {3., 5., 7.})->setComment("list of n_sigma values");
313 
314  desc.add<unsigned int>("rpId_45_N", 0)->setComment("decimal RP id for 45 near");
315  desc.add<unsigned int>("rpId_45_F", 0)->setComment("decimal RP id for 45 far");
316  desc.add<unsigned int>("rpId_56_N", 0)->setComment("decimal RP id for 56 near");
317  desc.add<unsigned int>("rpId_56_F", 0)->setComment("decimal RP id for 56 far");
318 
319  desc.add<std::string>("outputFile", "output.root")->setComment("output file name");
320 
321  desc.addUntracked<unsigned int>("verbosity", 0)->setComment("verbosity level");
322 
323  descriptions.add("ctppsProtonReconstructionEfficiencyEstimatorDataDefault", desc);
324 }
325 
326 //----------------------------------------------------------------------------------------------------
327 
329  const edm::EventSetup &iSetup) {
330  std::ostringstream os;
331 
332  // get conditions
333  const LHCInfoCombined lhcInfoCombined(
335  const auto &opticalFunctions = iSetup.getData(opticsESToken_);
336  const auto &ppsAssociationCuts = iSetup.getData(ppsAssociationCutsToken_);
337 
338  // check optics change
339  if (opticsWatcher_.check(iSetup)) {
340  data_[0].UpdateOptics(opticalFunctions);
341  data_[1].UpdateOptics(opticalFunctions);
342  }
343 
344  // get input
346  iEvent.getByToken(tokenTracks_, hTracks);
347 
348  Handle<reco::ForwardProtonCollection> hRecoProtonsMultiRP;
349  iEvent.getByToken(tokenRecoProtonsMultiRP_, hRecoProtonsMultiRP);
350 
351  // pre-selection of tracks
352  std::vector<unsigned int> sel_track_idc;
353 
354  std::map<unsigned int, std::vector<unsigned int>> trackingSelection;
355 
356  for (unsigned int idx = 0; idx < hTracks->size(); ++idx) {
357  const auto &tr = hTracks->at(idx);
358 
359  if (tr.tx() < localAngleXMin_ || tr.tx() > localAngleXMax_ || tr.ty() < localAngleYMin_ ||
360  tr.ty() > localAngleYMax_)
361  continue;
362 
364  if (tr.pixelTrackRecoInfo() == CTPPSpixelLocalTrackReconstructionInfo::allShiftedPlanes ||
365  tr.pixelTrackRecoInfo() == CTPPSpixelLocalTrackReconstructionInfo::mixedPlanes)
366  continue;
367  }
368 
369  sel_track_idc.push_back(idx);
370 
371  const CTPPSDetId rpId(tr.rpId());
372 
373  const bool trackerRP =
374  (rpId.subdetId() == CTPPSDetId::sdTrackingStrip || rpId.subdetId() == CTPPSDetId::sdTrackingPixel);
375 
376  if (trackerRP)
377  trackingSelection[rpId.arm()].push_back(idx);
378  }
379 
380  // debug print
381  if (verbosity_ > 1) {
382  os << "* tracks (pre-selected):" << std::endl;
383 
384  for (const auto idx : sel_track_idc) {
385  const auto &tr = hTracks->at(idx);
386  CTPPSDetId rpId(tr.rpId());
387  unsigned int decRPId = rpId.arm() * 100 + rpId.station() * 10 + rpId.rp();
388 
389  os << " [" << idx << "] RP=" << decRPId << ", x=" << tr.x() << ", y=" << tr.y() << std::endl;
390  }
391 
392  os << "* protons:" << std::endl;
393  for (unsigned int i = 0; i < hRecoProtonsMultiRP->size(); ++i) {
394  const auto &pr = (*hRecoProtonsMultiRP)[i];
395  os << " [" << i << "] track indices: ";
396  for (const auto &trr : pr.contributingLocalTracks())
397  os << trr.key() << ", ";
398  os << std::endl;
399  }
400  }
401 
402  // make de_x and de_y plots
403  map<unsigned int, bool> hasTracksInArm;
404 
405  for (const auto idx_i : sel_track_idc) {
406  const auto &tr_i = hTracks->at(idx_i);
407  CTPPSDetId rpId_i(tr_i.rpId());
408  unsigned int decRPId_i = rpId_i.arm() * 100 + rpId_i.station() * 10 + rpId_i.rp();
409 
410  for (const auto idx_j : sel_track_idc) {
411  const auto &tr_j = hTracks->at(idx_j);
412  CTPPSDetId rpId_j(tr_j.rpId());
413  unsigned int decRPId_j = rpId_j.arm() * 100 + rpId_j.station() * 10 + rpId_j.rp();
414 
415  // check whether desired RP combination
416  unsigned int arm = 123;
417  for (const auto &ap : data_) {
418  if (ap.second.rpId_N == decRPId_i && ap.second.rpId_F == decRPId_j)
419  arm = ap.first;
420  }
421 
422  if (arm > 1)
423  continue;
424 
425  // update flag
426  hasTracksInArm[arm] = true;
427 
428  // update plots
429  auto &ad = data_[arm];
430  const double de_x = tr_j.x() - tr_i.x();
431  const double de_y = tr_j.y() - tr_i.y();
432 
433  if (ad.n_events_with_tracks < n_prep_events_) {
434  ad.h_de_x->Fill(de_x);
435  ad.h_de_y->Fill(de_y);
436  }
437 
438  ad.h2_de_y_vs_de_x->Fill(de_x, de_y);
439  }
440  }
441 
442  // update event counter
443  for (auto &ap : data_) {
444  if (hasTracksInArm[ap.first])
445  ap.second.n_events_with_tracks++;
446  }
447 
448  // if threshold reached do fits
449  for (auto &ap : data_) {
450  auto &ad = ap.second;
451 
452  if (ad.n_events_with_tracks == n_prep_events_) {
453  if (ad.de_x_sigma > 0. && ad.de_y_sigma > 0.)
454  continue;
455 
456  std::vector<std::pair<unsigned int, TH1D *>> m;
457  m.emplace_back(0, ad.h_de_x.get());
458  m.emplace_back(1, ad.h_de_y.get());
459 
460  for (const auto &p : m) {
461  double max_pos = -1E100, max_val = -1.;
462  for (int bi = 1; bi < p.second->GetNbinsX(); ++bi) {
463  const double pos = p.second->GetBinCenter(bi);
464  const double val = p.second->GetBinContent(bi);
465 
466  if (val > max_val) {
467  max_val = val;
468  max_pos = pos;
469  }
470  }
471 
472  const double sig = 0.2;
473 
474  ff_->SetParameters(max_val, max_pos, sig, 0.);
475  p.second->Fit(ff_.get(), "Q", "", max_pos - 3. * sig, max_pos + 3. * sig);
476  p.second->Fit(ff_.get(), "Q", "", max_pos - 3. * sig, max_pos + 3. * sig);
477 
478  if (p.first == 0) {
479  ad.de_x_mean = ff_->GetParameter(1);
480  ad.de_x_sigma = fabs(ff_->GetParameter(2));
481  }
482  if (p.first == 1) {
483  ad.de_y_mean = ff_->GetParameter(1);
484  ad.de_y_sigma = fabs(ff_->GetParameter(2));
485  }
486  }
487 
488  if (verbosity_) {
489  os << "* fitting arm " << ap.first << std::endl
490  << " de_x: mean = " << ad.de_x_mean << ", sigma = " << ad.de_x_sigma << std::endl
491  << " de_y: mean = " << ad.de_y_mean << ", sigma = " << ad.de_y_sigma;
492  }
493  }
494  }
495 
496  // logic below:
497  // 1) evaluate "proton candiates" or "expected protons" = local tracks in the near RP which have a compatible
498  // partner in the far RP; the compatibility is evaluated at multiple n_sigma choices
499  // 2) check how often each "proton candidate" can be matched to a reconstructed proton
500  // 3) re-evaluate association cuts --> check details for each "proton candidate"
501 
502  // data structures for efficiency analysis
503 
504  struct ArmEventData {
505  // n_sigma --> list of "proton candidates" (local track indices in the near RP)
506  std::map<unsigned int, std::set<unsigned int>> matched_track_idc;
507 
508  // list of valid reco-proton indices (in the chosen arm)
509  std::set<unsigned int> reco_proton_idc;
510 
511  // n_sigma --> list of "proton candicates" which have/don't have matching reco proton
512  std::map<unsigned int, std::set<unsigned int>> matched_track_with_prot_idc, matched_track_without_prot_idc;
513 
514  // for re-evaluation of association cuts
515  struct EvaluatedPair {
516  unsigned idx_N, idx_F;
517  bool x_cut, y_cut;
518  bool match = false;
519  bool unique = false;
520  };
521 
522  vector<EvaluatedPair> evaluatedPairs;
523  };
524 
525  std::map<unsigned int, ArmEventData> armEventData;
526 
527  // determine the number of proton candiates or expected protons
528  for (const auto idx_i : sel_track_idc) {
529  const auto &tr_i = hTracks->at(idx_i);
530  CTPPSDetId rpId_i(tr_i.rpId());
531  unsigned int decRPId_i = rpId_i.arm() * 100 + rpId_i.station() * 10 + rpId_i.rp();
532 
533  for (const auto idx_j : sel_track_idc) {
534  const auto &tr_j = hTracks->at(idx_j);
535  CTPPSDetId rpId_j(tr_j.rpId());
536  unsigned int decRPId_j = rpId_j.arm() * 100 + rpId_j.station() * 10 + rpId_j.rp();
537 
538  // check whether desired RP combination
539  unsigned int arm = 123;
540  for (const auto &ap : data_) {
541  if (ap.second.rpId_N == decRPId_i && ap.second.rpId_F == decRPId_j)
542  arm = ap.first;
543  }
544 
545  if (arm > 1)
546  continue;
547 
548  // check near-far matching
549  auto &ad = data_[arm];
550  const double de_x = tr_j.x() - tr_i.x();
551  const double de_y = tr_j.y() - tr_i.y();
552 
553  for (unsigned int nsi = 0; nsi < ad.n_sigmas.size(); ++nsi) {
554  const double n_si = ad.n_sigmas[nsi];
555  const bool match_x = fabs(de_x - ad.de_x_mean) < n_si * ad.de_x_sigma;
556  const bool match_y = fabs(de_y - ad.de_y_mean) < n_si * ad.de_y_sigma;
557  if (match_x && match_y)
558  armEventData[arm].matched_track_idc[nsi].insert(idx_i);
559  }
560  }
561  }
562 
563  // determine the number of reconstructed protons
564  for (unsigned int i = 0; i < hRecoProtonsMultiRP->size(); ++i) {
565  const auto &proton = (*hRecoProtonsMultiRP)[i];
566 
567  CTPPSDetId rpId((*proton.contributingLocalTracks().begin())->rpId());
568  unsigned int arm = rpId.arm();
569 
570  if (proton.validFit())
571  armEventData[arm].reco_proton_idc.insert(i);
572  }
573 
574  // compare matched tracks with reco protons
575  if (verbosity_ > 1)
576  os << "* cmp matched tracks vs. reco protons" << std::endl;
577 
578  for (auto &ap : armEventData) {
579  auto &ad = data_[ap.first];
580 
581  if (verbosity_ > 1)
582  os << " arm " << ap.first << std::endl;
583 
584  for (unsigned int nsi = 0; nsi < ad.n_sigmas.size(); ++nsi) {
585  if (verbosity_ > 1)
586  os << " nsi = " << nsi << std::endl;
587 
588  for (const auto &tri : ap.second.matched_track_idc[nsi]) {
589  const auto &track = hTracks->at(tri);
590 
591  bool some_proton_matching = false;
592 
593  if (verbosity_ > 1)
594  os << " tri = " << tri << std::endl;
595 
596  for (const auto &pri : ap.second.reco_proton_idc) {
597  const auto &proton = (*hRecoProtonsMultiRP)[pri];
598 
599  bool proton_matching = false;
600 
601  for (const auto &pr_tr : proton.contributingLocalTracks()) {
602  CTPPSDetId rpId(pr_tr->rpId());
603  unsigned int decRPId = rpId.arm() * 100 + rpId.station() * 10 + rpId.rp();
604 
605  if (decRPId != ad.rpId_N)
606  continue;
607 
608  const double x = pr_tr->x();
609  const double y = pr_tr->y();
610  const double th = 1E-3; // 1 um
611 
612  const bool match = (fabs(x - track.x()) < th) && (fabs(y - track.y()) < th);
613 
614  if (verbosity_ > 1)
615  os << " pri = " << pri << ": x_tr = " << track.x() << ", x_pr = " << x
616  << ", match = " << match << std::endl;
617 
618  if (match) {
619  proton_matching = true;
620  break;
621  }
622  }
623 
624  if (proton_matching) {
625  some_proton_matching = true;
626  break;
627  }
628  }
629 
630  if (verbosity_ > 1)
631  os << " --> some_proton_matching " << some_proton_matching << std::endl;
632 
633  if (some_proton_matching)
634  ap.second.matched_track_with_prot_idc[nsi].insert(tri);
635  else
636  ap.second.matched_track_without_prot_idc[nsi].insert(tri);
637  }
638  }
639  }
640 
641  // redo association cuts
642  for (auto &ap : armEventData) {
643  const auto &arm = ap.first;
644 
645  auto &ad = data_[arm];
646 
647  auto &aed = ap.second;
648 
649  auto &ass_cut = ppsAssociationCuts.getAssociationCuts(arm);
650 
651  const auto &indices = trackingSelection[arm];
652 
653  map<unsigned int, unsigned> matching_multiplicity;
654 
655  for (const auto &i : indices) {
656  for (const auto &j : indices) {
657  const auto &tr_i = hTracks->at(i);
658  const auto &tr_j = hTracks->at(j);
659 
660  const CTPPSDetId id_i(tr_i.rpId());
661  const CTPPSDetId id_j(tr_j.rpId());
662 
663  const unsigned rpDecId_i = id_i.arm() * 100 + id_i.station() * 10 + id_i.rp();
664  const unsigned rpDecId_j = id_j.arm() * 100 + id_j.station() * 10 + id_j.rp();
665 
666  if (rpDecId_i != ad.rpId_N || rpDecId_j != ad.rpId_F)
667  continue;
668 
669  ArmEventData::EvaluatedPair evp;
670  evp.idx_N = i;
671  evp.idx_F = j;
672 
673  evp.x_cut =
674  ass_cut.isSatisfied(ass_cut.qX, tr_i.x(), tr_i.y(), lhcInfoCombined.crossingAngle(), tr_i.x() - tr_j.x());
675  evp.y_cut =
676  ass_cut.isSatisfied(ass_cut.qY, tr_i.x(), tr_i.y(), lhcInfoCombined.crossingAngle(), tr_i.y() - tr_j.y());
677 
678  evp.match = evp.x_cut && evp.y_cut;
679 
680  aed.evaluatedPairs.push_back(evp);
681 
682  if (evp.match) {
683  matching_multiplicity[i]++;
684  matching_multiplicity[j]++;
685  }
686  }
687  }
688 
689  for (auto &evp : aed.evaluatedPairs)
690  evp.unique = (matching_multiplicity[evp.idx_N] == 1) && (matching_multiplicity[evp.idx_F] == 1);
691  }
692 
693  // debug print
694  if (verbosity_ > 1) {
695  for (auto &ap : armEventData) {
696  auto &ad = data_[ap.first];
697 
698  if (ad.de_x_sigma <= 0. && ad.de_y_sigma <= 0.)
699  continue;
700 
701  os << "* results for arm " << ap.first << std::endl;
702 
703  os << " reco_proton_idc: ";
704  for (const auto &idx : ap.second.reco_proton_idc)
705  os << idx << ", ";
706  os << std::endl;
707 
708  for (unsigned int nsi = 0; nsi < ad.n_sigmas.size(); ++nsi) {
709  os << " n_si = " << ad.n_sigmas[nsi] << std::endl;
710 
711  os << " matched_track_idc: ";
712  for (const auto &idx : ap.second.matched_track_idc[nsi])
713  os << idx << ", ";
714  os << std::endl;
715 
716  os << " matched_track_with_prot_idc: ";
717  for (const auto &idx : ap.second.matched_track_with_prot_idc[nsi])
718  os << idx << ", ";
719  os << std::endl;
720 
721  os << " matched_track_without_prot_idc: ";
722  for (const auto &idx : ap.second.matched_track_without_prot_idc[nsi])
723  os << idx << ", ";
724  os << std::endl;
725  }
726 
727  os << " evaluated pairs: ";
728  for (const auto &p : ap.second.evaluatedPairs)
729  os << "(" << p.idx_N << "-" << p.idx_F << ",M" << p.match << ",U" << p.unique << ")"
730  << ", ";
731  os << std::endl;
732  }
733  }
734 
735  // update efficiency plots
736  for (auto &ap : armEventData) {
737  const auto &arm = ap.first;
738  auto &ad = data_[arm];
739 
740  // stop if sigmas not yet determined
741  if (ad.de_x_sigma <= 0. && ad.de_y_sigma <= 0.)
742  continue;
743 
744  // loop over n_sigma choices
745  for (unsigned int nsi = 0; nsi < ad.n_sigmas.size(); ++nsi) {
746  const unsigned int n_exp_prot = ap.second.matched_track_idc[nsi].size();
747  const unsigned int n_rec_prot = ap.second.reco_proton_idc.size();
748 
749  // stop if N(expected protons) out of range
750  if (n_exp_prot < 1 || n_exp_prot > ad.n_exp_prot_max)
751  continue;
752 
753  // update method 1 plots
754  const double eff = double(n_rec_prot) / n_exp_prot;
755 
756  for (unsigned int tri : ap.second.matched_track_idc[nsi]) {
757  const double x_N = hTracks->at(tri).x();
758  const double xi_N = ad.s_x_to_xi_N->Eval(x_N * 1E-1); // conversion mm to cm
759 
760  ad.effPlots[0][nsi].p_eff1_vs_x_N->Fill(x_N, eff);
761  ad.effPlots[0][nsi].p_eff1_vs_xi_N->Fill(xi_N, eff);
762 
763  ad.effPlots[n_exp_prot][nsi].p_eff1_vs_x_N->Fill(x_N, eff);
764  ad.effPlots[n_exp_prot][nsi].p_eff1_vs_xi_N->Fill(xi_N, eff);
765  }
766 
767  // update method 2 plots
768  for (const auto &tri : ap.second.matched_track_with_prot_idc[nsi]) {
769  const double x_N = hTracks->at(tri).x();
770  const double xi_N = ad.s_x_to_xi_N->Eval(x_N * 1E-1); // conversion mm to cm
771 
772  ad.effPlots[0][nsi].p_eff2_vs_x_N->Fill(x_N, 1.);
773  ad.effPlots[0][nsi].p_eff2_vs_xi_N->Fill(xi_N, 1.);
774 
775  ad.effPlots[n_exp_prot][nsi].p_eff2_vs_x_N->Fill(x_N, 1.);
776  ad.effPlots[n_exp_prot][nsi].p_eff2_vs_xi_N->Fill(xi_N, 1.);
777  }
778 
779  for (const auto &tri : ap.second.matched_track_without_prot_idc[nsi]) {
780  const double x_N = hTracks->at(tri).x();
781  const double xi_N = ad.s_x_to_xi_N->Eval(x_N * 1E-1); // conversion mm to cm
782 
783  ad.effPlots[0][nsi].p_eff2_vs_x_N->Fill(x_N, 0.);
784  ad.effPlots[0][nsi].p_eff2_vs_xi_N->Fill(xi_N, 0.);
785 
786  ad.effPlots[n_exp_prot][nsi].p_eff2_vs_x_N->Fill(x_N, 0.);
787  ad.effPlots[n_exp_prot][nsi].p_eff2_vs_xi_N->Fill(xi_N, 0.);
788  }
789 
790  // update association cut plots
791  for (const auto &cand : ap.second.matched_track_idc[nsi]) // loop over candidates
792  {
793  const double x_N = hTracks->at(cand).x();
794 
795  auto &plots = ad.effPlots[n_exp_prot][nsi];
796 
797  bool hasMatchingAndUniquePair = false;
798  bool hasMatchingAndNonUniquePair = false;
799  for (const auto &pair : ap.second.evaluatedPairs) // loop over pairs
800  {
801  // stop if cand not compatible with pair
802  if (cand != pair.idx_N)
803  continue;
804 
805  if (pair.match && pair.unique)
806  hasMatchingAndUniquePair = true;
807 
808  if (pair.match && !pair.unique)
809  hasMatchingAndNonUniquePair = true;
810 
811  unsigned int signature = 999999;
812  if (!pair.x_cut && !pair.y_cut)
813  signature = 0;
814  if (pair.x_cut && !pair.y_cut)
815  signature = 1;
816  if (!pair.x_cut && pair.y_cut)
817  signature = 2;
818  if (pair.x_cut && pair.y_cut)
819  signature = 12;
820 
821  plots.p_fr_signature_0->Fill(x_N, (signature == 0) ? 1 : 0);
822  plots.p_fr_signature_1->Fill(x_N, (signature == 1) ? 1 : 0);
823  plots.p_fr_signature_2->Fill(x_N, (signature == 2) ? 1 : 0);
824  plots.p_fr_signature_12->Fill(x_N, (signature == 12) ? 1 : 0);
825  }
826 
827  plots.p_fr_match_unique->Fill(x_N, (hasMatchingAndUniquePair) ? 1 : 0);
828  plots.p_fr_match_non_unique->Fill(x_N, (hasMatchingAndNonUniquePair) ? 1 : 0);
829  }
830  }
831  }
832 
833  if (verbosity_)
834  edm::LogInfo("CTPPSProtonReconstructionEfficiencyEstimatorData") << os.str();
835 }
836 
837 //----------------------------------------------------------------------------------------------------
838 
840  auto f_out = std::make_unique<TFile>(outputFile_.c_str(), "recreate");
841 
842  for (const auto &ait : data_) {
843  char buf[100];
844  sprintf(buf, "arm %u", ait.first);
845  TDirectory *d_arm = f_out->mkdir(buf);
846  gDirectory = d_arm;
847 
848  ait.second.write();
849  }
850 }
851 
852 //----------------------------------------------------------------------------------------------------
853 
ESGetTokenH3DDVariant esConsumes(std::string const &Record, edm::ConsumesCollector &)
Definition: DeDxTools.cc:283
T getParameter(std::string const &) const
Definition: ParameterSet.h:307
T const & getData(const ESGetToken< T, R > &iToken) const noexcept(false)
Definition: EventSetup.h:119
uint32_t arm() const
Definition: CTPPSDetId.h:57
float crossingAngle() const
const edm::ESGetToken< LHCInfoPerFill, LHCInfoPerFillRcd > lhcInfoPerFillToken_
Log< level::Error, false > LogError
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e g
Definition: Activities.doc:4
void UpdateOptics(const LHCInterpolatedOpticalFunctionsSetCollection &ofc)
int iEvent
Definition: GenABIO.cc:224
def unique(seq, keepstr=True)
Definition: tier0.py:24
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
edm::EDGetTokenT< reco::ForwardProtonCollection > tokenRecoProtonsMultiRP_
const edm::ESGetToken< LHCInfoPerLS, LHCInfoPerLSRcd > lhcInfoPerLSToken_
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
Log< level::Info, false > LogInfo
uint32_t rp() const
Definition: CTPPSDetId.h:71
std::vector< CTPPSLocalTrackLite > CTPPSLocalTrackLiteCollection
Collection of CTPPSLocalTrackLite objects.
edm::ESGetToken< LHCInterpolatedOpticalFunctionsSetCollection, CTPPSInterpolatedOpticsRcd > opticsESToken_
uint32_t station() const
Definition: CTPPSDetId.h:64
Set of optical functions corresponding to one scoring plane along LHC, including splines for interpol...
void add(std::string const &label, ParameterSetDescription const &psetDescription)
bool check(const edm::EventSetup &iSetup)
Definition: ESWatcher.h:57
Base class for CTPPS detector IDs.
Definition: CTPPSDetId.h:32
fixed size matrix
HLT enums.
std::pair< typename Association::data_type::first_type, double > match(Reference key, Association association, bool bestMatchByMaxValue)
Generic matching function.
Definition: Utils.h:10
std::vector< ForwardProton > ForwardProtonCollection
Collection of ForwardProton objects.
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined signature
Definition: Activities.doc:4
edm::ESGetToken< PPSAssociationCuts, PPSAssociationCutsRcd > ppsAssociationCutsToken_
void analyze(const edm::Event &, const edm::EventSetup &) override