File indexing completed on 2024-04-06 12:21:16
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #include "DataFormats/Common/interface/Handle.h"
0022 #include "DataFormats/Common/interface/View.h"
0023 #include "DataFormats/L1TrackTrigger/interface/TTTypes.h"
0024 #include "FWCore/Framework/interface/Frameworkfwd.h"
0025 #include "FWCore/Framework/interface/global/EDProducer.h"
0026 #include "FWCore/Framework/interface/Event.h"
0027 #include "FWCore/Framework/interface/MakerMacros.h"
0028 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0029 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0030 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0031 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0032 #include "FWCore/Utilities/interface/EDMException.h"
0033 #include "FWCore/Utilities/interface/StreamID.h"
0034
0035
0036 #include <ap_fixed.h>
0037 #include <ap_int.h>
0038
0039
0040 #define _USE_MATH_DEFINES
0041 #include <cmath>
0042 #include <string>
0043 #include <sstream>
0044 #include <vector>
0045
0046
0047
0048
0049
0050 class L1GTTInputProducer : public edm::global::EDProducer<> {
0051 public:
0052 explicit L1GTTInputProducer(const edm::ParameterSet&);
0053 ~L1GTTInputProducer() override;
0054
0055 static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
0056
0057 private:
0058
0059 static constexpr unsigned int Npars4 = 4;
0060 static constexpr unsigned int Npars5 = 5;
0061 enum ConversionBitWidths {
0062 kEtaMagSize = 3,
0063 kEtaFracSize = 5,
0064 kEtaInputSize = 16,
0065
0066 kPTMagSize = 7,
0067 kPTFracSize = 3,
0068 kPTInputSize = 15,
0069
0070 kEtaOutputSize = kEtaMagSize + kEtaFracSize,
0071 kPTOutputSize = kPTMagSize + kPTFracSize,
0072 };
0073
0074 static constexpr double kEtaErrThresh = 0.0485;
0075
0076 static constexpr double kPTErrThresh = 5;
0077 static constexpr double kSynchrotron = (1.0 / (0.3 * 3.8));
0078 static constexpr unsigned int kPtLutSize = (1 << ConversionBitWidths::kPTOutputSize);
0079 static constexpr unsigned int kEtaLutSize = (1 << (ConversionBitWidths::kEtaOutputSize - 1));
0080
0081 typedef TTTrack<Ref_Phase2TrackerDigi_> L1Track;
0082 typedef std::vector<L1Track> TTTrackCollection;
0083 typedef edm::View<L1Track> TTTrackCollectionView;
0084 typedef ap_fixed<kEtaOutputSize, kEtaMagSize, AP_RND_CONV, AP_SAT> out_eta_t;
0085 typedef TTTrack_TrackWord::tanl_t in_eta_t;
0086 typedef ap_ufixed<kPTOutputSize, kPTMagSize, AP_RND_CONV, AP_SAT> out_pt_t;
0087 typedef TTTrack_TrackWord::rinv_t in_pt_t;
0088 typedef ap_uint<1> out_charge_t;
0089
0090
0091 void generate_eta_lut();
0092 void generate_pt_lut();
0093 bool getEtaBits(
0094 const L1Track& track, out_eta_t& etaBits, double& expected, double& maxErrPerc, double& maxErrEpsilon) const;
0095 bool getPtBits(const L1Track& track,
0096 out_pt_t& ptBits,
0097 out_charge_t& chargeBit,
0098 double& expected,
0099 double& maxErrPerc,
0100 double& maxErrEpsilon,
0101 double& minErrPerc,
0102 double& minExpected) const;
0103 double indexTanLambda2Eta(unsigned int indexTanLambda) const;
0104 double inverseRT2InversePT(unsigned int indexRT) const;
0105 void produce(edm::StreamID, edm::Event&, const edm::EventSetup&) const override;
0106 template <typename T>
0107 int sgn(T val) const {
0108 return (T(0) < val) - (val < T(0));
0109 }
0110 double unpackSignedValue(unsigned int bits, unsigned int nBits, double lsb) const;
0111
0112
0113 const edm::EDGetTokenT<TTTrackCollectionView> l1TracksToken_;
0114 const std::string outputCollectionName_;
0115 bool setTrackWordBits_;
0116 int debug_;
0117 std::vector<out_pt_t> pt_lut_;
0118 std::vector<out_eta_t> eta_lut_;
0119 };
0120
0121
0122
0123
0124 L1GTTInputProducer::L1GTTInputProducer(const edm::ParameterSet& iConfig)
0125 : l1TracksToken_(consumes<TTTrackCollectionView>(iConfig.getParameter<edm::InputTag>("l1TracksInputTag"))),
0126 outputCollectionName_(iConfig.getParameter<std::string>("outputCollectionName")),
0127 setTrackWordBits_(iConfig.getParameter<bool>("setTrackWordBits")),
0128 debug_(iConfig.getParameter<int>("debug")) {
0129
0130 generate_eta_lut();
0131 generate_pt_lut();
0132
0133
0134 produces<TTTrackCollection>(outputCollectionName_);
0135 produces<std::vector<double>>("L1GTTInputTrackPtExpected");
0136 produces<std::vector<double>>("L1GTTInputTrackEtaExpected");
0137 }
0138
0139 L1GTTInputProducer::~L1GTTInputProducer() {}
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155 void L1GTTInputProducer::generate_eta_lut() {
0156
0157 eta_lut_.reserve(kEtaLutSize);
0158
0159
0160 for (unsigned int i = 0; i < kEtaLutSize; i++) {
0161
0162 unsigned int index = ((i + 0.5) * pow(2, (int)(kEtaInputSize - kEtaOutputSize)));
0163 double newValue = indexTanLambda2Eta(index);
0164 out_eta_t out_eta = newValue;
0165 eta_lut_[i] = out_eta;
0166 }
0167
0168 if (debug_ >= 3) {
0169 edm::LogInfo log("L1GTTInputProducer");
0170 log << "generate_eta_lut::The eta_lut_[" << kEtaLutSize << "] values are ... \n";
0171 for (unsigned int i = 0; i < kEtaLutSize; i++) {
0172 log << "\t" << i << "\t" << eta_lut_[i] << "\n";
0173 }
0174 }
0175 }
0176
0177 void L1GTTInputProducer::generate_pt_lut() {
0178
0179 pt_lut_.reserve(kPtLutSize);
0180
0181
0182 for (unsigned int i = 0; i < kPtLutSize; i++) {
0183 unsigned int index = (i + 0.5) * pow(2, (int)(kPTInputSize - 1 - kPTOutputSize));
0184 double newValue = inverseRT2InversePT(index);
0185 out_pt_t out_pt = 1.0 / newValue;
0186 pt_lut_[i] = out_pt;
0187 }
0188
0189 if (debug_ >= 3) {
0190 edm::LogInfo log("L1GTTInputProducer");
0191 log << "generate_pt_lut::The pt_lut_[" << kPtLutSize << "] values are ... \n";
0192 for (unsigned int i = 0; i < kPtLutSize; i++) {
0193 log << "\t" << i << "\t" << pt_lut_[i] << "\n";
0194 }
0195 }
0196 }
0197
0198 double L1GTTInputProducer::unpackSignedValue(unsigned int bits, unsigned int nBits, double lsb) const {
0199
0200
0201
0202 assert((bits >> nBits) == 0);
0203
0204
0205 int digitizedValue = bits;
0206 if (bits & (1 << (nBits - 1))) {
0207 digitizedValue -= (1 << nBits);
0208 }
0209
0210
0211 return (double(digitizedValue) + 0.5) * lsb;
0212 }
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222 double L1GTTInputProducer::indexTanLambda2Eta(unsigned int indexTanLambda) const {
0223 double tanl = unpackSignedValue(indexTanLambda, kEtaInputSize, TTTrack_TrackWord::stepTanL);
0224 double theta = (M_PI / 2.0) - atan(tanl);
0225 double eta = -1.0 * log(tan(theta / 2.0));
0226 if (debug_ >= 3) {
0227 edm::LogInfo("L1GTTInputProducer") << "indexTanLambda2Eta::tanl index = " << indexTanLambda << "\n"
0228 << "indexTanLambda2Eta::tanl value = " << tanl << "\n"
0229 << "indexTanLambda2Eta::theta = " << theta << "\n"
0230 << "indexTanLambda2Eta::eta = " << eta;
0231 }
0232 return eta;
0233 }
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243 double L1GTTInputProducer::inverseRT2InversePT(unsigned int indexRT) const {
0244 double inverseRT = unpackSignedValue(indexRT, kPTInputSize, TTTrack_TrackWord::stepRinv);
0245 return 100.0 * kSynchrotron * inverseRT;
0246 }
0247
0248 bool L1GTTInputProducer::getEtaBits(
0249 const L1Track& track, out_eta_t& etaBits, double& expected, double& maxErrPerc, double& maxErrEpsilon) const {
0250
0251 in_eta_t value = track.getTanlWord();
0252
0253
0254 out_eta_t maxValuePossible = pow(2, 15);
0255 expected = indexTanLambda2Eta(value);
0256 if (expected > maxValuePossible) {
0257 expected = maxValuePossible;
0258 }
0259
0260
0261
0262
0263 in_eta_t indexTanLambda = value;
0264 in_eta_t mask = ~0;
0265 bool sign = indexTanLambda.range(kEtaInputSize - 1, kEtaInputSize - 1);
0266 mask *= sign;
0267
0268
0269 indexTanLambda ^= mask;
0270 indexTanLambda += sign;
0271
0272
0273 indexTanLambda =
0274 indexTanLambda >>
0275 (kEtaInputSize -
0276 kEtaOutputSize);
0277 indexTanLambda =
0278 (indexTanLambda < (1 << (kEtaOutputSize - 1))) ? indexTanLambda : in_eta_t((1 << (kEtaOutputSize - 1)) - 1);
0279 etaBits = eta_lut_[indexTanLambda];
0280
0281
0282 out_eta_t maskOut;
0283 maskOut.V = ~0;
0284 maskOut *= sign;
0285 etaBits ^= maskOut;
0286 etaBits.V += sign;
0287
0288
0289 double delta = std::abs(expected - etaBits.to_double());
0290 double perc_diff = (delta / std::abs(expected)) * 100.;
0291 if (delta > maxErrEpsilon) {
0292 maxErrPerc = perc_diff;
0293 maxErrEpsilon = delta;
0294 }
0295
0296 if (delta >= kEtaErrThresh) {
0297 edm::LogError("L1GTTInputProducer") << "getEtaBits::MISMATCH!!!\n"
0298 << "\tTTTrack tanL = " << track.tanL() << "\n"
0299 << "\tTTTrack eta = " << track.momentum().eta() << "\n"
0300 << "\tTTTrack_TrackWord = " << track.getTrackWord().to_string(2) << "\n"
0301 << "\tTTTrack_TrackWord tanlWord = " << track.getTanlWord() << " ("
0302 << track.getTanlWord().to_string(2) << ")\n"
0303 << "\tin_eta_t value = " << value << " (" << value.to_string(2) << ")\n"
0304 << "\tExpected value = " << expected << "\n"
0305 << "\tCalculated eta = " << etaBits.to_double() << " (" << etaBits.to_string(2)
0306 << ") @ index " << indexTanLambda << "\n"
0307 << "\tDelta = " << delta << "\tpercentage error = " << perc_diff;
0308 return true;
0309 } else {
0310 if (debug_ >= 2) {
0311 edm::LogInfo("L1GTTInputProducer")
0312 << "getEtaBits::SUCCESS (TTTrack, floating eta calculation, bitwise calculation, initial index, lut index) = "
0313 << "(" << track.momentum().eta() << ", " << expected << ", " << etaBits << ", " << value << ", "
0314 << indexTanLambda << ")";
0315 }
0316 }
0317
0318 return false;
0319 }
0320
0321 bool L1GTTInputProducer::getPtBits(const L1Track& track,
0322 out_pt_t& ptBits,
0323 out_charge_t& chargeBit,
0324 double& expected,
0325 double& maxErrPerc,
0326 double& maxErrEpsilon,
0327 double& minErrPerc,
0328 double& minExpected) const {
0329
0330 in_pt_t value = track.getRinvWord();
0331 in_pt_t value_initial = value;
0332
0333
0334 out_pt_t maxValuePossible = pow(2, 16);
0335 expected = 1.0 / inverseRT2InversePT(value);
0336 bool saturation = true;
0337 if (std::abs(expected) > maxValuePossible) {
0338 expected = maxValuePossible;
0339 } else {
0340 saturation = false;
0341 }
0342
0343
0344
0345
0346 in_pt_t mask = ~0;
0347 bool sign = value.range(kPTInputSize - 1, kPTInputSize - 1);
0348 mask *= sign;
0349
0350
0351 value ^= mask;
0352 value += sign;
0353
0354
0355 value = value >> (kPTInputSize - 1 - (kPTOutputSize));
0356
0357
0358 ptBits = pt_lut_[value];
0359
0360
0361 chargeBit = sign;
0362 double charge = 1. - (2 * chargeBit.to_uint());
0363
0364
0365 double delta = std::abs(expected - (charge * ptBits.to_double()));
0366 double perc_diff = (delta / std::abs(expected)) * 100.;
0367
0368 if (delta > maxErrEpsilon) {
0369 maxErrPerc = perc_diff;
0370 maxErrEpsilon = delta;
0371 } else if (delta < minExpected && !saturation && minErrPerc > 100.0) {
0372 minErrPerc = perc_diff;
0373 minExpected = expected;
0374 }
0375
0376 if (std::abs(perc_diff) >= kPTErrThresh && !saturation) {
0377 edm::LogError("L1GTTInputProducer") << "getPtBits::MISMATCH!!!\n"
0378 << "\tTTTrack Rinv = " << track.rInv() << "\n"
0379 << "\tTTTrack pt = " << track.momentum().transverse() << "\n"
0380 << "\tTTTrack_TrackWord = " << track.getTrackWord().to_string(2) << "\n"
0381 << "\tTTTrack_TrackWord RinvWord = " << track.getRinvWord() << " ("
0382 << track.getRinvWord().to_string(2) << ")\n"
0383 << "\tin_pt_t value = " << value_initial << " (" << value_initial.to_string(2)
0384 << ")\n"
0385 << "\tExpected value = " << expected << "\n"
0386 << "\tCalculated pt = " << ptBits.to_double() << " (" << ptBits.to_string(2)
0387 << ") @ index " << value << "\n"
0388 << "\tcharge = " << charge << " (bit = " << chargeBit << ")\n"
0389 << "\tDelta = " << delta << "\tpercentage error = " << perc_diff;
0390 return true;
0391 } else {
0392 if (debug_ >= 2) {
0393 edm::LogInfo("L1GTTInputProducer") << "getPtBits::SUCCESS (TTTrack, floating pt calculation, charge, bitwise "
0394 "calculation, initial index, lut index) = "
0395 << "(" << sgn(track.rInv()) * track.momentum().transverse() << ", " << expected
0396 << ", " << charge << ", " << ptBits << ", " << value_initial << ", " << value
0397 << ")";
0398 }
0399 }
0400
0401 return false;
0402 }
0403
0404
0405 void L1GTTInputProducer::produce(edm::StreamID, edm::Event& iEvent, const edm::EventSetup& iSetup) const {
0406 auto vTTTrackOutput = std::make_unique<TTTrackCollection>();
0407 auto vPtOutput = std::make_unique<std::vector<double>>();
0408 auto vEtaOutput = std::make_unique<std::vector<double>>();
0409
0410 edm::Handle<TTTrackCollectionView> l1TracksHandle;
0411 iEvent.getByToken(l1TracksToken_, l1TracksHandle);
0412
0413 out_charge_t chargeBit = 0;
0414 out_pt_t ptBits = 0;
0415 out_eta_t etaBits = 0;
0416 in_pt_t ptBitsShifted = 0;
0417 in_eta_t etaBitsShifted = 0;
0418 unsigned int error_pt_c = 0;
0419 unsigned int error_eta_c = 0;
0420 double expectedPt = 0.0;
0421 double expectedEta = 0.0;
0422 double maxErrPercPt = 0.0;
0423 double maxErrPercEta = 0.0;
0424 double maxErrEpsilonPt = 0.0;
0425 double maxErrEpsilonEta = 0.0;
0426 double minErrPercPt = 10000000.0;
0427 double minExpectedPt = 10000000.0;
0428
0429 unsigned int nOutput = l1TracksHandle->size();
0430 vTTTrackOutput->reserve(nOutput);
0431 vPtOutput->reserve(nOutput);
0432 vEtaOutput->reserve(nOutput);
0433 for (const auto& track : *l1TracksHandle) {
0434 if (setTrackWordBits_ && !(track.nFitPars() == Npars4 || track.nFitPars() == Npars5)) {
0435 throw cms::Exception("nFitPars unknown")
0436 << "L1GTTInputProducer::produce method is called with numFitPars_ = " << track.nFitPars()
0437 << ". The only possible values are 4/5.";
0438 }
0439
0440
0441 vTTTrackOutput->push_back(track);
0442 auto& currentTrackRef = vTTTrackOutput->back();
0443 if (debug_ >= 2) {
0444 edm::LogInfo("L1GTTInputProducer") << "produce::word before anything with setTrackWordBits_ = "
0445 << setTrackWordBits_ << ": " << currentTrackRef.getTrackWord().to_string(2);
0446 }
0447
0448
0449 if (setTrackWordBits_)
0450 currentTrackRef.setTrackWordBits();
0451 if (debug_ >= 2) {
0452 edm::LogInfo("L1GTTInputProducer") << "produce::word after initial setting of the track word "
0453 << currentTrackRef.getTrackWord().to_string(2);
0454 }
0455
0456
0457 error_pt_c += getPtBits(
0458 currentTrackRef, ptBits, chargeBit, expectedPt, maxErrPercPt, maxErrEpsilonPt, minErrPercPt, minExpectedPt);
0459 error_eta_c += getEtaBits(currentTrackRef, etaBits, expectedEta, maxErrPercEta, maxErrEpsilonEta);
0460
0461
0462 ptBitsShifted = ptBits.range();
0463 etaBitsShifted = etaBits.range();
0464
0465
0466 ptBitsShifted = ptBitsShifted << 2;
0467 etaBitsShifted = etaBitsShifted << 8;
0468
0469
0470 ptBitsShifted.set(kPTInputSize - 1, chargeBit);
0471
0472
0473 currentTrackRef.setTrackWord(currentTrackRef.getValidWord(),
0474 ptBitsShifted,
0475 currentTrackRef.getPhiWord(),
0476 etaBitsShifted,
0477 currentTrackRef.getZ0Word(),
0478 currentTrackRef.getD0Word(),
0479 currentTrackRef.getChi2RPhiWord(),
0480 currentTrackRef.getChi2RZWord(),
0481 currentTrackRef.getBendChi2Word(),
0482 currentTrackRef.getHitPatternWord(),
0483 currentTrackRef.getMVAQualityWord(),
0484 currentTrackRef.getMVAOtherWord());
0485 if (debug_ >= 2) {
0486 edm::LogInfo("L1GTTInputProducer") << "produce::charge after all conversions " << chargeBit << "\n"
0487 << "produce::ptBits after all conversions " << ptBits.to_string(2) << " ("
0488 << ptBitsShifted.to_string(2) << " = " << ptBitsShifted.to_uint() << ")\n"
0489 << "produce::etaBits after all conversions " << etaBits.to_string(2) << " ("
0490 << etaBitsShifted.to_string(2) << " = " << etaBitsShifted.to_uint() << ")\n"
0491 << "produce::word after all conversions "
0492 << vTTTrackOutput->back().getTrackWord().to_string(2);
0493 }
0494
0495
0496 vPtOutput->push_back(expectedPt);
0497 vEtaOutput->push_back(expectedEta);
0498 }
0499
0500 if (debug_ >= 1) {
0501 edm::LogInfo("L1GTTInputProducer") << "\nNumber of converted tracks: " << nOutput << "\n\n"
0502 << "q/r ==> pt conversion:\n"
0503 << "\tError Threshold: " << kPTErrThresh << "%\n"
0504 << "\tMax error: " << maxErrEpsilonPt
0505 << " GeV difference with percentage: " << maxErrPercPt << "% @ "
0506 << 100.0 * maxErrEpsilonPt / maxErrPercPt << " GeV"
0507 << "\n"
0508 << "\tError @ max range: " << minExpectedPt
0509 << " GeV with precentage: " << minErrPercPt << "%"
0510 << "\n"
0511 << "\tTotal number of errors: " << error_pt_c << "\n\n"
0512 << "tan(lambda) ==> eta conversion:\n"
0513 << "\tError Threshold: " << kEtaErrThresh << "\n"
0514 << "\tMax error: " << maxErrEpsilonEta << " with percentage: " << maxErrPercEta
0515 << "% @ " << 100.0 * maxErrEpsilonEta / maxErrPercEta << "\n"
0516 << "\tTotal number of errors: " << error_eta_c;
0517 }
0518
0519 if (error_pt_c + error_eta_c) {
0520 edm::LogError("L1GTTInputProducer") << "produce::" << error_pt_c << "/" << error_eta_c
0521 << " pt/eta mismatches detected!!!";
0522 }
0523
0524
0525 iEvent.put(std::move(vTTTrackOutput), outputCollectionName_);
0526 iEvent.put(std::move(vPtOutput), "L1GTTInputTrackPtExpected");
0527 iEvent.put(std::move(vEtaOutput), "L1GTTInputTrackEtaExpected");
0528 }
0529
0530
0531 void L1GTTInputProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
0532
0533 edm::ParameterSetDescription desc;
0534 desc.add<int>("debug", 0)->setComment("Verbosity levels: 0, 1, 2, 3");
0535 desc.add<edm::InputTag>("l1TracksInputTag", edm::InputTag("TTTracksFromTrackletEmulation", "Level1TTTracks"));
0536 desc.add<std::string>("outputCollectionName", "Level1TTTracksConverted");
0537 desc.add<bool>("setTrackWordBits", true)
0538 ->setComment(
0539 "flag indicated whether the TTTrack_TrackWord should be set from float parameters or skipped (if TrackWord "
0540 "set by e.g. GTTFileReader decoding)");
0541 descriptions.addWithDefaultLabel(desc);
0542 }
0543
0544
0545 DEFINE_FWK_MODULE(L1GTTInputProducer);