CMS 3D CMS Logo

DeDxHitCalibrator.cc
Go to the documentation of this file.
7 
17 
24 
25 #include <fstream>
26 
28 public:
29  static constexpr int kIsNormal = 0, kIsBelow = 1, kIsOver = 2;
30  static constexpr int PXB = 0, PXF = 1, TIB = 2, TID = 3, TOB = 4, TECThin = 5, TECThick = 6;
31  typedef std::pair<uint32_t, unsigned char> ChipId;
32 
33  explicit DeDxHitCalibrator(const edm::ParameterSet&);
34  ~DeDxHitCalibrator() override = default;
36 
37 private:
38  void beginRun(edm::Run const&, const edm::EventSetup&) override;
39  void produce(edm::Event&, const edm::EventSetup&) override;
40 
41  int getDetId(const DetId&, const float&);
42  float correctEnergy(const float&, const ChipId&);
44  const float& trackMomentum,
47 
48  double getChi2(const std::vector<double>&, const std::vector<std::pair<double, int> >&, const double&, const double&);
49  void getAlphaBeta(const std::vector<double>&,
50  const std::vector<std::pair<double, int> >&,
51  CLHEP::HepMatrix&,
52  CLHEP::HepVector&,
53  const std::vector<bool>&,
54  const double&,
55  const double&);
56  std::pair<double, double> fitStripCluster(const std::vector<std::pair<double, int> >&, const double&, const double&);
57 
58  const bool applyGain_;
59  const double MeVPerElectron_;
67 
72 };
73 
75  : applyGain_(iConfig.getParameter<bool>("applyGain")),
76  MeVPerElectron_(iConfig.getParameter<double>("MeVPerElectron")),
77  VCaltoElectronGain_(iConfig.getParameter<int>("VCaltoElectronGain")),
78  VCaltoElectronGain_L1_(iConfig.getParameter<int>("VCaltoElectronGain_L1")),
79  VCaltoElectronOffset_(iConfig.getParameter<int>("VCaltoElectronOffset")),
80  VCaltoElectronOffset_L1_(iConfig.getParameter<int>("VCaltoElectronOffset_L1")),
81  pixelSaturationThr_(iConfig.getParameter<int>("pixelSaturationThr")),
82  tracksToken_(consumes<reco::TrackCollection>(iConfig.getParameter<edm::InputTag>("trackProducer"))),
83  dedxHitInfoToken_(consumes<reco::DeDxHitInfoAss>(iConfig.getParameter<edm::InputTag>("dedxHitInfo"))),
84  dedxCalibToken_(esConsumes<DeDxCalibration, DeDxCalibrationRcd, edm::Transition::BeginRun>()),
86  tkTopoToken_(esConsumes<TrackerTopology, TrackerTopologyRcd, edm::Transition::BeginRun>()),
87  pixelCalib_(iConfig, consumesCollector()) {
88  produces<reco::TrackDeDxHitsCollection>("PixelHits");
89  produces<reco::TrackDeDxHitsCollection>("StripHits");
90 }
91 
94  desc.add<bool>("applyGain", true);
95  desc.add<double>("MeVPerElectron", 3.61e-06);
96  desc.add<int>("VCaltoElectronGain", 65);
97  desc.add<int>("VCaltoElectronGain_L1", 65);
98  desc.add<int>("VCaltoElectronOffset", -414);
99  desc.add<int>("VCaltoElectronOffset_L1", -414);
100  desc.add<int>("pixelSaturationThr", 254);
101  desc.add<edm::InputTag>("trackProducer", edm::InputTag("generalTracks"));
102  desc.add<edm::InputTag>("dedxHitInfo", edm::InputTag("dedxHitInfo"));
103  descriptions.add("dedxHitCalibrator", desc);
104 }
105 
108  tkGeom_ = iSetup.getHandle(tkGeomToken_);
109  tkTopo_ = iSetup.getHandle(tkTopoToken_);
110 }
111 
113  const auto& tracks = iEvent.getHandle(tracksToken_);
114  const auto& dedxHitInfo = iEvent.get(dedxHitInfoToken_);
115  pixelCalib_.setESObjects(iSetup);
116 
117  // creates the output collection
118  auto pixelTrackDeDxHitAss = std::make_unique<reco::TrackDeDxHitsCollection>(reco::TrackRefProd(tracks));
119  auto stripTrackDeDxHitAss = std::make_unique<reco::TrackDeDxHitsCollection>(reco::TrackRefProd(tracks));
120 
121  for (size_t i = 0; i < tracks->size(); i++) {
122  const auto& track = reco::TrackRef(tracks, i);
123  const auto& dedxHits = dedxHitInfo[track];
124  if (dedxHits.isNull())
125  continue;
127  processHitInfo(*dedxHits, track->p(), pixelHits, stripHits);
128  pixelTrackDeDxHitAss->setValue(i, pixelHits);
129  stripTrackDeDxHitAss->setValue(i, stripHits);
130  }
131 
132  iEvent.put(std::move(pixelTrackDeDxHitAss), "PixelHits");
133  iEvent.put(std::move(stripTrackDeDxHitAss), "StripHits");
134 }
135 
136 /*****************************************************************************/
138  const float& trackMomentum,
141  // Energy loss parametrization from https://doi.org/10.1016/j.nima.2012.06.064
142  static constexpr double a = 0.07; //energy loss factor in silicon
143  static constexpr double l0 = 450e-4; //reference path length in um
144 
145  for (size_t i = 0; i < info.size(); i++) {
146  // Require hits to be complete and compatible
147  const auto& type = info.type(i);
149  continue;
150 
151  // Effective path length
152  const auto& pl = info.pathlength(i);
153  const auto pathLength = pl * (1. + a * std::log(pl / l0));
154  const DetId& detId = info.detId(i);
155 
156  // Strip
157  if (const auto& stripCluster = info.stripCluster(i)) {
158  const auto& thickness =
159  dynamic_cast<const StripGeomDetUnit*>(tkGeom_->idToDet(detId))->surface().bounds().thickness();
160  const auto& det = getDetId(detId, thickness);
161  const auto& chipId = ChipId(detId, stripCluster->barycenter() / sistrip::STRIPS_PER_APV);
162  // Fill measured strip deposits
163  const auto& thr = dedxCalib_->thr()[det];
164  std::vector<std::pair<double, int> > b;
165  b.reserve(stripCluster->amplitudes().size() + 2);
166  b.emplace_back(thr, kIsBelow);
167  for (const auto& adc : stripCluster->amplitudes()) {
168  if (adc > 253)
169  b.emplace_back(254., kIsOver);
170  else
171  b.emplace_back(adc + 0.5, kIsNormal);
172  }
173  b.emplace_back(thr, kIsBelow);
174  // Fit
175  const auto& result = fitStripCluster(b, dedxCalib_->alpha()[det], 1. / dedxCalib_->sigma()[det]);
176  // ADC -> e- -> MeV
177  const auto& energy = correctEnergy(result.first * sistrip::MeVperADCStrip, chipId);
178  const auto& esigma = correctEnergy(result.second * sistrip::MeVperADCStrip, chipId);
179  // Compute charge
180  const auto& charge = pathLength != 0. ? energy / pathLength : 0.;
181  stripHits.emplace_back(charge, trackMomentum, pathLength, 0, esigma);
182  }
183 
184  // Pixel
185  if (const auto& pixelCluster = info.pixelCluster(i)) {
186  const auto& thickness =
187  dynamic_cast<const PixelGeomDetUnit*>(tkGeom_->idToDet(detId))->surface().bounds().thickness();
188  const auto& det = getDetId(detId, thickness);
189  const auto& chipId =
190  ChipId(detId, (int(pixelCluster->x() / ROCSizeInX) << 3) + int(pixelCluster->y() / ROCSizeInY));
191  // Collect adc
192  double delta(0);
193  bool isSaturated(false);
194  for (size_t j = 0; j < pixelCluster->pixelADC().size(); j++) {
195  const auto& elec = pixelCluster->pixelADC()[j];
196  delta += elec * MeVPerElectron_;
197  if (isSaturated)
198  continue;
199  // ( pos , (x , y) )
200  const auto& row = pixelCluster->minPixelRow() + pixelCluster->pixelOffset()[2 * j];
201  const auto& col = pixelCluster->minPixelCol() + pixelCluster->pixelOffset()[2 * j + 1];
202  // Go back to adc
203  const auto& DBgain = pixelCalib_.getGain(detId, col, row);
204  const auto& DBpedestal = pixelCalib_.getPedestal(detId, col, row);
206  isSaturated = true;
207  else if (DBgain > 0.) {
208  double vcal;
209  const auto& theLayer = (detId.subdetId() == 1) ? tkTopo_->pxbLayer(detId) : 0;
210  if (theLayer == 1)
212  else
213  vcal = (elec - VCaltoElectronOffset_) / VCaltoElectronGain_;
214  const auto adc = std::round(DBpedestal + vcal / DBgain);
215  if (adc > pixelSaturationThr_)
216  isSaturated = true;
217  }
218  }
219  // Compute energy
220  const auto& energy = correctEnergy(delta, chipId);
221  if (det != PXF && energy <= 50e-3)
222  continue;
223  // Estimate sigma for cluster
224  const unsigned char& nChannels = pixelCluster->pixelADC().size();
225  const auto esigma = 10e-3 * std::sqrt(nChannels);
226  // Compute charge
227  const auto& charge = pathLength != 0. ? energy / pathLength : 0.;
228  pixelHits.emplace_back(charge, trackMomentum, pathLength, isSaturated, esigma);
229  }
230  }
231 }
232 
233 /*****************************************************************************/
234 int DeDxHitCalibrator::getDetId(const DetId& id, const float& thickness) {
235  const auto& subdet = id.subdetId() - 1;
236  if (subdet == TECThin && thickness > 400e-4)
237  return TECThick;
238  return subdet;
239 }
240 
241 /*****************************************************************************/
243  const auto& g = dedxCalib_->gain().find(detId);
244  if (applyGain_ && g != dedxCalib_->gain().end())
245  return energy * g->second;
246  return energy;
247 }
248 
249 /*****************************************************************************/
250 double DeDxHitCalibrator::getChi2(const std::vector<double>& x,
251  const std::vector<std::pair<double, int> >& b,
252  const double& coupling,
253  const double& iSigma) {
254  const auto& npar = b.size();
255  std::vector<double> y(npar, 0.);
256  for (size_t i = 0; i < npar; i++) {
257  const auto dx = coupling * x[i];
258  if (i >= 1)
259  y[i - 1] += dx;
260  y[i] += x[i] - 2 * dx;
261  if (i + 1 < npar)
262  y[i + 1] += dx;
263  }
264  double chi2(0.);
265  for (size_t i = 0; i < npar; i++) {
266  auto q = (b[i].first - y[i]) * iSigma;
267  if (b[i].second == kIsNormal)
268  chi2 += q * q;
269  else if (b[i].second == kIsBelow) {
270  q -= 2;
271  if (q < 0)
272  chi2 += 0.5 * q * q;
273  } else if (b[i].second == kIsOver) {
274  q += 2;
275  if (q > 0)
276  chi2 += 0.5 * q * q;
277  }
278  // Penalty for negatives
279  if (x[i] < 0) {
280  q = x[i] * iSigma;
281  chi2 += q * q;
282  }
283  }
284  return chi2;
285 }
286 
287 /*****************************************************************************/
288 void DeDxHitCalibrator::getAlphaBeta(const std::vector<double>& x,
289  const std::vector<std::pair<double, int> >& b,
290  CLHEP::HepMatrix& alpha,
291  CLHEP::HepVector& beta,
292  const std::vector<bool>& isFix,
293  const double& coupling,
294  const double& iSigma) {
295  const auto& npar = b.size();
296  const auto a0 = coupling * iSigma;
297  const auto a1 = (1 - 2 * coupling) * iSigma;
298  const auto a00 = a0 * a0;
299  const auto a11 = a1 * a1;
300  const auto a01 = a0 * a1;
301  std::vector<double> y(npar, 0.);
302  for (size_t i = 0; i < npar; i++)
303  if (!isFix[i]) {
304  const auto dx = coupling * x[i];
305  if (i >= 1)
306  y[i - 1] += dx;
307  y[i] += x[i] - 2 * dx;
308  if (i + 1 < npar)
309  y[i + 1] += dx;
310  }
311  for (size_t i = 0; i < npar; i++) {
312  auto q = (y[i] - b[i].first) * iSigma;
313  int f(0);
314  if (b[i].second == kIsNormal)
315  f = 2;
316  else if (b[i].second == kIsBelow) {
317  q += 2;
318  if (q > 0)
319  f = 1;
320  } else if (b[i].second == kIsOver) {
321  q -= 2;
322  if (q < 0)
323  f = 1;
324  }
325  if (f > 0) {
326  if (i >= 1)
327  if (!isFix[i - 1]) {
328  alpha[i - 1][i - 1] += f * a00;
329  if (!isFix[i]) {
330  alpha[i - 1][i] += f * a01;
331  alpha[i][i - 1] += f * a01;
332  }
333  beta[i - 1] += f * q * a0;
334  }
335  if (!isFix[i]) {
336  alpha[i][i] += f * a11;
337  beta[i] += f * q * a1;
338  }
339  if (i + 1 < npar)
340  if (!isFix[i + 1]) {
341  alpha[i + 1][i + 1] += f * a00;
342  if (!isFix[i]) {
343  alpha[i + 1][i] += f * a01;
344  alpha[i][i + 1] += f * a01;
345  }
346  beta[i + 1] += f * q * a0;
347  }
348  }
349  // Penalty for negatives
350  if (!isFix[i])
351  if (x[i] < 0) {
352  alpha[i][i] += 2 * iSigma * iSigma;
353  q = x[i] * iSigma;
354  beta[i] += 2 * q * iSigma;
355  }
356  }
357  for (size_t i = 0; i < npar; i++)
358  if (isFix[i]) {
359  alpha[i][i] = 1.;
360  beta[i] = 0.;
361  }
362 }
363 
364 /*****************************************************************************/
365 std::pair<double, double> DeDxHitCalibrator::fitStripCluster(const std::vector<std::pair<double, int> >& b,
366  const double& coupling,
367  const double& iSigma) {
368  const auto& npar = b.size();
369  std::vector<bool> isFix(npar, false);
370  std::vector<double> x;
371  x.reserve(b.size());
372  for (const auto& ib : b)
373  x.emplace_back(ib.first);
374 
375  bool ok = false;
376  CLHEP::HepMatrix hessian(npar, npar);
377  int iter = 0;
378  do {
379  double diff(0);
380  auto old = getChi2(x, b, coupling, iSigma);
381  do {
382  CLHEP::HepMatrix alpha(npar, npar, 0.);
383  CLHEP::HepVector beta(npar, 0.);
384  getAlphaBeta(x, b, alpha, beta, isFix, coupling, iSigma);
385  const auto& delta = CLHEP::solve(alpha, -beta);
386  double lambda(1.);
387  std::vector<double> xn(npar);
388  for (size_t i = 0; i < npar; i++)
389  xn[i] = x[i] + lambda * delta[i];
390  const auto& next = getChi2(xn, b, coupling, iSigma);
391  diff = old - next;
392  if (diff > 0)
393  x = xn;
394  old = next;
395  hessian = alpha;
396  iter++;
397  } while (diff > 1e-6 && iter < 100);
398  // Check if we have negatives
399  const auto& mi = std::min_element(x.begin(), x.end()) - x.begin();
400  if (x[mi] < 0) {
401  x[mi] = 0.;
402  isFix[mi] = true;
403  } else
404  ok = true;
405  } while (!ok && iter < 100);
406  hessian /= 2.;
407  int flag;
408  hessian.invert(flag);
409 
410  double var2(0.);
411  for (size_t i = 0; i < npar; i++)
412  for (size_t j = 0; j < npar; j++)
413  if (!isFix[i] && !isFix[j])
414  var2 += hessian[i][j];
415  var2 = std::abs(var2);
416 
417  double sum(0.);
418  for (size_t i = 0; i < npar; i++)
419  if (!isFix[i])
420  sum += x[i];
421 
422  return {sum, std::sqrt(var2)};
423 }
424 
425 //define this as a plug-in
void processHitInfo(const reco::DeDxHitInfo &, const float &trackMomentum, reco::DeDxHitCollection &, reco::DeDxHitCollection &)
std::pair< uint32_t, unsigned char > ChipId
ESGetTokenH3DDVariant esConsumes(std::string const &Record, edm::ConsumesCollector &)
Definition: DeDxTools.cc:283
unsigned int pxbLayer(const DetId &id) const
static const TGPicture * info(bool iBackgroundIsBlack)
std::pair< double, double > fitStripCluster(const std::vector< std::pair< double, int > > &, const double &, const double &)
static constexpr int PXB
static constexpr int TECThick
std::vector< Track > TrackCollection
collection of Tracks
Definition: TrackFwd.h:14
edm::ESHandle< TrackerGeometry > tkGeom_
std::vector< DeDxHit > DeDxHitCollection
Definition: DeDxHit.h:45
static constexpr int Compatible
Definition: DeDxHitInfo.h:40
const std::vector< double > & thr() const
void beginRun(edm::Run const &, const edm::EventSetup &) override
const edm::ESGetToken< TrackerGeometry, TrackerDigiGeometryRecord > tkGeomToken_
const std::vector< double > & alpha() const
const std::map< ChipId, float > & gain() const
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
U second(std::pair< T, U > const &p)
static constexpr int nChannels
edm::ESHandle< TrackerTopology > tkTopo_
int iEvent
Definition: GenABIO.cc:224
edm::Association< DeDxHitInfoCollection > DeDxHitInfoAss
Definition: DeDxHitInfo.h:123
const edm::EDGetTokenT< reco::DeDxHitInfoAss > dedxHitInfoToken_
const edm::ESGetToken< TrackerTopology, TrackerTopologyRcd > tkTopoToken_
edm::ESHandle< DeDxCalibration > dedxCalib_
T sqrt(T t)
Definition: SSEVec.h:23
static constexpr int TID
void setESObjects(const edm::EventSetup &es) override
const edm::ESGetToken< DeDxCalibration, DeDxCalibrationRcd > dedxCalibToken_
double getChi2(const std::vector< double > &, const std::vector< std::pair< double, int > > &, const double &, const double &)
static constexpr int TOB
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
Transition
Definition: Transition.h:12
int getDetId(const DetId &, const float &)
static void fillDescriptions(edm::ConfigurationDescriptions &)
double f[11][100]
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
const int VCaltoElectronGain_
edm::RefProd< TrackCollection > TrackRefProd
persistent reference to a Track collection
Definition: TrackFwd.h:26
const int VCaltoElectronOffset_
ESHandle< T > getHandle(const ESGetToken< T, R > &iToken) const
Definition: EventSetup.h:130
const TrackerGeomDet * idToDet(DetId) const override
~DeDxHitCalibrator() override=default
static constexpr int TIB
Definition: DetId.h:17
static constexpr int TECThin
const int VCaltoElectronOffset_L1_
void getAlphaBeta(const std::vector< double > &, const std::vector< std::pair< double, int > > &, CLHEP::HepMatrix &, CLHEP::HepVector &, const std::vector< bool > &, const double &, const double &)
static constexpr float a0
const edm::EDGetTokenT< reco::TrackCollection > tracksToken_
Constants and enumerated types for FED/FEC systems.
edm::Ref< TrackCollection > TrackRef
persistent reference to a Track
Definition: TrackFwd.h:20
double b
Definition: hdecay.h:120
void add(std::string const &label, ParameterSetDescription const &psetDescription)
DeDxHitCalibrator(const edm::ParameterSet &)
static constexpr int Complete
Definition: DeDxHitInfo.h:40
bool isSaturated(const Digi &digi, const int &maxADCvalue, int ifirst, int n)
fixed size matrix
static constexpr int kIsOver
void produce(edm::Event &, const edm::EventSetup &) override
HLT enums.
SiPixelGainCalibrationOfflineService pixelCalib_
const int VCaltoElectronGain_L1_
static const uint16_t STRIPS_PER_APV
double a
Definition: hdecay.h:121
static constexpr float MeVperADCStrip
col
Definition: cuy.py:1009
float correctEnergy(const float &, const ChipId &)
float x
const std::vector< double > & sigma() const
float getPedestal(const uint32_t &detID, const int &col, const int &row) override
const double MeVPerElectron_
static constexpr int PXF
static constexpr int kIsNormal
def move(src, dest)
Definition: eostools.py:511
Definition: Run.h:45
uint16_t *__restrict__ uint16_t const *__restrict__ adc
ib
Definition: cuy.py:661
constexpr int ROCSizeInX
float getGain(const uint32_t &detID, const int &col, const int &row) override
static constexpr int kIsBelow
constexpr int ROCSizeInY
const int pixelSaturationThr_