File indexing completed on 2024-06-22 02:24:11
0001 #include "FWCore/Framework/interface/stream/EDProducer.h"
0002 #include "FWCore/Framework/interface/EventSetup.h"
0003 #include "FWCore/Framework/interface/Event.h"
0004 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0005 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0006 #include "FWCore/ParameterSet/interface/FileInPath.h"
0007
0008 #include "DataFormats/TrackReco/interface/Track.h"
0009 #include "DataFormats/TrackReco/interface/TrackDeDxHits.h"
0010 #include "DataFormats/TrackReco/interface/DeDxHit.h"
0011 #include "DataFormats/TrackReco/interface/DeDxHitInfo.h"
0012 #include "DataFormats/TrackerCommon/interface/TrackerTopology.h"
0013 #include "DataFormats/SiStripCommon/interface/ConstantsForHardwareSystems.h"
0014 #include "CondFormats/PhysicsToolsObjects/interface/DeDxCalibration.h"
0015 #include "CondFormats/DataRecord/interface/DeDxCalibrationRcd.h"
0016 #include "CondFormats/SiPixelObjects/interface/PixelIndices.h"
0017
0018 #include "Geometry/Records/interface/TrackerDigiGeometryRecord.h"
0019 #include "Geometry/Records/interface/TrackerTopologyRcd.h"
0020 #include "Geometry/CommonDetUnit/interface/PixelGeomDetUnit.h"
0021 #include "Geometry/TrackerGeometryBuilder/interface/TrackerGeometry.h"
0022 #include "Geometry/TrackerGeometryBuilder/interface/StripGeomDetUnit.h"
0023 #include "CalibTracker/SiPixelESProducers/interface/SiPixelGainCalibrationOfflineService.h"
0024
0025 #include <fstream>
0026
0027 class DeDxHitCalibrator : public edm::stream::EDProducer<> {
0028 public:
0029 static constexpr int kIsNormal = 0, kIsBelow = 1, kIsOver = 2;
0030 static constexpr int PXB = 0, PXF = 1, TIB = 2, TID = 3, TOB = 4, TECThin = 5, TECThick = 6;
0031 typedef std::pair<uint32_t, unsigned char> ChipId;
0032
0033 explicit DeDxHitCalibrator(const edm::ParameterSet&);
0034 ~DeDxHitCalibrator() override = default;
0035 static void fillDescriptions(edm::ConfigurationDescriptions&);
0036
0037 private:
0038 void beginRun(edm::Run const&, const edm::EventSetup&) override;
0039 void produce(edm::Event&, const edm::EventSetup&) override;
0040
0041 int getDetId(const DetId&, const float&);
0042 float correctEnergy(const float&, const ChipId&);
0043 void processHitInfo(const reco::DeDxHitInfo&,
0044 const float& trackMomentum,
0045 reco::DeDxHitCollection&,
0046 reco::DeDxHitCollection&);
0047
0048 double getChi2(const std::vector<double>&, const std::vector<std::pair<double, int> >&, const double&, const double&);
0049 void getAlphaBeta(const std::vector<double>&,
0050 const std::vector<std::pair<double, int> >&,
0051 CLHEP::HepMatrix&,
0052 CLHEP::HepVector&,
0053 const std::vector<bool>&,
0054 const double&,
0055 const double&);
0056 std::pair<double, double> fitStripCluster(const std::vector<std::pair<double, int> >&, const double&, const double&);
0057
0058 const bool applyGain_;
0059 const double MeVPerElectron_;
0060 const int VCaltoElectronGain_, VCaltoElectronGain_L1_, VCaltoElectronOffset_, VCaltoElectronOffset_L1_;
0061 const int pixelSaturationThr_;
0062 const edm::EDGetTokenT<reco::TrackCollection> tracksToken_;
0063 const edm::EDGetTokenT<reco::DeDxHitInfoAss> dedxHitInfoToken_;
0064 const edm::ESGetToken<DeDxCalibration, DeDxCalibrationRcd> dedxCalibToken_;
0065 const edm::ESGetToken<TrackerGeometry, TrackerDigiGeometryRecord> tkGeomToken_;
0066 const edm::ESGetToken<TrackerTopology, TrackerTopologyRcd> tkTopoToken_;
0067
0068 SiPixelGainCalibrationOfflineService pixelCalib_;
0069 edm::ESHandle<DeDxCalibration> dedxCalib_;
0070 edm::ESHandle<TrackerGeometry> tkGeom_;
0071 edm::ESHandle<TrackerTopology> tkTopo_;
0072 };
0073
0074 DeDxHitCalibrator::DeDxHitCalibrator(const edm::ParameterSet& iConfig)
0075 : applyGain_(iConfig.getParameter<bool>("applyGain")),
0076 MeVPerElectron_(iConfig.getParameter<double>("MeVPerElectron")),
0077 VCaltoElectronGain_(iConfig.getParameter<int>("VCaltoElectronGain")),
0078 VCaltoElectronGain_L1_(iConfig.getParameter<int>("VCaltoElectronGain_L1")),
0079 VCaltoElectronOffset_(iConfig.getParameter<int>("VCaltoElectronOffset")),
0080 VCaltoElectronOffset_L1_(iConfig.getParameter<int>("VCaltoElectronOffset_L1")),
0081 pixelSaturationThr_(iConfig.getParameter<int>("pixelSaturationThr")),
0082 tracksToken_(consumes<reco::TrackCollection>(iConfig.getParameter<edm::InputTag>("trackProducer"))),
0083 dedxHitInfoToken_(consumes<reco::DeDxHitInfoAss>(iConfig.getParameter<edm::InputTag>("dedxHitInfo"))),
0084 dedxCalibToken_(esConsumes<DeDxCalibration, DeDxCalibrationRcd, edm::Transition::BeginRun>()),
0085 tkGeomToken_(esConsumes<TrackerGeometry, TrackerDigiGeometryRecord, edm::Transition::BeginRun>()),
0086 tkTopoToken_(esConsumes<TrackerTopology, TrackerTopologyRcd, edm::Transition::BeginRun>()),
0087 pixelCalib_(iConfig, consumesCollector()) {
0088 produces<reco::TrackDeDxHitsCollection>("PixelHits");
0089 produces<reco::TrackDeDxHitsCollection>("StripHits");
0090 }
0091
0092 void DeDxHitCalibrator::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
0093 edm::ParameterSetDescription desc;
0094 desc.add<bool>("applyGain", true);
0095 desc.add<double>("MeVPerElectron", 3.61e-06);
0096 desc.add<int>("VCaltoElectronGain", 65);
0097 desc.add<int>("VCaltoElectronGain_L1", 65);
0098 desc.add<int>("VCaltoElectronOffset", -414);
0099 desc.add<int>("VCaltoElectronOffset_L1", -414);
0100 desc.add<int>("pixelSaturationThr", 254);
0101 desc.add<edm::InputTag>("trackProducer", edm::InputTag("generalTracks"));
0102 desc.add<edm::InputTag>("dedxHitInfo", edm::InputTag("dedxHitInfo"));
0103 descriptions.add("dedxHitCalibrator", desc);
0104 }
0105
0106 void DeDxHitCalibrator::beginRun(edm::Run const&, const edm::EventSetup& iSetup) {
0107 dedxCalib_ = iSetup.getHandle(dedxCalibToken_);
0108 tkGeom_ = iSetup.getHandle(tkGeomToken_);
0109 tkTopo_ = iSetup.getHandle(tkTopoToken_);
0110 }
0111
0112 void DeDxHitCalibrator::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) {
0113 const auto& tracks = iEvent.getHandle(tracksToken_);
0114 const auto& dedxHitInfo = iEvent.get(dedxHitInfoToken_);
0115 pixelCalib_.setESObjects(iSetup);
0116
0117
0118 auto pixelTrackDeDxHitAss = std::make_unique<reco::TrackDeDxHitsCollection>(reco::TrackRefProd(tracks));
0119 auto stripTrackDeDxHitAss = std::make_unique<reco::TrackDeDxHitsCollection>(reco::TrackRefProd(tracks));
0120
0121 for (size_t i = 0; i < tracks->size(); i++) {
0122 const auto& track = reco::TrackRef(tracks, i);
0123 const auto& dedxHits = dedxHitInfo[track];
0124 if (dedxHits.isNull())
0125 continue;
0126 reco::DeDxHitCollection pixelHits, stripHits;
0127 processHitInfo(*dedxHits, track->p(), pixelHits, stripHits);
0128 pixelTrackDeDxHitAss->setValue(i, pixelHits);
0129 stripTrackDeDxHitAss->setValue(i, stripHits);
0130 }
0131
0132 iEvent.put(std::move(pixelTrackDeDxHitAss), "PixelHits");
0133 iEvent.put(std::move(stripTrackDeDxHitAss), "StripHits");
0134 }
0135
0136
0137 void DeDxHitCalibrator::processHitInfo(const reco::DeDxHitInfo& info,
0138 const float& trackMomentum,
0139 reco::DeDxHitCollection& pixelHits,
0140 reco::DeDxHitCollection& stripHits) {
0141
0142 static constexpr double a = 0.07;
0143 static constexpr double l0 = 450e-4;
0144
0145 for (size_t i = 0; i < info.size(); i++) {
0146
0147 const auto& type = info.type(i);
0148 if (!(type & (1 << reco::DeDxHitInfo::Complete)) || !(type & (1 << reco::DeDxHitInfo::Compatible)))
0149 continue;
0150
0151
0152 const auto& pl = info.pathlength(i);
0153 const auto pathLength = pl * (1. + a * std::log(pl / l0));
0154 const DetId& detId = info.detId(i);
0155
0156
0157 if (const auto& stripCluster = info.stripCluster(i)) {
0158 const auto& thickness =
0159 dynamic_cast<const StripGeomDetUnit*>(tkGeom_->idToDet(detId))->surface().bounds().thickness();
0160 const auto& det = getDetId(detId, thickness);
0161 const auto& chipId = ChipId(detId, stripCluster->barycenter() / sistrip::STRIPS_PER_APV);
0162
0163 const auto& thr = dedxCalib_->thr()[det];
0164 std::vector<std::pair<double, int> > b;
0165 b.reserve(stripCluster->amplitudes().size() + 2);
0166 b.emplace_back(thr, kIsBelow);
0167 for (const auto& adc : stripCluster->amplitudes()) {
0168 if (adc > 253)
0169 b.emplace_back(254., kIsOver);
0170 else
0171 b.emplace_back(adc + 0.5, kIsNormal);
0172 }
0173 b.emplace_back(thr, kIsBelow);
0174
0175 const auto& result = fitStripCluster(b, dedxCalib_->alpha()[det], 1. / dedxCalib_->sigma()[det]);
0176
0177 const auto& energy = correctEnergy(result.first * sistrip::MeVperADCStrip, chipId);
0178 const auto& esigma = correctEnergy(result.second * sistrip::MeVperADCStrip, chipId);
0179
0180 const auto& charge = pathLength != 0. ? energy / pathLength : 0.;
0181 stripHits.emplace_back(charge, trackMomentum, pathLength, 0, esigma);
0182 }
0183
0184
0185 if (const auto& pixelCluster = info.pixelCluster(i)) {
0186 const auto& thickness =
0187 dynamic_cast<const PixelGeomDetUnit*>(tkGeom_->idToDet(detId))->surface().bounds().thickness();
0188 const auto& det = getDetId(detId, thickness);
0189 const auto& chipId =
0190 ChipId(detId, (int(pixelCluster->x() / ROCSizeInX) << 3) + int(pixelCluster->y() / ROCSizeInY));
0191
0192 double delta(0);
0193 bool isSaturated(false);
0194 for (size_t j = 0; j < pixelCluster->pixelADC().size(); j++) {
0195 const auto& elec = pixelCluster->pixelADC()[j];
0196 delta += elec * MeVPerElectron_;
0197 if (isSaturated)
0198 continue;
0199
0200 const auto& row = pixelCluster->minPixelRow() + pixelCluster->pixelOffset()[2 * j];
0201 const auto& col = pixelCluster->minPixelCol() + pixelCluster->pixelOffset()[2 * j + 1];
0202
0203 const auto& DBgain = pixelCalib_.getGain(detId, col, row);
0204 const auto& DBpedestal = pixelCalib_.getPedestal(detId, col, row);
0205 if (elec == std::numeric_limits<uint16_t>::max())
0206 isSaturated = true;
0207 else if (DBgain > 0.) {
0208 double vcal;
0209 const auto& theLayer = (detId.subdetId() == 1) ? tkTopo_->pxbLayer(detId) : 0;
0210 if (theLayer == 1)
0211 vcal = (elec - VCaltoElectronOffset_L1_) / VCaltoElectronGain_L1_;
0212 else
0213 vcal = (elec - VCaltoElectronOffset_) / VCaltoElectronGain_;
0214 const auto adc = std::round(DBpedestal + vcal / DBgain);
0215 if (adc > pixelSaturationThr_)
0216 isSaturated = true;
0217 }
0218 }
0219
0220 const auto& energy = correctEnergy(delta, chipId);
0221 if (det != PXF && energy <= 50e-3)
0222 continue;
0223
0224 const unsigned char& nChannels = pixelCluster->pixelADC().size();
0225 const auto esigma = 10e-3 * std::sqrt(nChannels);
0226
0227 const auto& charge = pathLength != 0. ? energy / pathLength : 0.;
0228 pixelHits.emplace_back(charge, trackMomentum, pathLength, isSaturated, esigma);
0229 }
0230 }
0231 }
0232
0233
0234 int DeDxHitCalibrator::getDetId(const DetId& id, const float& thickness) {
0235 const auto& subdet = id.subdetId() - 1;
0236 if (subdet == TECThin && thickness > 400e-4)
0237 return TECThick;
0238 return subdet;
0239 }
0240
0241
0242 float DeDxHitCalibrator::correctEnergy(const float& energy, const ChipId& detId) {
0243 const auto& g = dedxCalib_->gain().find(detId);
0244 if (applyGain_ && g != dedxCalib_->gain().end())
0245 return energy * g->second;
0246 return energy;
0247 }
0248
0249
0250 double DeDxHitCalibrator::getChi2(const std::vector<double>& x,
0251 const std::vector<std::pair<double, int> >& b,
0252 const double& coupling,
0253 const double& iSigma) {
0254 const auto& npar = b.size();
0255 std::vector<double> y(npar, 0.);
0256 for (size_t i = 0; i < npar; i++) {
0257 const auto dx = coupling * x[i];
0258 if (i >= 1)
0259 y[i - 1] += dx;
0260 y[i] += x[i] - 2 * dx;
0261 if (i + 1 < npar)
0262 y[i + 1] += dx;
0263 }
0264 double chi2(0.);
0265 for (size_t i = 0; i < npar; i++) {
0266 auto q = (b[i].first - y[i]) * iSigma;
0267 if (b[i].second == kIsNormal)
0268 chi2 += q * q;
0269 else if (b[i].second == kIsBelow) {
0270 q -= 2;
0271 if (q < 0)
0272 chi2 += 0.5 * q * q;
0273 } else if (b[i].second == kIsOver) {
0274 q += 2;
0275 if (q > 0)
0276 chi2 += 0.5 * q * q;
0277 }
0278
0279 if (x[i] < 0) {
0280 q = x[i] * iSigma;
0281 chi2 += q * q;
0282 }
0283 }
0284 return chi2;
0285 }
0286
0287
0288 void DeDxHitCalibrator::getAlphaBeta(const std::vector<double>& x,
0289 const std::vector<std::pair<double, int> >& b,
0290 CLHEP::HepMatrix& alpha,
0291 CLHEP::HepVector& beta,
0292 const std::vector<bool>& isFix,
0293 const double& coupling,
0294 const double& iSigma) {
0295 const auto& npar = b.size();
0296 const auto a0 = coupling * iSigma;
0297 const auto a1 = (1 - 2 * coupling) * iSigma;
0298 const auto a00 = a0 * a0;
0299 const auto a11 = a1 * a1;
0300 const auto a01 = a0 * a1;
0301 std::vector<double> y(npar, 0.);
0302 for (size_t i = 0; i < npar; i++)
0303 if (!isFix[i]) {
0304 const auto dx = coupling * x[i];
0305 if (i >= 1)
0306 y[i - 1] += dx;
0307 y[i] += x[i] - 2 * dx;
0308 if (i + 1 < npar)
0309 y[i + 1] += dx;
0310 }
0311 for (size_t i = 0; i < npar; i++) {
0312 auto q = (y[i] - b[i].first) * iSigma;
0313 int f(0);
0314 if (b[i].second == kIsNormal)
0315 f = 2;
0316 else if (b[i].second == kIsBelow) {
0317 q += 2;
0318 if (q > 0)
0319 f = 1;
0320 } else if (b[i].second == kIsOver) {
0321 q -= 2;
0322 if (q < 0)
0323 f = 1;
0324 }
0325 if (f > 0) {
0326 if (i >= 1)
0327 if (!isFix[i - 1]) {
0328 alpha[i - 1][i - 1] += f * a00;
0329 if (!isFix[i]) {
0330 alpha[i - 1][i] += f * a01;
0331 alpha[i][i - 1] += f * a01;
0332 }
0333 beta[i - 1] += f * q * a0;
0334 }
0335 if (!isFix[i]) {
0336 alpha[i][i] += f * a11;
0337 beta[i] += f * q * a1;
0338 }
0339 if (i + 1 < npar)
0340 if (!isFix[i + 1]) {
0341 alpha[i + 1][i + 1] += f * a00;
0342 if (!isFix[i]) {
0343 alpha[i + 1][i] += f * a01;
0344 alpha[i][i + 1] += f * a01;
0345 }
0346 beta[i + 1] += f * q * a0;
0347 }
0348 }
0349
0350 if (!isFix[i])
0351 if (x[i] < 0) {
0352 alpha[i][i] += 2 * iSigma * iSigma;
0353 q = x[i] * iSigma;
0354 beta[i] += 2 * q * iSigma;
0355 }
0356 }
0357 for (size_t i = 0; i < npar; i++)
0358 if (isFix[i]) {
0359 alpha[i][i] = 1.;
0360 beta[i] = 0.;
0361 }
0362 }
0363
0364
0365 std::pair<double, double> DeDxHitCalibrator::fitStripCluster(const std::vector<std::pair<double, int> >& b,
0366 const double& coupling,
0367 const double& iSigma) {
0368 const auto& npar = b.size();
0369 std::vector<bool> isFix(npar, false);
0370 std::vector<double> x;
0371 x.reserve(b.size());
0372 for (const auto& ib : b)
0373 x.emplace_back(ib.first);
0374
0375 bool ok = false;
0376 CLHEP::HepMatrix hessian(npar, npar);
0377 int iter = 0;
0378 do {
0379 double diff(0);
0380 auto old = getChi2(x, b, coupling, iSigma);
0381 do {
0382 CLHEP::HepMatrix alpha(npar, npar, 0.);
0383 CLHEP::HepVector beta(npar, 0.);
0384 getAlphaBeta(x, b, alpha, beta, isFix, coupling, iSigma);
0385 const auto& delta = CLHEP::solve(alpha, -beta);
0386 double lambda(1.);
0387 std::vector<double> xn(npar);
0388 for (size_t i = 0; i < npar; i++)
0389 xn[i] = x[i] + lambda * delta[i];
0390 const auto& next = getChi2(xn, b, coupling, iSigma);
0391 diff = old - next;
0392 if (diff > 0)
0393 x = xn;
0394 old = next;
0395 hessian = alpha;
0396 iter++;
0397 } while (diff > 1e-6 && iter < 100);
0398
0399 const auto& mi = std::min_element(x.begin(), x.end()) - x.begin();
0400 if (x[mi] < 0) {
0401 x[mi] = 0.;
0402 isFix[mi] = true;
0403 } else
0404 ok = true;
0405 } while (!ok && iter < 100);
0406 hessian /= 2.;
0407 int flag;
0408 hessian.invert(flag);
0409
0410 double var2(0.);
0411 for (size_t i = 0; i < npar; i++)
0412 for (size_t j = 0; j < npar; j++)
0413 if (!isFix[i] && !isFix[j])
0414 var2 += hessian[i][j];
0415 var2 = std::abs(var2);
0416
0417 double sum(0.);
0418 for (size_t i = 0; i < npar; i++)
0419 if (!isFix[i])
0420 sum += x[i];
0421
0422 return {sum, std::sqrt(var2)};
0423 }
0424
0425
0426 #include "FWCore/Framework/interface/MakerMacros.h"
0427 DEFINE_FWK_MODULE(DeDxHitCalibrator);