Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-09-07 04:37:07

0001 #include "L1Trigger/TrackFindingTMTT/interface/Histos.h"
0002 #include "L1Trigger/TrackFindingTMTT/interface/InputData.h"
0003 #include "L1Trigger/TrackFindingTMTT/interface/Sector.h"
0004 #include "L1Trigger/TrackFindingTMTT/interface/HTrphi.h"
0005 #include "L1Trigger/TrackFindingTMTT/interface/Make3Dtracks.h"
0006 #include "L1Trigger/TrackFindingTMTT/interface/TrkRZfilter.h"
0007 #include "L1Trigger/TrackFindingTMTT/interface/L1fittedTrack.h"
0008 #include "L1Trigger/TrackFindingTMTT/interface/Utility.h"
0009 #include "L1Trigger/TrackFindingTMTT/interface/PrintL1trk.h"
0010 
0011 #include "DataFormats/Math/interface/deltaPhi.h"
0012 #include "DataFormats/Math/interface/deltaR.h"
0013 #include "FWCore/Utilities/interface/Exception.h"
0014 
0015 #include <TH1F.h>
0016 #include <TH2F.h>
0017 #include <TH2Poly.h>
0018 #include <TF1.h>
0019 #include <TPad.h>
0020 #include <TProfile.h>
0021 #include <TGraphAsymmErrors.h>
0022 #include <TGraph.h>
0023 #include <TEfficiency.h>
0024 
0025 #include <algorithm>
0026 #include <array>
0027 #include <unordered_set>
0028 #include <list>
0029 #include <sstream>
0030 #include <memory>
0031 #include <mutex>
0032 
0033 using namespace std;
0034 
0035 namespace tmtt {
0036 
0037   //=== Store cfg parameters.
0038 
0039   Histos::Histos(const Settings* settings) : settings_(settings), oldSumW2opt_(false), bApproxMistake_(false) {
0040     genMinStubLayers_ = settings->genMinStubLayers();
0041     numPhiSectors_ = settings->numPhiSectors();
0042     numEtaRegions_ = settings->numEtaRegions();
0043     houghMinPt_ = settings->houghMinPt();
0044     houghNbinsPt_ = settings->houghNbinsPt();
0045     houghNbinsPhi_ = settings->houghNbinsPhi();
0046     chosenRofZ_ = settings->chosenRofZ();
0047     trackFitters_ = settings->trackFitters();
0048     useRZfilter_ = settings->useRZfilter();
0049     ranRZfilter_ = (not useRZfilter_.empty());  // Was any r-z track filter run?
0050     resPlotOpt_ = settings->resPlotOpt();       // Only use signal events for helix resolution plots?
0051   }
0052 
0053   //=== Book all histograms
0054 
0055   void Histos::book() {
0056     // Don't bother booking histograms if user didn't request them via TFileService in their cfg.
0057     if (not this->enabled())
0058       return;
0059 
0060     oldSumW2opt_ = TH1::GetDefaultSumw2();
0061     TH1::SetDefaultSumw2(true);
0062 
0063     // Book histograms about input data.
0064     this->bookInputData();
0065     // Book histograms checking if (eta,phi) sector definition choices are good.
0066     this->bookEtaPhiSectors();
0067     // Book histograms checking filling of r-phi HT array.
0068     this->bookRphiHT();
0069     // Book histograms about r-z track filters.
0070     if (ranRZfilter_)
0071       this->bookRZfilters();
0072     // Book histograms studying 3D track candidates found after HT.
0073     this->bookTrackCands("HT");
0074     // Book histograms studying 3D track candidates found after r-z track filter.
0075     if (ranRZfilter_)
0076       this->bookTrackCands("RZ");
0077     // Book histograms studying track fitting performance
0078     this->bookTrackFitting();
0079   }
0080 
0081   //=== Fill all histograms
0082 
0083   void Histos::fill(const InputData& inputData,
0084                     const Array2D<unique_ptr<Sector>>& mSectors,
0085                     const Array2D<unique_ptr<HTrphi>>& mHtRphis,
0086                     const Array2D<unique_ptr<Make3Dtracks>>& mMake3Dtrks,
0087                     const std::map<std::string, std::list<const L1fittedTrack*>>& mapFinalTracks) {
0088     // Each function here protected by a mytex lock, so only one thread can run it at a time.
0089 
0090     // Don't bother filling histograms if user didn't request them via TFileService in their cfg.
0091     if (not this->enabled())
0092       return;
0093 
0094     // Fill histograms about input data.
0095     this->fillInputData(inputData);
0096 
0097     // Fill histograms checking if (eta,phi) sector definition choices are good.
0098     this->fillEtaPhiSectors(inputData, mSectors);
0099 
0100     // Fill histograms checking filling of r-phi HT array.
0101     this->fillRphiHT(mHtRphis);
0102 
0103     // Fill histograms about r-z track filters.
0104     if (ranRZfilter_)
0105       this->fillRZfilters(mMake3Dtrks);
0106 
0107     // Fill histograms studying 3D track candidates found after HT.
0108     this->fillTrackCands(inputData, mMake3Dtrks, "HT");
0109 
0110     // Fill histograms studying 3D track candidates found after r-z track filter.
0111     if (ranRZfilter_) {
0112       this->fillTrackCands(inputData, mMake3Dtrks, "RZ");
0113     }
0114 
0115     // Fill histograms studying track fitting performance
0116     this->fillTrackFitting(inputData, mapFinalTracks);
0117   }
0118 
0119   //=== Book histograms using input stubs and tracking particles.
0120 
0121   TFileDirectory Histos::bookInputData() {
0122     TFileDirectory inputDir = fs_->mkdir("InputData");
0123 
0124     hisStubsVsEta_ = inputDir.make<TH1F>("StubsVsEta", "; #eta; No. stubs in tracker", 30, -3.0, 3.0);
0125     hisStubsVsR_ = inputDir.make<TH1F>("StubsVsR", "; radius (cm); No. stubs in tracker", 1200, 0., 120.);
0126 
0127     hisNumLayersPerTP_ =
0128         inputDir.make<TH1F>("NumLayersPerTP", "; Number of layers per TP for alg. eff.", 20, -0.5, 19.5);
0129     hisNumPSLayersPerTP_ =
0130         inputDir.make<TH1F>("NumPSLayersPerTP", "; Number of PS layers per TP for alg. eff.", 20, -0.5, 19.5);
0131 
0132     // Study efficiency of tightened front end-electronics cuts.
0133 
0134     hisStubKillFE_ = inputDir.make<TProfile>(
0135         "StubKillFE", "; barrelLayer or 10+endcapRing; Stub fraction rejected by FE chip", 30, -0.5, 29.5);
0136     hisStubIneffiVsInvPt_ =
0137         inputDir.make<TProfile>("StubIneffiVsPt", "; 1/Pt; Inefficiency of FE chip for good stubs", 25, 0.0, 0.5);
0138     hisStubIneffiVsEta_ =
0139         inputDir.make<TProfile>("StubIneffiVsEta", "; |#eta|; Inefficiency of FE chip for good stubs", 15, 0.0, 3.0);
0140 
0141     // Study stub resolution.
0142 
0143     hisBendStub_ = inputDir.make<TH1F>("BendStub", "; Stub bend in units of strips", 59, -7.375, 7.375);
0144     hisBendResStub_ = inputDir.make<TH1F>("BendResStub", "; Stub bend minus TP bend in units of strips", 100, -5., 5.);
0145 
0146     // Histos for denominator of tracking efficiency
0147     hisTPinvptForEff_ = inputDir.make<TH1F>("TPinvptForEff", "; TP 1/Pt (for effi.);", 50, 0., 0.5);
0148     hisTPetaForEff_ = inputDir.make<TH1F>("TPetaForEff", "; TP #eta (for effi.);", 20, -3., 3.);
0149     hisTPphiForEff_ = inputDir.make<TH1F>("TPphiForEff", "; TP #phi (for effi.);", 20, -M_PI, M_PI);
0150     hisTPd0ForEff_ = inputDir.make<TH1F>("TPd0ForEff", "; TP d0 (for effi.);", 40, 0., 4.);
0151     hisTPz0ForEff_ = inputDir.make<TH1F>("TPz0ForEff", "; TP z0 (for effi.);", 50, 0., 25.);
0152     //
0153     hisTPinvptForAlgEff_ = inputDir.make<TH1F>("TPinvptForAlgEff", "; TP 1/Pt (for alg. effi.);", 50, 0., 0.5);
0154     hisTPetaForAlgEff_ = inputDir.make<TH1F>("TPetaForAlgEff", "; TP #eta (for alg. effi.);", 20, -3., 3.);
0155     hisTPphiForAlgEff_ = inputDir.make<TH1F>("TPphiForAlgEff", "; TP #phi (for alg. effi.);", 20, -M_PI, M_PI);
0156     hisTPd0ForAlgEff_ = inputDir.make<TH1F>("TPd0ForAlgEff", "; TP d0 (for alg. effi.);", 40, 0., 4.);
0157     hisTPz0ForAlgEff_ = inputDir.make<TH1F>("TPz0ForAlgEff", "; TP z0 (for alg. effi.);", 50, 0., 25.);
0158 
0159     return inputDir;
0160   }
0161 
0162   //=== Fill histograms using input stubs and tracking particles.
0163 
0164   void Histos::fillInputData(const InputData& inputData) {
0165     // Allow only one thread to run this function at a time
0166     static std::mutex myMutex;
0167     std::lock_guard<std::mutex> myGuard(myMutex);
0168 
0169     const list<const Stub*>& vStubs = inputData.stubsConst();
0170     const list<TP>& vTPs = inputData.getTPs();
0171 
0172     for (const Stub* stub : vStubs) {
0173       hisStubsVsEta_->Fill(stub->eta());
0174       hisStubsVsR_->Fill(stub->r());
0175     }
0176 
0177     // Study efficiency of stubs to pass front-end electronics cuts.
0178 
0179     const list<Stub>& vAllStubs = inputData.allStubs();  // Get all stubs prior to FE cuts to do this.
0180     for (const Stub& s : vAllStubs) {
0181       unsigned int layerOrTenPlusRing = s.barrel() ? s.layerId() : 10 + s.trackerModule()->endcapRing();
0182       // Fraction of all stubs (good and bad) failing tightened front-end electronics cuts.
0183       hisStubKillFE_->Fill(layerOrTenPlusRing, (!s.frontendPass()));
0184     }
0185 
0186     // Study efficiency for good stubs of tightened front end-electronics cuts.
0187     for (const TP& tp : vTPs) {
0188       if (tp.useForAlgEff()) {  // Only bother for stubs that are on TP that we have a chance of reconstructing.
0189         const vector<const Stub*>& stubs = tp.assocStubs();
0190         for (const Stub* s : stubs) {
0191           hisStubIneffiVsInvPt_->Fill(1. / tp.pt(), (!s->frontendPass()));
0192           hisStubIneffiVsEta_->Fill(std::abs(tp.eta()), (!s->frontendPass()));
0193         }
0194       }
0195     }
0196 
0197     // Plot stub bend-derived information.
0198     for (const Stub* stub : vStubs) {
0199       hisBendStub_->Fill(stub->bend());
0200     }
0201 
0202     // Look at stub resolution.
0203     for (const TP& tp : vTPs) {
0204       if (tp.useForAlgEff()) {
0205         const vector<const Stub*>& assStubs = tp.assocStubs();
0206 
0207         for (const Stub* stub : assStubs) {
0208           hisBendResStub_->Fill(stub->bend() - tp.dphi(stub->r()) / stub->dphiOverBend());
0209         }
0210 
0211         if (std::abs(tp.eta()) < 0.5) {
0212           double nLayersOnTP = Utility::countLayers(settings_, assStubs, true, false);
0213           double nPSLayersOnTP = Utility::countLayers(settings_, assStubs, true, true);
0214           hisNumLayersPerTP_->Fill(nLayersOnTP);
0215           hisNumPSLayersPerTP_->Fill(nPSLayersOnTP);
0216         }
0217       }
0218     }
0219 
0220     // Determine r (z) range of each barrel layer (endcap wheel).
0221 
0222     for (const Stub* stub : vStubs) {
0223       unsigned int layer = stub->layerId();
0224       if (stub->barrel()) {
0225         // Get range in r of each barrel layer.
0226         float r = stub->r();
0227         if (mapBarrelLayerMinR_.find(layer) == mapBarrelLayerMinR_.end()) {
0228           mapBarrelLayerMinR_[layer] = r;
0229           mapBarrelLayerMaxR_[layer] = r;
0230         } else {
0231           if (mapBarrelLayerMinR_[layer] > r)
0232             mapBarrelLayerMinR_[layer] = r;
0233           if (mapBarrelLayerMaxR_[layer] < r)
0234             mapBarrelLayerMaxR_[layer] = r;
0235         }
0236       } else {
0237         layer = layer % 10;
0238         // Range in |z| of each endcap wheel.
0239         float z = std::abs(stub->z());
0240         if (mapEndcapWheelMinZ_.find(layer) == mapEndcapWheelMinZ_.end()) {
0241           mapEndcapWheelMinZ_[layer] = z;
0242           mapEndcapWheelMaxZ_[layer] = z;
0243         } else {
0244           if (mapEndcapWheelMinZ_[layer] > z)
0245             mapEndcapWheelMinZ_[layer] = z;
0246           if (mapEndcapWheelMaxZ_[layer] < z)
0247             mapEndcapWheelMaxZ_[layer] = z;
0248         }
0249       }
0250     }
0251 
0252     // Determine Range in (r,|z|) of each module type.
0253 
0254     for (const Stub* stub : vStubs) {
0255       float r = stub->r();
0256       float z = std::abs(stub->z());
0257       unsigned int modType = stub->trackerModule()->moduleTypeID();
0258       // Do something ugly, as modules in 1-2nd & 3-4th endcap wheels are different to those in wheel 5 ...
0259       // And boundary between flat & tilted modules in barrel layers 1-3 varies in z.
0260       if (stub->barrel() && stub->layerId() == 1) {  // barrel layer 1
0261         if (mapExtraAModuleTypeMinR_.find(modType) == mapExtraAModuleTypeMinR_.end()) {
0262           mapExtraAModuleTypeMinR_[modType] = r;
0263           mapExtraAModuleTypeMaxR_[modType] = r;
0264           mapExtraAModuleTypeMinZ_[modType] = z;
0265           mapExtraAModuleTypeMaxZ_[modType] = z;
0266         } else {
0267           if (mapExtraAModuleTypeMinR_[modType] > r)
0268             mapExtraAModuleTypeMinR_[modType] = r;
0269           if (mapExtraAModuleTypeMaxR_[modType] < r)
0270             mapExtraAModuleTypeMaxR_[modType] = r;
0271           if (mapExtraAModuleTypeMinZ_[modType] > z)
0272             mapExtraAModuleTypeMinZ_[modType] = z;
0273           if (mapExtraAModuleTypeMaxZ_[modType] < z)
0274             mapExtraAModuleTypeMaxZ_[modType] = z;
0275         }
0276       } else if (stub->barrel() && stub->layerId() == 2) {  // barrel layer 2
0277         if (mapExtraBModuleTypeMinR_.find(modType) == mapExtraBModuleTypeMinR_.end()) {
0278           mapExtraBModuleTypeMinR_[modType] = r;
0279           mapExtraBModuleTypeMaxR_[modType] = r;
0280           mapExtraBModuleTypeMinZ_[modType] = z;
0281           mapExtraBModuleTypeMaxZ_[modType] = z;
0282         } else {
0283           if (mapExtraBModuleTypeMinR_[modType] > r)
0284             mapExtraBModuleTypeMinR_[modType] = r;
0285           if (mapExtraBModuleTypeMaxR_[modType] < r)
0286             mapExtraBModuleTypeMaxR_[modType] = r;
0287           if (mapExtraBModuleTypeMinZ_[modType] > z)
0288             mapExtraBModuleTypeMinZ_[modType] = z;
0289           if (mapExtraBModuleTypeMaxZ_[modType] < z)
0290             mapExtraBModuleTypeMaxZ_[modType] = z;
0291         }
0292       } else if (!stub->barrel() && (stub->layerId() % 10 == 1 || stub->layerId() % 10 == 2)) {  // endcap wheel 1-2
0293         if (mapExtraCModuleTypeMinR_.find(modType) == mapExtraCModuleTypeMinR_.end()) {
0294           mapExtraCModuleTypeMinR_[modType] = r;
0295           mapExtraCModuleTypeMaxR_[modType] = r;
0296           mapExtraCModuleTypeMinZ_[modType] = z;
0297           mapExtraCModuleTypeMaxZ_[modType] = z;
0298         } else {
0299           if (mapExtraCModuleTypeMinR_[modType] > r)
0300             mapExtraCModuleTypeMinR_[modType] = r;
0301           if (mapExtraCModuleTypeMaxR_[modType] < r)
0302             mapExtraCModuleTypeMaxR_[modType] = r;
0303           if (mapExtraCModuleTypeMinZ_[modType] > z)
0304             mapExtraCModuleTypeMinZ_[modType] = z;
0305           if (mapExtraCModuleTypeMaxZ_[modType] < z)
0306             mapExtraCModuleTypeMaxZ_[modType] = z;
0307         }
0308       } else if (!stub->barrel() && (stub->layerId() % 10 == 3 || stub->layerId() % 10 == 4)) {  // endcap wheel 3-4
0309         if (mapExtraDModuleTypeMinR_.find(modType) == mapExtraDModuleTypeMinR_.end()) {
0310           mapExtraDModuleTypeMinR_[modType] = r;
0311           mapExtraDModuleTypeMaxR_[modType] = r;
0312           mapExtraDModuleTypeMinZ_[modType] = z;
0313           mapExtraDModuleTypeMaxZ_[modType] = z;
0314         } else {
0315           if (mapExtraDModuleTypeMinR_[modType] > r)
0316             mapExtraDModuleTypeMinR_[modType] = r;
0317           if (mapExtraDModuleTypeMaxR_[modType] < r)
0318             mapExtraDModuleTypeMaxR_[modType] = r;
0319           if (mapExtraDModuleTypeMinZ_[modType] > z)
0320             mapExtraDModuleTypeMinZ_[modType] = z;
0321           if (mapExtraDModuleTypeMaxZ_[modType] < z)
0322             mapExtraDModuleTypeMaxZ_[modType] = z;
0323         }
0324       } else {  // barrel layer 3-6 or endcap wheel 5.
0325         if (mapModuleTypeMinR_.find(modType) == mapModuleTypeMinR_.end()) {
0326           mapModuleTypeMinR_[modType] = r;
0327           mapModuleTypeMaxR_[modType] = r;
0328           mapModuleTypeMinZ_[modType] = z;
0329           mapModuleTypeMaxZ_[modType] = z;
0330         } else {
0331           if (mapModuleTypeMinR_[modType] > r)
0332             mapModuleTypeMinR_[modType] = r;
0333           if (mapModuleTypeMaxR_[modType] < r)
0334             mapModuleTypeMaxR_[modType] = r;
0335           if (mapModuleTypeMinZ_[modType] > z)
0336             mapModuleTypeMinZ_[modType] = z;
0337           if (mapModuleTypeMaxZ_[modType] < z)
0338             mapModuleTypeMaxZ_[modType] = z;
0339         }
0340       }
0341     }
0342 
0343     //=== Make denominator of tracking efficiency plots
0344 
0345     for (const TP& tp : vTPs) {
0346       if (tp.useForEff()) {  // Check TP is good for efficiency measurement.
0347         // Plot kinematics of all good TP.
0348         hisTPinvptForEff_->Fill(1. / tp.pt());
0349         hisTPetaForEff_->Fill(tp.eta());
0350         hisTPphiForEff_->Fill(tp.phi0());
0351         // Plot also production point of all good TP.
0352         hisTPd0ForEff_->Fill(std::abs(tp.d0()));
0353         hisTPz0ForEff_->Fill(std::abs(tp.z0()));
0354 
0355         if (tp.useForAlgEff()) {  // Check TP is good for algorithmic efficiency measurement.
0356           hisTPinvptForAlgEff_->Fill(1. / tp.pt());
0357           hisTPetaForAlgEff_->Fill(tp.eta());
0358           hisTPphiForAlgEff_->Fill(tp.phi0());
0359           // Plot also production point of all good TP.
0360           hisTPd0ForAlgEff_->Fill(std::abs(tp.d0()));
0361           hisTPz0ForAlgEff_->Fill(std::abs(tp.z0()));
0362         }
0363       }
0364     }
0365   }
0366 
0367   //=== Book histograms checking if (eta,phi) sector defis(nition choices are good.
0368 
0369   TFileDirectory Histos::bookEtaPhiSectors() {
0370     TFileDirectory inputDir = fs_->mkdir("CheckSectors");
0371 
0372     // Check if stubs excessively duplicated between overlapping sectors.
0373     hisNumEtaSecsPerStub_ =
0374         inputDir.make<TH1F>("NumEtaSecPerStub", "; No. of #eta sectors each stub in", 20, -0.5, 19.5);
0375     hisNumPhiSecsPerStub_ =
0376         inputDir.make<TH1F>("NumPhiSecPerStub", "; No. of #phi sectors each stub in", 20, -0.5, 19.5);
0377 
0378     // Count stubs per (eta,phi) sector.
0379     hisNumStubsPerSec_ = inputDir.make<TH1F>("NumStubsPerSec", "; No. of stubs per sector", 150, -0.5, 299.5);
0380 
0381     return inputDir;
0382   }
0383 
0384   //=== Fill histograms checking if (eta,phi) sector definition choices are good.
0385 
0386   void Histos::fillEtaPhiSectors(const InputData& inputData, const Array2D<unique_ptr<Sector>>& mSectors) {
0387     // Allow only one thread to run this function at a time
0388     static std::mutex myMutex;
0389     std::lock_guard<std::mutex> myGuard(myMutex);
0390 
0391     const list<const Stub*>& vStubs = inputData.stubsConst();
0392     //const list<TP>& vTPs = inputData.getTPs();
0393 
0394     //=== Loop over all stubs, counting how many sectors each one appears in.
0395 
0396     for (const Stub* stub : vStubs) {
0397       // Number of (eta,phi), phi & eta sectors containing this stub.
0398       unsigned int nEtaSecs = 0;
0399       unsigned int nPhiSecs = 0;
0400 
0401       // Loop over (eta, phi) sectors.
0402       for (unsigned int iPhiSec = 0; iPhiSec < numPhiSectors_; iPhiSec++) {
0403         for (unsigned int iEtaReg = 0; iEtaReg < numEtaRegions_; iEtaReg++) {
0404           const Sector* sector = mSectors(iPhiSec, iEtaReg).get();
0405 
0406           // Check if sector contains stub stub, and if so count it.
0407           // Take care to just use one eta (phi) typical region when counting phi (eta) sectors.
0408           if (iPhiSec == 0 && sector->insideEta(stub))
0409             nEtaSecs++;
0410           if (iEtaReg == 0 && sector->insidePhi(stub))
0411             nPhiSecs++;
0412         }
0413       }
0414 
0415       // Plot number of sectors each stub appears in.
0416       hisNumEtaSecsPerStub_->Fill(nEtaSecs);
0417       hisNumPhiSecsPerStub_->Fill(nPhiSecs);
0418     }
0419 
0420     //=== Loop over all sectors, counting the stubs in each one.
0421     for (unsigned int iEtaReg = 0; iEtaReg < numEtaRegions_; iEtaReg++) {
0422       for (unsigned int iPhiSec = 0; iPhiSec < numPhiSectors_; iPhiSec++) {
0423         const Sector* sector = mSectors(iPhiSec, iEtaReg).get();
0424 
0425         unsigned int nStubs = 0;
0426         for (const Stub* stub : vStubs) {
0427           if (sector->inside(stub))
0428             nStubs++;
0429         }
0430         hisNumStubsPerSec_->Fill(nStubs);
0431       }
0432     }
0433   }
0434 
0435   //=== Book histograms checking filling of r-phi HT array.
0436 
0437   TFileDirectory Histos::bookRphiHT() {
0438     TFileDirectory inputDir = fs_->mkdir("HTrphi");
0439 
0440     return inputDir;
0441   }
0442 
0443   //=== Fill histograms checking filling of r-phi HT array.
0444 
0445   void Histos::fillRphiHT(const Array2D<unique_ptr<HTrphi>>& mHtRphis) {
0446     //--- Loop over (eta,phi) sectors, counting the number of stubs in the HT array of each.
0447 
0448     // Allow only one thread to run this function at a time (UNCOMMENT IF YOU ADD HISTOS HERE)
0449     //static std::mutex myMutex;
0450     //std::lock_guard<std::mutex> myGuard(myMutex);
0451   }
0452 
0453   //=== Book histograms about r-z track filters (or other filters applied after r-phi HT array).
0454 
0455   TFileDirectory Histos::bookRZfilters() {
0456     TFileDirectory inputDir = fs_->mkdir("RZfilters");
0457 
0458     return inputDir;
0459   }
0460 
0461   //=== Fill histograms about r-z track filters.
0462 
0463   void Histos::fillRZfilters(const Array2D<unique_ptr<Make3Dtracks>>& mMake3Dtrks) {
0464     // Allow only one thread to run this function at a time (UNCOMMENT IF YOU ADD HISTOS HERE)
0465     //static std::mutex myMutex;
0466     //std::lock_guard<std::mutex> myGuard(myMutex);
0467   }
0468 
0469   //=== Book histograms studying track candidates found by Hough Transform.
0470 
0471   TFileDirectory Histos::bookTrackCands(const string& tName) {
0472     // Now book histograms for studying tracking in general.
0473 
0474     auto addn = [tName](const string& s) { return TString::Format("%s_%s", s.c_str(), tName.c_str()); };
0475 
0476     TFileDirectory inputDir = fs_->mkdir(addn("TrackCands").Data());
0477 
0478     bool TMTT = (tName == "HT" || tName == "RZ");
0479 
0480     // Count tracks in various ways (including/excluding duplicates, excluding fakes ...)
0481     profNumTrackCands_[tName] =
0482         inputDir.make<TProfile>(addn("NumTrackCands"), "; class; N. of tracks in tracker", 7, 0.5, 7.5);
0483     profNumTrackCands_[tName]->GetXaxis()->SetBinLabel(7, "TP for eff recoed");
0484     profNumTrackCands_[tName]->GetXaxis()->SetBinLabel(6, "TP recoed");
0485     profNumTrackCands_[tName]->GetXaxis()->SetBinLabel(5, "TP recoed x #eta sector dups");
0486     profNumTrackCands_[tName]->GetXaxis()->SetBinLabel(4, "TP recoed x sector dups");
0487     profNumTrackCands_[tName]->GetXaxis()->SetBinLabel(2, "TP recoed x track dups");
0488     profNumTrackCands_[tName]->GetXaxis()->SetBinLabel(1, "reco tracks including fakes");
0489     profNumTrackCands_[tName]->LabelsOption("d");
0490 
0491     hisNumTrksPerNon_[tName] = inputDir.make<TH1F>(addn("NumTrksPerNon"), "; No. tracks per nonant;", 100, -0.5, 399.5);
0492 
0493     unsigned int nEta = numEtaRegions_;
0494     hisNumTracksVsQoverPt_[tName] =
0495         inputDir.make<TH1F>(addn("NumTracksVsQoverPt"), "; Q/Pt; No. of tracks in tracker", 100, -0.5, 0.5);
0496     if (TMTT) {
0497       profNumTracksVsEta_[tName] = inputDir.make<TProfile>(
0498           addn("NumTracksVsEta"), "; #eta region; No. of tracks in tracker", nEta, -0.5, nEta - 0.5);
0499     }
0500 
0501     // Count stubs per event assigned to tracks (determines HT data output rate)
0502 
0503     profStubsOnTracks_[tName] =
0504         inputDir.make<TProfile>(addn("StubsOnTracks"), "; ; No. of stubs on tracks per event", 1, 0.5, 1.5);
0505     hisStubsOnTracksPerNon_[tName] =
0506         inputDir.make<TH1F>(addn("StubsOnTracksPerNon"), "; No. of stubs on tracks per nonant", 100, -0.5, 4999.5);
0507 
0508     hisStubsPerTrack_[tName] = inputDir.make<TH1F>(addn("StubsPerTrack"), ";No. of stubs per track;", 50, -0.5, 49.5);
0509     hisLayersPerTrack_[tName] =
0510         inputDir.make<TH1F>(addn("LayersPerTrack"), ";No. of layers with stubs per track;", 20, -0.5, 19.5);
0511 
0512     if (TMTT) {
0513       hisNumStubsPerLink_[tName] =
0514           inputDir.make<TH1F>(addn("NumStubsPerLink"), "; Mean #stubs per MHT output opto-link;", 50, -0.5, 249.5);
0515       profMeanStubsPerLink_[tName] =
0516           inputDir.make<TProfile>(addn("MeanStubsPerLink"), "; Mean #stubs per MHT output opto-link;", 36, -0.5, 35.5);
0517     }
0518 
0519     hisFracMatchStubsOnTracks_[tName] = inputDir.make<TH1F>(
0520         addn("FracMatchStubsOnTracks"), "; Frac. of stubs per trk matching best TP;", 101, -0.005, 1.005);
0521 
0522     if (TMTT) {
0523       // Study duplication of tracks within an individual HT array.
0524       profDupTracksVsEta_[tName] =
0525           inputDir.make<TProfile>(addn("DupTracksVsTPeta"), "; #eta; No. of dup. trks per TP;", 15, 0.0, 3.0);
0526       profDupTracksVsInvPt_[tName] =
0527           inputDir.make<TProfile>(addn("DupTracksVsInvPt"), "; 1/Pt; No. of dup. trks per TP", 25, 0., 0.5);
0528     }
0529 
0530     // Histos of track params.
0531     hisQoverPt_[tName] = inputDir.make<TH1F>(addn("QoverPt"), "; track q/Pt", 100, -0.5, 0.5);
0532     hisPhi0_[tName] = inputDir.make<TH1F>(addn("Phi0"), "; track #phi0", 70, -3.5, 3.5);
0533     hisEta_[tName] = inputDir.make<TH1F>(addn("Eta"), "; track #eta", 60, -3.0, 3.0);
0534     hisZ0_[tName] = inputDir.make<TH1F>(addn("Z0"), "; track z0", 100, -25.0, 25.0);
0535 
0536     // Histos of track parameter resolution
0537     hisQoverPtRes_[tName] = inputDir.make<TH1F>(addn("QoverPtRes"), "; track resolution in q/Pt", 100, -0.06, 0.06);
0538     hisPhi0Res_[tName] = inputDir.make<TH1F>(addn("Phi0Res"), "; track resolution in #phi0", 100, -0.04, 0.04);
0539     hisEtaRes_[tName] = inputDir.make<TH1F>(addn("EtaRes"), "; track resolution in #eta", 100, -1.0, 1.0);
0540     hisZ0Res_[tName] = inputDir.make<TH1F>(addn("Z0Res"), "; track resolution in z0", 100, -10.0, 10.0);
0541 
0542     // Histos for tracking efficiency vs. TP kinematics
0543     hisRecoTPinvptForEff_[tName] =
0544         inputDir.make<TH1F>(addn("RecoTPinvptForEff"), "; TP 1/Pt of recoed tracks (for effi.);", 50, 0., 0.5);
0545     hisRecoTPetaForEff_[tName] =
0546         inputDir.make<TH1F>(addn("RecoTPetaForEff"), "; TP #eta of recoed tracks (for effi.);", 20, -3., 3.);
0547     hisRecoTPphiForEff_[tName] =
0548         inputDir.make<TH1F>(addn("RecoTPphiForEff"), "; TP #phi of recoed tracks (for effi.);", 20, -M_PI, M_PI);
0549 
0550     // Histo for efficiency to reconstruct track perfectly (no incorrect hits).
0551     hisPerfRecoTPinvptForEff_[tName] = inputDir.make<TH1F>(
0552         addn("PerfRecoTPinvptForEff"), "; TP 1/Pt of recoed tracks (for perf. effi.);", 50, 0., 0.5);
0553     hisPerfRecoTPetaForEff_[tName] =
0554         inputDir.make<TH1F>(addn("PerfRecoTPetaForEff"), "; TP #eta of recoed tracks (for perf. effi.);", 20, -3., 3.);
0555 
0556     // Histos for  tracking efficiency vs. TP production point
0557     hisRecoTPd0ForEff_[tName] =
0558         inputDir.make<TH1F>(addn("RecoTPd0ForEff"), "; TP d0 of recoed tracks (for effi.);", 40, 0., 4.);
0559     hisRecoTPz0ForEff_[tName] =
0560         inputDir.make<TH1F>(addn("RecoTPz0ForEff"), "; TP z0 of recoed tracks (for effi.);", 50, 0., 25.);
0561 
0562     // Histos for algorithmic tracking efficiency vs. TP kinematics
0563     hisRecoTPinvptForAlgEff_[tName] =
0564         inputDir.make<TH1F>(addn("RecoTPinvptForAlgEff"), "; TP 1/Pt of recoed tracks (for alg. effi.);", 50, 0., 0.5);
0565     hisRecoTPetaForAlgEff_[tName] =
0566         inputDir.make<TH1F>(addn("RecoTPetaForAlgEff"), "; TP #eta of recoed tracks (for alg. effi.);", 20, -3., 3.);
0567     hisRecoTPphiForAlgEff_[tName] = inputDir.make<TH1F>(
0568         addn("RecoTPphiForAlgEff"), "; TP #phi of recoed tracks (for alg. effi.);", 20, -M_PI, M_PI);
0569 
0570     // Histo for efficiency to reconstruct track perfectly (no incorrect hits).
0571     hisPerfRecoTPinvptForAlgEff_[tName] = inputDir.make<TH1F>(
0572         addn("PerfRecoTPinvptForAlgEff"), "; TP 1/Pt of recoed tracks (for perf. alg. effi.);", 50, 0., 0.5);
0573     hisPerfRecoTPetaForAlgEff_[tName] =
0574         inputDir.make<TH1F>(addn("PerfRecoTPetaForAlgEff"), "; TP #eta (for perf. alg. effi.);", 20, -3., 3.);
0575 
0576     // Histos for algorithmic tracking efficiency vs. TP production point
0577     hisRecoTPd0ForAlgEff_[tName] =
0578         inputDir.make<TH1F>(addn("RecoTPd0ForAlgEff"), "; TP d0 of recoed tracks (for alg. effi.);", 40, 0., 4.);
0579     hisRecoTPz0ForAlgEff_[tName] =
0580         inputDir.make<TH1F>(addn("RecoTPz0ForAlgEff"), "; TP z0 of recoed tracks (for alg. effi.);", 50, 0., 25.);
0581 
0582     return inputDir;
0583   }
0584 
0585   //=== Fill histograms studying track candidates found before track fit is run.
0586 
0587   void Histos::fillTrackCands(const InputData& inputData,
0588                               const Array2D<std::unique_ptr<Make3Dtracks>>& mMake3Dtrks,
0589                               const string& tName) {
0590     // Allow only one thread to run this function at a time
0591     static std::mutex myMutex;
0592     std::lock_guard<std::mutex> myGuard(myMutex);
0593 
0594     vector<L1track3D> tracks;
0595     bool withRZfilter = (tName == "RZ") ? true : false;
0596     for (unsigned int iEtaReg = 0; iEtaReg < numEtaRegions_; iEtaReg++) {
0597       for (unsigned int iPhiSec = 0; iPhiSec < numPhiSectors_; iPhiSec++) {
0598         const Make3Dtracks* make3Dtrk = mMake3Dtrks(iPhiSec, iEtaReg).get();
0599         const std::list<L1track3D>& tracksSec = make3Dtrk->trackCands3D(withRZfilter);
0600         tracks.insert(tracks.end(), tracksSec.begin(), tracksSec.end());
0601       }
0602     }
0603     this->fillTrackCands(inputData, tracks, tName);
0604   }
0605 
0606   //=== Fill histograms studying track candidates found before track fit is run.
0607 
0608   void Histos::fillTrackCands(const InputData& inputData, const vector<L1track3D>& tracks, const string& tName) {
0609     bool withRZfilter = (tName == "RZ");
0610 
0611     bool algoTMTT = (tName == "HT" || tName == "RZ");  // Check if running TMTT or Hybrid L1 tracking.
0612 
0613     const list<TP>& vTPs = inputData.getTPs();
0614 
0615     //=== Count track candidates found in the tracker.
0616 
0617     const unsigned int numPhiNonants = settings_->numPhiNonants();
0618     vector<unsigned int> nTrksPerEtaReg(numEtaRegions_, 0);
0619     vector<unsigned int> nTrksPerNonant(numPhiNonants, 0);
0620     for (const L1track3D& t : tracks) {
0621       unsigned int iNonant = floor((t.iPhiSec()) * numPhiNonants / (numPhiSectors_));  // phi nonant number
0622       nTrksPerEtaReg[t.iEtaReg()]++;
0623       nTrksPerNonant[iNonant]++;
0624     }
0625 
0626     profNumTrackCands_[tName]->Fill(1.0, tracks.size());  // Plot mean number of tracks/event.
0627     if (algoTMTT) {
0628       for (unsigned int iEtaReg = 0; iEtaReg < numEtaRegions_; iEtaReg++) {
0629         profNumTracksVsEta_[tName]->Fill(iEtaReg, nTrksPerEtaReg[iEtaReg]);
0630       }
0631     }
0632     for (unsigned int iNonant = 0; iNonant < numPhiNonants; iNonant++) {
0633       hisNumTrksPerNon_[tName]->Fill(nTrksPerNonant[iNonant]);
0634     }
0635 
0636     //=== Count stubs per event assigned to track candidates in the Tracker
0637 
0638     unsigned int nStubsOnTracks = 0;
0639     vector<unsigned int> nStubsOnTracksInNonant(numPhiNonants, 0);
0640 
0641     for (const L1track3D& t : tracks) {
0642       const vector<const Stub*>& stubs = t.stubsConst();
0643       unsigned int nStubs = stubs.size();
0644       unsigned int iNonant = floor((t.iPhiSec()) * numPhiNonants / (numPhiSectors_));  // phi nonant number
0645       // Count stubs on all tracks in this sector & nonant.
0646       nStubsOnTracks += nStubs;
0647       nStubsOnTracksInNonant[iNonant] += nStubs;
0648     }
0649 
0650     profStubsOnTracks_[tName]->Fill(1.0, nStubsOnTracks);
0651 
0652     for (unsigned int iNonant = 0; iNonant < numPhiNonants; iNonant++) {
0653       hisStubsOnTracksPerNon_[tName]->Fill(nStubsOnTracksInNonant[iNonant]);
0654     }
0655 
0656     // Plot number of tracks & number of stubs per output HT opto-link.
0657 
0658     if (algoTMTT && not withRZfilter) {
0659       //const unsigned int numPhiSecPerNon = numPhiSectors_ / numPhiNonants;
0660       // Hard-wired bodge
0661       const unsigned int nLinks = houghNbinsPt_ / 2;  // Hard-wired to number of course HT bins. Check.
0662 
0663       for (unsigned int iPhiNon = 0; iPhiNon < numPhiNonants; iPhiNon++) {
0664         // Each nonant has a separate set of links.
0665         vector<unsigned int> stubsToLinkCount(nLinks, 0);  // Must use vectors to count links with zero entries.
0666         for (const L1track3D& trk : tracks) {
0667           unsigned int iNonantTrk = floor((trk.iPhiSec()) * numPhiNonants / (numPhiSectors_));  // phi nonant number
0668           if (iPhiNon == iNonantTrk) {
0669             unsigned int link = trk.optoLinkID();
0670             if (link < nLinks) {
0671               stubsToLinkCount[link] += trk.numStubs();
0672             } else {
0673               std::stringstream text;
0674               text << "\n ===== HISTOS MESS UP: Increase size of nLinks ===== " << link << "\n";
0675               static std::once_flag printOnce;
0676               std::call_once(printOnce, [](string t) { edm::LogWarning("L1track") << t; }, text.str());
0677             }
0678           }
0679         }
0680 
0681         for (unsigned int link = 0; link < nLinks; link++) {
0682           unsigned int nstbs = stubsToLinkCount[link];
0683           hisNumStubsPerLink_[tName]->Fill(nstbs);
0684           profMeanStubsPerLink_[tName]->Fill(link, nstbs);
0685         }
0686       }
0687     }
0688 
0689     // Plot q/pt spectrum of track candidates, and number of stubs/tracks
0690     for (const L1track3D& trk : tracks) {
0691       hisNumTracksVsQoverPt_[tName]->Fill(trk.qOverPt());  // Plot reconstructed q/Pt of track cands.
0692       hisStubsPerTrack_[tName]->Fill(trk.numStubs());      // Stubs per track.
0693       hisLayersPerTrack_[tName]->Fill(trk.numLayers());
0694     }
0695 
0696     // Count fraction of stubs on each track matched to a TP that are from same TP.
0697 
0698     for (const L1track3D& trk : tracks) {
0699       // Only consider tracks that match a tracking particle for the alg. efficiency measurement.
0700       const TP* tp = trk.matchedTP();
0701       if (tp != nullptr) {
0702         if (tp->useForAlgEff()) {
0703           hisFracMatchStubsOnTracks_[tName]->Fill(trk.purity());
0704         }
0705       }
0706     }
0707 
0708     // Count total number of tracking particles in the event that were reconstructed,
0709     // counting also how many of them were reconstructed multiple times (duplicate tracks).
0710 
0711     unsigned int nRecoedTPsForEff = 0;     // Total no. of TPs for effi measurement recoed as >= 1 track.
0712     unsigned int nRecoedTPs = 0;           // Total no. of TPs recoed as >= 1 one track.
0713     unsigned int nEtaSecsMatchingTPs = 0;  // Total no. of eta sectors that all TPs were reconstructed in
0714     unsigned int nSecsMatchingTPs = 0;     // Total no. of eta x phi sectors that all TPs were reconstructed in
0715     unsigned int nTrksMatchingTPs = 0;     // Total no. of tracks that all TPs were reconstructed as
0716 
0717     for (const TP& tp : vTPs) {
0718       vector<const L1track3D*> matchedTrks;
0719       for (const L1track3D& trk : tracks) {
0720         const TP* tpAssoc = trk.matchedTP();
0721         if (tpAssoc != nullptr) {
0722           if (tpAssoc->index() == tp.index())
0723             matchedTrks.push_back(&trk);
0724         }
0725       }
0726       unsigned int nTrk = matchedTrks.size();
0727 
0728       bool tpRecoed = false;
0729 
0730       if (nTrk > 0) {
0731         tpRecoed = true;           // This TP was reconstructed at least once in tracker.
0732         nTrksMatchingTPs += nTrk;  // Increment sum by no. of tracks this TP was reconstructed as
0733 
0734         set<unsigned int> iEtaRegRecoed;
0735         for (const L1track3D* trk : matchedTrks)
0736           iEtaRegRecoed.insert(trk->iEtaReg());
0737         nEtaSecsMatchingTPs = iEtaRegRecoed.size();
0738 
0739         set<pair<unsigned int, unsigned int>> iSecRecoed;
0740         for (const L1track3D* trk : matchedTrks)
0741           iSecRecoed.insert({trk->iPhiSec(), trk->iEtaReg()});
0742         nSecsMatchingTPs = iSecRecoed.size();
0743 
0744         if (algoTMTT) {
0745           for (const auto& p : iSecRecoed) {
0746             unsigned int nTrkInSec = 0;
0747             for (const L1track3D* trk : matchedTrks) {
0748               if (trk->iPhiSec() == p.first && trk->iEtaReg() == p.second)
0749                 nTrkInSec++;
0750             }
0751             if (nTrkInSec > 0) {
0752               profDupTracksVsEta_[tName]->Fill(
0753                   std::abs(tp.eta()), nTrkInSec - 1);  // Study duplication of tracks within an individual HT array.
0754               profDupTracksVsInvPt_[tName]->Fill(
0755                   std::abs(tp.qOverPt()), nTrkInSec - 1);  // Study duplication of tracks within an individual HT array.
0756             }
0757           }
0758         }
0759       }
0760 
0761       if (tpRecoed) {
0762         // Increment sum each time a TP is reconstructed at least once inside Tracker
0763         if (tp.useForEff())
0764           nRecoedTPsForEff++;
0765         nRecoedTPs++;
0766       }
0767     }
0768 
0769     //--- Plot mean number of tracks/event, counting number due to different kinds of duplicates
0770 
0771     // Plot number of TPs for the efficiency measurement that are reconstructed.
0772     profNumTrackCands_[tName]->Fill(7.0, nRecoedTPsForEff);
0773     // Plot number of TPs that are reconstructed.
0774     profNumTrackCands_[tName]->Fill(6.0, nRecoedTPs);
0775     // Plot number of TPs that are reconstructed. Count +1 for each eta sector they are reconstructed in.
0776     profNumTrackCands_[tName]->Fill(5.0, nEtaSecsMatchingTPs);
0777     // Plot number of TPs that are reconstructed. Count +1 for each (eta,phi) sector they are reconstructed in.
0778     profNumTrackCands_[tName]->Fill(4.0, nSecsMatchingTPs);
0779     // Plot number of TP that are reconstructed. Count +1 for each track they are reconstructed as.
0780     profNumTrackCands_[tName]->Fill(2.0, nTrksMatchingTPs);
0781 
0782     // Histos of track helix params.
0783     for (const L1track3D& trk : tracks) {
0784       hisQoverPt_[tName]->Fill(trk.qOverPt());
0785       hisPhi0_[tName]->Fill(trk.phi0());
0786       hisEta_[tName]->Fill(trk.eta());
0787       hisZ0_[tName]->Fill(trk.z0());
0788     }
0789 
0790     // Histos of track parameter resolution
0791 
0792     for (const TP& tp : vTPs) {
0793       if ((resPlotOpt_ && tp.useForAlgEff()) ||
0794           (not resPlotOpt_)) {  // Check TP is good for efficiency measurement (& also comes from signal event if requested)
0795 
0796         // For each tracking particle, find the corresponding reconstructed track(s).
0797         for (const L1track3D& trk : tracks) {
0798           const TP* tpAssoc = trk.matchedTP();
0799           if (tpAssoc != nullptr) {
0800             if (tpAssoc->index() == tp.index()) {
0801               hisQoverPtRes_[tName]->Fill(trk.qOverPt() - tp.qOverPt());
0802               hisPhi0Res_[tName]->Fill(reco::deltaPhi(trk.phi0(), tp.phi0()));
0803               hisEtaRes_[tName]->Fill(trk.eta() - tp.eta());
0804               hisZ0Res_[tName]->Fill(trk.z0() - tp.z0());
0805             }
0806           }
0807         }
0808       }
0809     }
0810 
0811     //=== Study tracking efficiency by looping over tracking particles.
0812 
0813     for (const TP& tp : vTPs) {
0814       if (tp.useForEff()) {  // Check TP is good for efficiency measurement.
0815 
0816         // Check if this TP was reconstructed anywhere in the tracker..
0817         bool tpRecoed = false;
0818         bool tpRecoedPerfect = false;
0819         for (const L1track3D& trk : tracks) {
0820           const TP* tpAssoc = trk.matchedTP();
0821           if (tpAssoc != nullptr) {
0822             if (tpAssoc->index() == tp.index()) {
0823               tpRecoed = true;
0824               if (trk.purity() == 1.)
0825                 tpRecoedPerfect = true;
0826             }
0827           }
0828         }
0829 
0830         // If TP was reconstucted by HT, then plot its kinematics.
0831         if (tpRecoed) {
0832           hisRecoTPinvptForEff_[tName]->Fill(1. / tp.pt());
0833           hisRecoTPetaForEff_[tName]->Fill(tp.eta());
0834           hisRecoTPphiForEff_[tName]->Fill(tp.phi0());
0835           // Plot also production point of all good reconstructed TP.
0836           hisRecoTPd0ForEff_[tName]->Fill(std::abs(tp.d0()));
0837           hisRecoTPz0ForEff_[tName]->Fill(std::abs(tp.z0()));
0838           // Also plot efficiency to perfectly reconstruct the track (no fake hits)
0839           if (tpRecoedPerfect) {
0840             hisPerfRecoTPinvptForEff_[tName]->Fill(1. / tp.pt());
0841             hisPerfRecoTPetaForEff_[tName]->Fill(tp.eta());
0842           }
0843           if (tp.useForAlgEff()) {  // Check TP is good for algorithmic efficiency measurement.
0844             hisRecoTPinvptForAlgEff_[tName]->Fill(1. / tp.pt());
0845             hisRecoTPetaForAlgEff_[tName]->Fill(tp.eta());
0846             hisRecoTPphiForAlgEff_[tName]->Fill(tp.phi0());
0847             // Plot also production point of all good reconstructed TP.
0848             hisRecoTPd0ForAlgEff_[tName]->Fill(std::abs(tp.d0()));
0849             hisRecoTPz0ForAlgEff_[tName]->Fill(std::abs(tp.z0()));
0850 
0851             // Also plot efficiency to perfectly reconstruct the track (no fake hits)
0852             if (tpRecoedPerfect) {
0853               hisPerfRecoTPinvptForAlgEff_[tName]->Fill(1. / tp.pt());
0854               hisPerfRecoTPetaForAlgEff_[tName]->Fill(tp.eta());
0855             }
0856           }
0857         }
0858       }
0859     }
0860   }
0861 
0862   //=== Book histograms for studying track fitting.
0863 
0864   map<string, TFileDirectory> Histos::bookTrackFitting() {
0865     map<string, TFileDirectory> inputDirMap;
0866 
0867     for (const string& fitName : trackFitters_) {
0868       // Define lambda function to facilitate adding "fitName" histogram names.
0869       auto addn = [fitName](const string& s) { return TString::Format("%s_%s", s.c_str(), fitName.c_str()); };
0870 
0871       TFileDirectory inputDir = fs_->mkdir(fitName);
0872       inputDirMap[fitName] = inputDir;
0873 
0874       profNumFitTracks_[fitName] =
0875           inputDir.make<TProfile>(addn("NumFitTracks"), "; class; # of fitted tracks", 11, 0.5, 11.5, -0.5, 9.9e6);
0876       profNumFitTracks_[fitName]->GetXaxis()->SetBinLabel(7, "TP for eff fitted");
0877       profNumFitTracks_[fitName]->GetXaxis()->SetBinLabel(6, "TP fitted");
0878       profNumFitTracks_[fitName]->GetXaxis()->SetBinLabel(2, "Fit tracks that are genuine");
0879       profNumFitTracks_[fitName]->GetXaxis()->SetBinLabel(1, "Fit tracks including fakes");
0880       profNumFitTracks_[fitName]->LabelsOption("d");
0881 
0882       hisNumFitTrks_[fitName] =
0883           inputDir.make<TH1F>(addn("NumFitTrks"), "; No. fitted tracks in tracker;", 200, -0.5, 399.5);
0884       hisNumFitTrksPerNon_[fitName] =
0885           inputDir.make<TH1F>(addn("NumFitTrksPerNon"), "; No. fitted tracks per nonant;", 200, -0.5, 199.5);
0886 
0887       hisStubsPerFitTrack_[fitName] =
0888           inputDir.make<TH1F>(addn("StubsPerFitTrack"), "; No. of stubs per fitted track", 20, -0.5, 19.5);
0889       profStubsOnFitTracks_[fitName] = inputDir.make<TProfile>(
0890           addn("StubsOnFitTracks"), "; ; No. of stubs on all fitted tracks per event", 1, 0.5, 1.5);
0891 
0892       hisFitQinvPtMatched_[fitName] =
0893           inputDir.make<TH1F>(addn("FitQinvPtMatched"), "Fitted q/p_{T} for matched tracks", 120, -0.6, 0.6);
0894       hisFitPhi0Matched_[fitName] =
0895           inputDir.make<TH1F>(addn("FitPhi0Matched"), "Fitted #phi_{0} for matched tracks", 70, -3.5, 3.5);
0896       hisFitD0Matched_[fitName] =
0897           inputDir.make<TH1F>(addn("FitD0Matched"), "Fitted d_{0} for matched tracks", 100, -2., 2.);
0898       hisFitZ0Matched_[fitName] =
0899           inputDir.make<TH1F>(addn("FitZ0Matched"), "Fitted z_{0} for matched tracks", 100, -25., 25.);
0900       hisFitEtaMatched_[fitName] =
0901           inputDir.make<TH1F>(addn("FitEtaMatched"), "Fitted #eta for matched tracks", 70, -3.5, 3.5);
0902 
0903       hisFitQinvPtUnmatched_[fitName] =
0904           inputDir.make<TH1F>(addn("FitQinvPtUnmatched"), "Fitted q/p_{T} for unmatched tracks", 120, -0.6, 0.6);
0905       hisFitPhi0Unmatched_[fitName] =
0906           inputDir.make<TH1F>(addn("FitPhi0Unmatched"), "Fitted #phi_{0} for unmatched tracks", 70, -3.5, 3.5);
0907       hisFitD0Unmatched_[fitName] =
0908           inputDir.make<TH1F>(addn("FitD0Unmatched"), "Fitted d_{0} for unmatched tracks", 100, -2., 2.);
0909       hisFitZ0Unmatched_[fitName] =
0910           inputDir.make<TH1F>(addn("FitZ0Unmatched"), "Fitted z_{0} for unmatched tracks", 100, -25., 25.);
0911       hisFitEtaUnmatched_[fitName] =
0912           inputDir.make<TH1F>(addn("FitEtaUnmatched"), "Fitted #eta for unmatched tracks", 70, -3.5, 3.5);
0913 
0914       const unsigned int nBinsChi2 = 39;
0915       const float chi2dofBins[nBinsChi2 + 1] = {0.0,  0.2,  0.4,  0.6,   0.8,   1.0,   1.2,   1.4,   1.6,   1.8,
0916                                                 2.0,  2.4,  2.8,  3.2,   3.6,   4.0,   4.5,   5.0,   6.0,   7.0,
0917                                                 8.0,  9.0,  10.0, 12.0,  14.0,  16.0,  18.0,  20.0,  25.0,  30.0,
0918                                                 40.0, 50.0, 75.0, 100.0, 150.0, 200.0, 250.0, 350.0, 500.0, 1000.0};
0919 
0920       hisFitChi2DofRphiMatched_[fitName] =
0921           inputDir.make<TH1F>(addn("FitChi2DofRphiMatched"), ";#chi^{2}rphi;", nBinsChi2, chi2dofBins);
0922       hisFitChi2DofRzMatched_[fitName] =
0923           inputDir.make<TH1F>(addn("FitChi2DofRzMatched"), ";#chi^{2}rz/DOF;", nBinsChi2, chi2dofBins);
0924       profFitChi2DofRphiVsInvPtMatched_[fitName] =
0925           inputDir.make<TProfile>(addn("FitChi2DofRphiVsInvPtMatched"), "; 1/p_{T}; Fit #chi^{2}rphi/dof", 25, 0., 0.5);
0926 
0927       hisFitChi2DofRphiUnmatched_[fitName] =
0928           inputDir.make<TH1F>(addn("FitChi2DofRphiUnmatched"), ";#chi^{2}rphi/DOF;", nBinsChi2, chi2dofBins);
0929       hisFitChi2DofRzUnmatched_[fitName] =
0930           inputDir.make<TH1F>(addn("FitChi2DofRzUnmatched"), ";#chi^{2}rz/DOF;", nBinsChi2, chi2dofBins);
0931       profFitChi2DofRphiVsInvPtUnmatched_[fitName] = inputDir.make<TProfile>(
0932           addn("FitChi2DofRphiVsInvPtUnmatched"), "; 1/p_{T}; Fit #chi^{2}rphi/dof", 25, 0., 0.5);
0933 
0934       // Monitoring specific track fit algorithms.
0935       if (fitName.find("KF") != string::npos) {
0936         hisKalmanNumUpdateCalls_[fitName] =
0937             inputDir.make<TH1F>(addn("KalmanNumUpdateCalls"), "; Calls to KF updator;", 100, -0.5, 99.5);
0938 
0939         hisKalmanChi2DofSkipLay0Matched_[fitName] = inputDir.make<TH1F>(
0940             addn("KalmanChi2DofSkipLay0Matched"), ";#chi^{2} for nSkippedLayers = 0;", nBinsChi2, chi2dofBins);
0941         hisKalmanChi2DofSkipLay1Matched_[fitName] = inputDir.make<TH1F>(
0942             addn("KalmanChi2DofSkipLay1Matched"), ";#chi^{2} for nSkippedLayers = 1;", nBinsChi2, chi2dofBins);
0943         hisKalmanChi2DofSkipLay2Matched_[fitName] = inputDir.make<TH1F>(
0944             addn("KalmanChi2DofSkipLay2Matched"), ";#chi^{2} for nSkippedLayers = 2;", nBinsChi2, chi2dofBins);
0945         hisKalmanChi2DofSkipLay0Unmatched_[fitName] = inputDir.make<TH1F>(
0946             addn("KalmanChi2DofSkipLay0Unmatched"), ";#chi^{2} for nSkippedLayers = 0;", nBinsChi2, chi2dofBins);
0947         hisKalmanChi2DofSkipLay1Unmatched_[fitName] = inputDir.make<TH1F>(
0948             addn("KalmanChi2DofSkipLay1Unmatched"), ";#chi^{2} for nSkippedLayers = 1;", nBinsChi2, chi2dofBins);
0949         hisKalmanChi2DofSkipLay2Unmatched_[fitName] = inputDir.make<TH1F>(
0950             addn("KalmanChi2DofSkipLay2Unmatched"), ";#chi^{2} for nSkippedLayers = 2;", nBinsChi2, chi2dofBins);
0951       }
0952 
0953       // Plots of helix param resolution.
0954 
0955       hisQoverPtResVsTrueEta_[fitName] = inputDir.make<TProfile>(
0956           addn("QoverPtResVsTrueEta"), "q/p_{T} resolution; |#eta|; q/p_{T} resolution", 30, 0.0, 3.0);
0957       hisPhi0ResVsTrueEta_[fitName] = inputDir.make<TProfile>(
0958           addn("PhiResVsTrueEta"), "#phi_{0} resolution; |#eta|; #phi_{0} resolution", 30, 0.0, 3.0);
0959       hisEtaResVsTrueEta_[fitName] =
0960           inputDir.make<TProfile>(addn("EtaResVsTrueEta"), "#eta resolution; |#eta|; #eta resolution", 30, 0.0, 3.0);
0961       hisZ0ResVsTrueEta_[fitName] =
0962           inputDir.make<TProfile>(addn("Z0ResVsTrueEta"), "z_{0} resolution; |#eta|; z_{0} resolution", 30, 0.0, 3.0);
0963       hisD0ResVsTrueEta_[fitName] =
0964           inputDir.make<TProfile>(addn("D0ResVsTrueEta"), "d_{0} resolution; |#eta|; d_{0} resolution", 30, 0.0, 3.0);
0965 
0966       hisQoverPtResVsTrueInvPt_[fitName] = inputDir.make<TProfile>(
0967           addn("QoverPtResVsTrueInvPt"), "q/p_{T} resolution; 1/p_{T}; q/p_{T} resolution", 25, 0.0, 0.5);
0968       hisPhi0ResVsTrueInvPt_[fitName] = inputDir.make<TProfile>(
0969           addn("PhiResVsTrueInvPt"), "#phi_{0} resolution; 1/p_{T}; #phi_{0} resolution", 25, 0.0, 0.5);
0970       hisEtaResVsTrueInvPt_[fitName] =
0971           inputDir.make<TProfile>(addn("EtaResVsTrueInvPt"), "#eta resolution; 1/p_{T}; #eta resolution", 25, 0.0, 0.5);
0972       hisZ0ResVsTrueInvPt_[fitName] = inputDir.make<TProfile>(
0973           addn("Z0ResVsTrueInvPt"), "z_{0} resolution; 1/p_{T}; z_{0} resolution", 25, 0.0, 0.5);
0974       hisD0ResVsTrueInvPt_[fitName] = inputDir.make<TProfile>(
0975           addn("D0ResVsTrueInvPt"), "d_{0} resolution; 1/p_{T}; d_{0} resolution", 25, 0.0, 0.5);
0976 
0977       // Duplicate track histos.
0978       profDupFitTrksVsEta_[fitName] =
0979           inputDir.make<TProfile>(addn("DupFitTrksVsEta"), "; #eta; No. of duplicate tracks per TP", 12, 0., 3.);
0980       profDupFitTrksVsInvPt_[fitName] =
0981           inputDir.make<TProfile>(addn("DupFitTrksVsInvPt"), "; 1/Pt; No. of duplicate tracks per TP", 25, 0., 0.5);
0982 
0983       // Histos for tracking efficiency vs. TP kinematics. (Binning must match similar histos in bookTrackCands()).
0984       hisFitTPinvptForEff_[fitName] =
0985           inputDir.make<TH1F>(addn("FitTPinvptForEff"), "; TP 1/Pt of fitted tracks (for effi.);", 50, 0., 0.5);
0986       hisFitTPetaForEff_[fitName] =
0987           inputDir.make<TH1F>(addn("FitTPetaForEff"), "; TP #eta of fitted tracks (for effi.);", 20, -3., 3.);
0988       hisFitTPphiForEff_[fitName] =
0989           inputDir.make<TH1F>(addn("FitTPphiForEff"), "; TP #phi of fitted tracks (for effi.);", 20, -M_PI, M_PI);
0990 
0991       // Histo for efficiency to reconstruct track perfectly (no incorrect hits). (Binning must match similar histos in bookTrackCands()).
0992       hisPerfFitTPinvptForEff_[fitName] = inputDir.make<TH1F>(
0993           addn("PerfFitTPinvptForEff"), "; TP 1/Pt of fitted tracks (for perf. effi.);", 50, 0., 0.5);
0994       hisPerfFitTPetaForEff_[fitName] = inputDir.make<TH1F>(
0995           addn("PerfFitTPetaForEff"), "; TP #eta of fitted tracks (for perfect effi.);", 20, -3., 3.);
0996 
0997       // Histos for tracking efficiency vs. TP production point. (Binning must match similar histos in bookTrackCands()).
0998       hisFitTPd0ForEff_[fitName] =
0999           inputDir.make<TH1F>(addn("FitTPd0ForEff"), "; TP d0 of fitted tracks (for effi.);", 40, 0., 4.);
1000       hisFitTPz0ForEff_[fitName] =
1001           inputDir.make<TH1F>(addn("FitTPz0ForEff"), "; TP z0 of fitted tracks (for effi.);", 50, 0., 25.);
1002 
1003       // Histos for algorithmic tracking efficiency vs. TP kinematics. (Binning must match similar histos in bookTrackCands()).
1004       hisFitTPinvptForAlgEff_[fitName] =
1005           inputDir.make<TH1F>(addn("FitTPinvptForAlgEff"), "; TP 1/Pt of fitted tracks (for alg. effi.);", 50, 0., 0.5);
1006       hisFitTPetaForAlgEff_[fitName] =
1007           inputDir.make<TH1F>(addn("FitTPetaForAlgEff"), "; TP #eta of fitted tracks (for alg. effi.);", 20, -3., 3.);
1008       hisFitTPphiForAlgEff_[fitName] = inputDir.make<TH1F>(
1009           addn("FitTPphiForAlgEff"), "; TP #phi of fitted tracks (for alg. effi.);", 20, -M_PI, M_PI);
1010 
1011       // Histo for efficiency to reconstruct track perfectly (no incorrect hits). (Binning must match similar histos in bookTrackCands()).
1012       hisPerfFitTPinvptForAlgEff_[fitName] = inputDir.make<TH1F>(
1013           addn("PerfFitTPinvptForAlgEff"), "; TP 1/Pt of fitted tracks (for perf. alg. effi.);", 50, 0., 0.5);
1014       hisPerfFitTPetaForAlgEff_[fitName] =
1015           inputDir.make<TH1F>(addn("PerfFitTPetaForAlgEff"), "; TP #eta (for perf. alg. effi.);", 20, -3., 3.);
1016 
1017       // Histos for algorithmic tracking efficiency vs. TP production point. (Binning must match similar histos in bookTrackCands()).
1018       hisFitTPd0ForAlgEff_[fitName] =
1019           inputDir.make<TH1F>(addn("FitTPd0ForAlgEff"), "; TP d0 of fitted tracks (for alg. effi.);", 40, 0., 4.);
1020       hisFitTPz0ForAlgEff_[fitName] =
1021           inputDir.make<TH1F>(addn("FitTPz0ForAlgEff"), "; TP z0 of fitted tracks (for alg. effi.);", 50, 0., 25.);
1022     }
1023     return inputDirMap;
1024   }
1025 
1026   //=== Fill histograms for studying track fitting.
1027 
1028   void Histos::fillTrackFitting(const InputData& inputData,
1029                                 const map<string, list<const L1fittedTrack*>>& mapFinalTracks) {
1030     // Allow only one thread to run this function at a time
1031     static std::mutex myMutex;
1032     std::lock_guard<std::mutex> myGuard(myMutex);
1033 
1034     const list<TP>& vTPs = inputData.getTPs();
1035 
1036     // Loop over all the fitting algorithms we are trying.
1037     for (const string& fitName : trackFitters_) {
1038       const list<const L1fittedTrack*>& fittedTracks = mapFinalTracks.at(fitName);  // Get fitted tracks.
1039 
1040       // Count tracks
1041       unsigned int nFitTracks = 0;
1042       unsigned int nFitsMatchingTP = 0;
1043 
1044       const unsigned int numPhiNonants = settings_->numPhiNonants();
1045       vector<unsigned int> nFitTracksPerNonant(numPhiNonants, 0);
1046 
1047       for (const L1fittedTrack* fitTrk : fittedTracks) {
1048         nFitTracks++;
1049 
1050         // Get matched truth particle, if any.
1051         const TP* tp = fitTrk->matchedTP();
1052         if (tp != nullptr)
1053           nFitsMatchingTP++;
1054         // Count fitted tracks per nonant.
1055         unsigned int iNonant = (numPhiSectors_ > 0) ? floor(fitTrk->iPhiSec() * numPhiNonants / (numPhiSectors_))
1056                                                     : 0;  // phi nonant number
1057         nFitTracksPerNonant[iNonant]++;
1058       }
1059 
1060       profNumFitTracks_[fitName]->Fill(1, nFitTracks);
1061       profNumFitTracks_[fitName]->Fill(2, nFitsMatchingTP);
1062 
1063       hisNumFitTrks_[fitName]->Fill(nFitTracks);
1064       for (const unsigned int& num : nFitTracksPerNonant) {
1065         hisNumFitTrksPerNon_[fitName]->Fill(num);
1066       }
1067 
1068       // Count stubs assigned to fitted tracks.
1069       unsigned int nTotStubs = 0;
1070       for (const L1fittedTrack* fitTrk : fittedTracks) {
1071         unsigned int nStubs = fitTrk->numStubs();
1072         hisStubsPerFitTrack_[fitName]->Fill(nStubs);
1073         nTotStubs += nStubs;
1074       }
1075       profStubsOnFitTracks_[fitName]->Fill(1., nTotStubs);
1076 
1077       // Note truth particles that are successfully fitted. And which give rise to duplicate tracks.
1078 
1079       map<const TP*, bool> tpRecoedMap;  // Note which truth particles were successfully fitted.
1080       map<const TP*, bool>
1081           tpPerfRecoedMap;  // Note which truth particles were successfully fitted with no incorrect hits.
1082       map<const TP*, unsigned int> tpRecoedDup;  // Note that this TP gave rise to duplicate tracks.
1083       for (const TP& tp : vTPs) {
1084         tpRecoedMap[&tp] = false;
1085         tpPerfRecoedMap[&tp] = false;
1086         unsigned int nMatch = 0;
1087         for (const L1fittedTrack* fitTrk : fittedTracks) {
1088           const TP* assocTP = fitTrk->matchedTP();  // Get the TP the fitted track matches to, if any.
1089           if (assocTP == &tp) {
1090             tpRecoedMap[&tp] = true;
1091             if (fitTrk->purity() == 1.)
1092               tpPerfRecoedMap[&tp] = true;
1093             nMatch++;
1094           }
1095         }
1096         tpRecoedDup[&tp] = nMatch;
1097       }
1098 
1099       // Count truth particles that are successfully fitted.
1100 
1101       unsigned int nFittedTPs = 0;
1102       unsigned int nFittedTPsForEff = 0;
1103       for (const TP& tp : vTPs) {
1104         if (tpRecoedMap[&tp]) {  // Was this truth particle successfully fitted?
1105           nFittedTPs++;
1106           if (tp.useForEff())
1107             nFittedTPsForEff++;
1108         }
1109       }
1110 
1111       profNumFitTracks_[fitName]->Fill(6, nFittedTPs);
1112       profNumFitTracks_[fitName]->Fill(7, nFittedTPsForEff);
1113 
1114       // Loop over fitted tracks again.
1115 
1116       for (const L1fittedTrack* fitTrk : fittedTracks) {
1117         // Info for specific track fit algorithms.
1118         unsigned int nSkippedLayers = 0;
1119         unsigned int numUpdateCalls = 0;
1120         if (fitName.find("KF") != string::npos) {
1121           fitTrk->infoKF(nSkippedLayers, numUpdateCalls);
1122           hisKalmanNumUpdateCalls_[fitName]->Fill(numUpdateCalls);
1123         }
1124 
1125         //--- Compare fitted tracks that match truth particles to those that don't.
1126 
1127         // Get matched truth particle, if any.
1128         const TP* tp = fitTrk->matchedTP();
1129 
1130         if (tp != nullptr) {
1131           hisFitQinvPtMatched_[fitName]->Fill(fitTrk->qOverPt());
1132           hisFitPhi0Matched_[fitName]->Fill(fitTrk->phi0());
1133           hisFitD0Matched_[fitName]->Fill(fitTrk->d0());
1134           hisFitZ0Matched_[fitName]->Fill(fitTrk->z0());
1135           hisFitEtaMatched_[fitName]->Fill(fitTrk->eta());
1136 
1137           // Only plot matched chi2 for tracks with no incorrect stubs.
1138           if (fitTrk->purity() == 1.) {
1139             hisFitChi2DofRphiMatched_[fitName]->Fill(fitTrk->chi2rphi() / fitTrk->numDOFrphi());
1140             hisFitChi2DofRzMatched_[fitName]->Fill(fitTrk->chi2rz() / fitTrk->numDOFrz());
1141             profFitChi2DofRphiVsInvPtMatched_[fitName]->Fill(std::abs(fitTrk->qOverPt()),
1142                                                              (fitTrk->chi2rphi() / fitTrk->numDOFrphi()));
1143 
1144             if (fitName.find("KF") != string::npos) {
1145               // No. of skipped layers on track during Kalman track fit.
1146               if (nSkippedLayers == 0) {
1147                 hisKalmanChi2DofSkipLay0Matched_[fitName]->Fill(fitTrk->chi2dof());
1148               } else if (nSkippedLayers == 1) {
1149                 hisKalmanChi2DofSkipLay1Matched_[fitName]->Fill(fitTrk->chi2dof());
1150               } else if (nSkippedLayers >= 2) {
1151                 hisKalmanChi2DofSkipLay2Matched_[fitName]->Fill(fitTrk->chi2dof());
1152               }
1153             }
1154           }
1155 
1156         } else {
1157           hisFitQinvPtUnmatched_[fitName]->Fill(fitTrk->qOverPt());
1158           hisFitPhi0Unmatched_[fitName]->Fill(fitTrk->phi0());
1159           hisFitD0Unmatched_[fitName]->Fill(fitTrk->d0());
1160           hisFitZ0Unmatched_[fitName]->Fill(fitTrk->z0());
1161           hisFitEtaUnmatched_[fitName]->Fill(fitTrk->eta());
1162 
1163           hisFitChi2DofRphiUnmatched_[fitName]->Fill(fitTrk->chi2rphi() / fitTrk->numDOFrphi());
1164           hisFitChi2DofRzUnmatched_[fitName]->Fill(fitTrk->chi2rz() / fitTrk->numDOFrz());
1165           profFitChi2DofRphiVsInvPtUnmatched_[fitName]->Fill(std::abs(fitTrk->qOverPt()),
1166                                                              (fitTrk->chi2rphi() / fitTrk->numDOFrphi()));
1167 
1168           if (fitName.find("KF") != string::npos) {
1169             // No. of skipped layers on track during Kalman track fit.
1170             if (nSkippedLayers == 0) {
1171               hisKalmanChi2DofSkipLay0Unmatched_[fitName]->Fill(fitTrk->chi2dof());
1172             } else if (nSkippedLayers == 1) {
1173               hisKalmanChi2DofSkipLay1Unmatched_[fitName]->Fill(fitTrk->chi2dof());
1174             } else if (nSkippedLayers >= 2) {
1175               hisKalmanChi2DofSkipLay2Unmatched_[fitName]->Fill(fitTrk->chi2dof());
1176             }
1177           }
1178         }
1179       }
1180 
1181       // Study helix param resolution.
1182 
1183       for (const L1fittedTrack* fitTrk : fittedTracks) {
1184         const TP* tp = fitTrk->matchedTP();
1185         if (tp != nullptr) {
1186           // IRT
1187           if ((resPlotOpt_ && tp->useForAlgEff()) ||
1188               (not resPlotOpt_)) {  // Check TP is good for efficiency measurement (& also comes from signal event if requested)
1189 
1190             // Plot helix parameter resolution against eta or Pt.
1191             hisQoverPtResVsTrueEta_[fitName]->Fill(std::abs(tp->eta()), std::abs(fitTrk->qOverPt() - tp->qOverPt()));
1192             hisPhi0ResVsTrueEta_[fitName]->Fill(std::abs(tp->eta()),
1193                                                 std::abs(reco::deltaPhi(fitTrk->phi0(), tp->phi0())));
1194             hisEtaResVsTrueEta_[fitName]->Fill(std::abs(tp->eta()), std::abs(fitTrk->eta() - tp->eta()));
1195             hisZ0ResVsTrueEta_[fitName]->Fill(std::abs(tp->eta()), std::abs(fitTrk->z0() - tp->z0()));
1196             hisD0ResVsTrueEta_[fitName]->Fill(std::abs(tp->eta()), std::abs(fitTrk->d0() - tp->d0()));
1197 
1198             hisQoverPtResVsTrueInvPt_[fitName]->Fill(std::abs(tp->qOverPt()),
1199                                                      std::abs(fitTrk->qOverPt() - tp->qOverPt()));
1200             hisPhi0ResVsTrueInvPt_[fitName]->Fill(std::abs(tp->qOverPt()),
1201                                                   std::abs(reco::deltaPhi(fitTrk->phi0(), tp->phi0())));
1202             hisEtaResVsTrueInvPt_[fitName]->Fill(std::abs(tp->qOverPt()), std::abs(fitTrk->eta() - tp->eta()));
1203             hisZ0ResVsTrueInvPt_[fitName]->Fill(std::abs(tp->qOverPt()), std::abs(fitTrk->z0() - tp->z0()));
1204             hisD0ResVsTrueInvPt_[fitName]->Fill(std::abs(tp->qOverPt()), std::abs(fitTrk->d0() - tp->d0()));
1205           }
1206         }
1207       }
1208 
1209       //=== Study duplicate tracks.
1210 
1211       for (const TP& tp : vTPs) {
1212         if (tpRecoedMap[&tp]) {  // Was this truth particle successfully fitted?
1213           profDupFitTrksVsEta_[fitName]->Fill(std::abs(tp.eta()), tpRecoedDup[&tp] - 1);
1214           profDupFitTrksVsInvPt_[fitName]->Fill(std::abs(tp.qOverPt()), tpRecoedDup[&tp] - 1);
1215         }
1216       }
1217 
1218       //=== Study tracking efficiency by looping over tracking particles.
1219 
1220       for (const TP& tp : vTPs) {
1221         if (tp.useForEff()) {  // Check TP is good for efficiency measurement.
1222 
1223           // If TP was reconstucted by HT, then plot its kinematics.
1224           if (tpRecoedMap[&tp]) {  // This truth particle was successfully fitted.
1225             hisFitTPinvptForEff_[fitName]->Fill(1. / tp.pt());
1226             hisFitTPetaForEff_[fitName]->Fill(tp.eta());
1227             hisFitTPphiForEff_[fitName]->Fill(tp.phi0());
1228             // Plot also production point of all good reconstructed TP.
1229             hisFitTPd0ForEff_[fitName]->Fill(std::abs(tp.d0()));
1230             hisFitTPz0ForEff_[fitName]->Fill(std::abs(tp.z0()));
1231             // Also plot efficiency to perfectly reconstruct the track (no fake hits)
1232             if (tpPerfRecoedMap[&tp]) {  // This truth particle was successfully fitted with no incorrect hits.
1233               hisPerfFitTPinvptForEff_[fitName]->Fill(1. / tp.pt());
1234               hisPerfFitTPetaForEff_[fitName]->Fill(tp.eta());
1235             }
1236             if (tp.useForAlgEff()) {  // Check TP is good for algorithmic efficiency measurement.
1237               hisFitTPinvptForAlgEff_[fitName]->Fill(1. / tp.pt());
1238               hisFitTPetaForAlgEff_[fitName]->Fill(tp.eta());
1239               hisFitTPphiForAlgEff_[fitName]->Fill(tp.phi0());
1240               // Plot also production point of all good reconstructed TP.
1241               hisFitTPd0ForAlgEff_[fitName]->Fill(std::abs(tp.d0()));
1242               hisFitTPz0ForAlgEff_[fitName]->Fill(std::abs(tp.z0()));
1243               // Also plot efficiency to perfectly reconstruct the track (no fake hits)
1244               if (tpPerfRecoedMap[&tp]) {
1245                 hisPerfFitTPinvptForAlgEff_[fitName]->Fill(1. / tp.pt());
1246                 hisPerfFitTPetaForAlgEff_[fitName]->Fill(tp.eta());
1247               }
1248             }
1249           }
1250         }
1251       }
1252     }
1253   }
1254 
1255   //=== Produce plots of tracking efficiency after HT or after r-z track filter (run at end of job).
1256 
1257   TFileDirectory Histos::plotTrackEfficiency(const string& tName) {
1258     // Define lambda function to facilitate adding "tName" to directory & histogram names.
1259     auto addn = [tName](const string& s) { return TString::Format("%s_%s", s.c_str(), tName.c_str()); };
1260 
1261     TFileDirectory inputDir = fs_->mkdir(addn("Effi").Data());
1262     // Plot tracking efficiency
1263     makeEfficiencyPlot(inputDir,
1264                        teffEffVsInvPt_[tName],
1265                        hisRecoTPinvptForEff_[tName],
1266                        hisTPinvptForEff_,
1267                        addn("EffVsInvPt"),
1268                        "; 1/Pt; Tracking efficiency");
1269     makeEfficiencyPlot(inputDir,
1270                        teffEffVsEta_[tName],
1271                        hisRecoTPetaForEff_[tName],
1272                        hisTPetaForEff_,
1273                        addn("EffVsEta"),
1274                        "; #eta; Tracking efficiency");
1275 
1276     makeEfficiencyPlot(inputDir,
1277                        teffEffVsPhi_[tName],
1278                        hisRecoTPphiForEff_[tName],
1279                        hisTPphiForEff_,
1280                        addn("EffVsPhi"),
1281                        "; #phi; Tracking efficiency");
1282 
1283     makeEfficiencyPlot(inputDir,
1284                        teffEffVsD0_[tName],
1285                        hisRecoTPd0ForEff_[tName],
1286                        hisTPd0ForEff_,
1287                        addn("EffVsD0"),
1288                        "; d0 (cm); Tracking efficiency");
1289     makeEfficiencyPlot(inputDir,
1290                        teffEffVsZ0_[tName],
1291                        hisRecoTPz0ForEff_[tName],
1292                        hisTPz0ForEff_,
1293                        addn("EffVsZ0"),
1294                        "; z0 (cm); Tracking efficiency");
1295 
1296     // Also plot efficiency to reconstruct track perfectly.
1297     makeEfficiencyPlot(inputDir,
1298                        teffPerfEffVsInvPt_[tName],
1299                        hisPerfRecoTPinvptForEff_[tName],
1300                        hisTPinvptForEff_,
1301                        addn("PerfEffVsInvPt"),
1302                        "; 1/Pt; Tracking perfect efficiency");
1303     makeEfficiencyPlot(inputDir,
1304                        teffPerfEffVsEta_[tName],
1305                        hisPerfRecoTPetaForEff_[tName],
1306                        hisTPetaForEff_,
1307                        addn("PerfEffVsEta"),
1308                        "; #eta; Tracking perfect efficiency");
1309 
1310     // Plot algorithmic tracking efficiency
1311     makeEfficiencyPlot(inputDir,
1312                        teffAlgEffVsInvPt_[tName],
1313                        hisRecoTPinvptForAlgEff_[tName],
1314                        hisTPinvptForAlgEff_,
1315                        addn("AlgEffVsInvPt"),
1316                        "; 1/Pt; Tracking efficiency");
1317     makeEfficiencyPlot(inputDir,
1318                        teffAlgEffVsEta_[tName],
1319                        hisRecoTPetaForAlgEff_[tName],
1320                        hisTPetaForAlgEff_,
1321                        addn("AlgEffVsEta"),
1322                        "; #eta; Tracking efficiency");
1323     makeEfficiencyPlot(inputDir,
1324                        teffAlgEffVsPhi_[tName],
1325                        hisRecoTPphiForAlgEff_[tName],
1326                        hisTPphiForAlgEff_,
1327                        addn("AlgEffVsPhi"),
1328                        "; #phi; Tracking efficiency");
1329 
1330     makeEfficiencyPlot(inputDir,
1331                        teffAlgEffVsD0_[tName],
1332                        hisRecoTPd0ForAlgEff_[tName],
1333                        hisTPd0ForAlgEff_,
1334                        addn("AlgEffVsD0"),
1335                        "; d0 (cm); Tracking efficiency");
1336     makeEfficiencyPlot(inputDir,
1337                        teffAlgEffVsZ0_[tName],
1338                        hisRecoTPz0ForAlgEff_[tName],
1339                        hisTPz0ForAlgEff_,
1340                        addn("AlgEffVsZ0"),
1341                        "; z0 (cm); Tracking efficiency");
1342 
1343     // Also plot algorithmic efficiency to reconstruct track perfectly.
1344     makeEfficiencyPlot(inputDir,
1345                        teffPerfAlgEffVsInvPt_[tName],
1346                        hisPerfRecoTPinvptForAlgEff_[tName],
1347                        hisTPinvptForAlgEff_,
1348                        addn("PerfAlgEffVsInvPt"),
1349                        "; 1/Pt; Tracking perfect efficiency");
1350     makeEfficiencyPlot(inputDir,
1351                        teffPerfAlgEffVsEta_[tName],
1352                        hisPerfRecoTPetaForAlgEff_[tName],
1353                        hisTPetaForAlgEff_,
1354                        addn("PerfAlgEffVsEta"),
1355                        "; #eta; Tracking perfect efficiency");
1356 
1357     return inputDir;
1358   }
1359 
1360   //=== Produce plots of tracking efficiency after track fit (run at end of job).
1361 
1362   TFileDirectory Histos::plotTrackEffAfterFit(const string& fitName) {
1363     // Define lambda function to facilitate adding "fitName" to directory & histogram names.
1364     auto addn = [fitName](const string& s) { return TString::Format("%s_%s", s.c_str(), fitName.c_str()); };
1365 
1366     TFileDirectory inputDir = fs_->mkdir(addn("Effi").Data());
1367     // Plot tracking efficiency
1368     makeEfficiencyPlot(inputDir,
1369                        teffEffFitVsInvPt_[fitName],
1370                        hisFitTPinvptForEff_[fitName],
1371                        hisTPinvptForEff_,
1372                        addn("EffFitVsInvPt"),
1373                        "; 1/Pt; Tracking efficiency");
1374     makeEfficiencyPlot(inputDir,
1375                        teffEffFitVsEta_[fitName],
1376                        hisFitTPetaForEff_[fitName],
1377                        hisTPetaForEff_,
1378                        addn("EffFitVsEta"),
1379                        "; #eta; Tracking efficiency");
1380     makeEfficiencyPlot(inputDir,
1381                        teffEffFitVsPhi_[fitName],
1382                        hisFitTPphiForEff_[fitName],
1383                        hisTPphiForEff_,
1384                        addn("EffFitVsPhi"),
1385                        "; #phi; Tracking efficiency");
1386 
1387     makeEfficiencyPlot(inputDir,
1388                        teffEffFitVsD0_[fitName],
1389                        hisFitTPd0ForEff_[fitName],
1390                        hisTPd0ForEff_,
1391                        addn("EffFitVsD0"),
1392                        "; d0 (cm); Tracking efficiency");
1393     makeEfficiencyPlot(inputDir,
1394                        teffEffFitVsZ0_[fitName],
1395                        hisFitTPz0ForEff_[fitName],
1396                        hisTPz0ForEff_,
1397                        addn("EffFitVsZ0"),
1398                        "; z0 (cm); Tracking efficiency");
1399 
1400     // Also plot efficiency to reconstruct track perfectly.
1401     makeEfficiencyPlot(inputDir,
1402                        teffPerfEffFitVsInvPt_[fitName],
1403                        hisPerfFitTPinvptForEff_[fitName],
1404                        hisTPinvptForEff_,
1405                        addn("PerfEffFitVsInvPt"),
1406                        "; 1/Pt; Tracking perfect efficiency");
1407     makeEfficiencyPlot(inputDir,
1408                        teffPerfEffFitVsEta_[fitName],
1409                        hisPerfFitTPetaForEff_[fitName],
1410                        hisTPetaForEff_,
1411                        addn("PerfEffFitVsEta"),
1412                        "; #eta; Tracking perfect efficiency");
1413 
1414     // Plot algorithmic tracking efficiency
1415     makeEfficiencyPlot(inputDir,
1416                        teffAlgEffFitVsInvPt_[fitName],
1417                        hisFitTPinvptForAlgEff_[fitName],
1418                        hisTPinvptForAlgEff_,
1419                        addn("AlgEffFitVsInvPt"),
1420                        "; 1/Pt; Tracking efficiency");
1421     makeEfficiencyPlot(inputDir,
1422                        teffAlgEffFitVsEta_[fitName],
1423                        hisFitTPetaForAlgEff_[fitName],
1424                        hisTPetaForAlgEff_,
1425                        addn("AlgEffFitVsEta"),
1426                        "; #eta; Tracking efficiency");
1427     makeEfficiencyPlot(inputDir,
1428                        teffAlgEffFitVsPhi_[fitName],
1429                        hisFitTPphiForAlgEff_[fitName],
1430                        hisTPphiForAlgEff_,
1431                        addn("AlgEffFitVsPhi"),
1432                        "; #phi; Tracking efficiency");
1433 
1434     makeEfficiencyPlot(inputDir,
1435                        teffAlgEffFitVsD0_[fitName],
1436                        hisFitTPd0ForAlgEff_[fitName],
1437                        hisTPd0ForAlgEff_,
1438                        addn("AlgEffFitVsD0"),
1439                        "; d0 (cm); Tracking efficiency");
1440     makeEfficiencyPlot(inputDir,
1441                        teffAlgEffFitVsZ0_[fitName],
1442                        hisFitTPz0ForAlgEff_[fitName],
1443                        hisTPz0ForAlgEff_,
1444                        addn("AlgEffFitVsZ0"),
1445                        "; z0 (cm); Tracking efficiency");
1446 
1447     // Also plot algorithmic efficiency to reconstruct track perfectly.
1448     makeEfficiencyPlot(inputDir,
1449                        teffPerfAlgEffFitVsInvPt_[fitName],
1450                        hisPerfFitTPinvptForAlgEff_[fitName],
1451                        hisTPinvptForAlgEff_,
1452                        addn("PerfAlgEffFitVsInvPt"),
1453                        "; 1/Pt; Tracking perfect efficiency");
1454     makeEfficiencyPlot(inputDir,
1455                        teffPerfAlgEffFitVsEta_[fitName],
1456                        hisPerfFitTPetaForAlgEff_[fitName],
1457                        hisTPetaForAlgEff_,
1458                        addn("Perf AlgEffFitVsEta"),
1459                        "; #eta; Tracking perfect efficiency");
1460     return inputDir;
1461   }
1462 
1463   void Histos::makeEfficiencyPlot(
1464       TFileDirectory& inputDir, TEfficiency* outputEfficiency, TH1F* pass, TH1F* all, TString name, TString title) {
1465     outputEfficiency = inputDir.make<TEfficiency>(*pass, *all);
1466     outputEfficiency->SetName(name);
1467     outputEfficiency->SetTitle(title);
1468   }
1469 
1470   //=== Print summary of track-finding performance after track pattern reco.
1471 
1472   void Histos::printTrackPerformance(const string& tName) {
1473     float numTrackCands = profNumTrackCands_[tName]->GetBinContent(1);   // No. of track cands
1474     float numTrackCandsErr = profNumTrackCands_[tName]->GetBinError(1);  // No. of track cands uncertainty
1475     float numMatchedTrackCandsIncDups =
1476         profNumTrackCands_[tName]->GetBinContent(2);  // Ditto, counting only those matched to TP
1477     float numMatchedTrackCandsExcDups = profNumTrackCands_[tName]->GetBinContent(6);  // Ditto, but excluding duplicates
1478     float numFakeTracks = numTrackCands - numMatchedTrackCandsIncDups;
1479     float numExtraDupTracks = numMatchedTrackCandsIncDups - numMatchedTrackCandsExcDups;
1480     float fracFake = numFakeTracks / (numTrackCands + 1.0e-6);
1481     float fracDup = numExtraDupTracks / (numTrackCands + 1.0e-6);
1482 
1483     float numStubsOnTracks = profStubsOnTracks_[tName]->GetBinContent(1);
1484     float meanStubsPerTrack =
1485         numStubsOnTracks / (numTrackCands + 1.0e-6);  //protection against demoninator equals zero.
1486     unsigned int numRecoTPforAlg = hisRecoTPinvptForAlgEff_[tName]->GetEntries();
1487     // Histograms of input truth particles (e.g. hisTPinvptForAlgEff_), used for denominator of efficiencies, are identical,
1488     // irrespective of whether made after HT or after r-z track filter, so always use the former.
1489     unsigned int numTPforAlg = hisTPinvptForAlgEff_->GetEntries();
1490     unsigned int numPerfRecoTPforAlg = hisPerfRecoTPinvptForAlgEff_[tName]->GetEntries();
1491     float algEff = float(numRecoTPforAlg) / (numTPforAlg + 1.0e-6);  //protection against demoninator equals zero.
1492     float algEffErr = sqrt(algEff * (1 - algEff) / (numTPforAlg + 1.0e-6));  // uncertainty
1493     float algPerfEff =
1494         float(numPerfRecoTPforAlg) / (numTPforAlg + 1.0e-6);  //protection against demoninator equals zero.
1495     float algPerfEffErr = sqrt(algPerfEff * (1 - algPerfEff) / (numTPforAlg + 1.0e-6));  // uncertainty
1496 
1497     PrintL1trk() << "=========================================================================";
1498     if (tName == "HT") {
1499       PrintL1trk() << "               TRACK-FINDING SUMMARY AFTER HOUGH TRANSFORM             ";
1500     } else if (tName == "RZ") {
1501       PrintL1trk() << "               TRACK-FINDING SUMMARY AFTER R-Z TRACK FILTER            ";
1502     } else if (tName == "TRACKLET") {
1503       PrintL1trk() << "               TRACK-FINDING SUMMARY AFTER TRACKLET PATTERN RECO       ";
1504     }
1505     PrintL1trk() << "Number of track candidates found per event = " << numTrackCands << " +- " << numTrackCandsErr;
1506     PrintL1trk() << "                     with mean stubs/track = " << meanStubsPerTrack;
1507     PrintL1trk() << "Fraction of track cands that are fake = " << fracFake;
1508     PrintL1trk() << "Fraction of track cands that are genuine, but extra duplicates = " << fracDup;
1509 
1510     PrintL1trk() << std::fixed << std::setprecision(4) << "Algorithmic tracking efficiency = " << numRecoTPforAlg << "/"
1511                  << numTPforAlg << " = " << algEff << " +- " << algEffErr;
1512     PrintL1trk() << "Perfect algorithmic tracking efficiency = " << numPerfRecoTPforAlg << "/" << numTPforAlg << " = "
1513                  << algPerfEff << " +- " << algPerfEffErr << " (no incorrect hits)";
1514   }
1515 
1516   //=== Print summary of track-finding performance after helix fit for given track fitter.
1517 
1518   void Histos::printFitTrackPerformance(const string& fitName) {
1519     float numFitTracks = profNumFitTracks_[fitName]->GetBinContent(1);   // No. of track cands
1520     float numFitTracksErr = profNumFitTracks_[fitName]->GetBinError(1);  // No. of track cands uncertainty
1521     float numMatchedFitTracksIncDups =
1522         profNumFitTracks_[fitName]->GetBinContent(2);  // Ditto, counting only those matched to TP
1523     float numMatchedFitTracksExcDups = profNumFitTracks_[fitName]->GetBinContent(6);  // Ditto, but excluding duplicates
1524     float numFakeFitTracks = numFitTracks - numMatchedFitTracksIncDups;
1525     float numExtraDupFitTracks = numMatchedFitTracksIncDups - numMatchedFitTracksExcDups;
1526     float fracFakeFit = numFakeFitTracks / (numFitTracks + 1.0e-6);
1527     float fracDupFit = numExtraDupFitTracks / (numFitTracks + 1.0e-6);
1528 
1529     float numStubsOnFitTracks = profStubsOnFitTracks_[fitName]->GetBinContent(1);
1530     float meanStubsPerFitTrack =
1531         numStubsOnFitTracks / (numFitTracks + 1.0e-6);  //protection against demoninator equals zero.
1532     unsigned int numFitTPforAlg = hisFitTPinvptForAlgEff_[fitName]->GetEntries();
1533     // Histograms of input truth particles (e.g. hisTPinvptForAlgEff_), used for denominator of efficiencies, are identical,
1534     // irrespective of whether made after HT or after r-z track filter, so always use the former.
1535     unsigned int numTPforAlg = hisTPinvptForAlgEff_->GetEntries();
1536     unsigned int numPerfFitTPforAlg = hisPerfFitTPinvptForAlgEff_[fitName]->GetEntries();
1537     float fitEff = float(numFitTPforAlg) / (numTPforAlg + 1.0e-6);  //protection against demoninator equals zero.
1538     float fitEffErr = sqrt(fitEff * (1 - fitEff) / (numTPforAlg + 1.0e-6));  // uncertainty
1539     float fitPerfEff =
1540         float(numPerfFitTPforAlg) / (numTPforAlg + 1.0e-6);  //protection against demoninator equals zero.
1541     float fitPerfEffErr = sqrt(fitPerfEff * (1 - fitPerfEff) / (numTPforAlg + 1.0e-6));  // uncertainty
1542 
1543     // Does this fitter require r-z track filter to be run before it?
1544     bool useRZfilt = (std::count(useRZfilter_.begin(), useRZfilter_.end(), fitName) > 0);
1545 
1546     PrintL1trk() << "=========================================================================";
1547     PrintL1trk() << "                    TRACK FIT SUMMARY FOR: " << fitName;
1548     PrintL1trk() << "Number of fitted track candidates found per event = " << numFitTracks << " +- " << numFitTracksErr;
1549     PrintL1trk() << "                     with mean stubs/track = " << meanStubsPerFitTrack;
1550     PrintL1trk() << "Fraction of fitted tracks that are fake = " << fracFakeFit;
1551     PrintL1trk() << "Fraction of fitted tracks that are genuine, but extra duplicates = " << fracDupFit;
1552     PrintL1trk() << "Algorithmic fitting efficiency = " << numFitTPforAlg << "/" << numTPforAlg << " = " << fitEff
1553                  << " +- " << fitEffErr;
1554     PrintL1trk() << "Perfect algorithmic fitting efficiency = " << numPerfFitTPforAlg << "/" << numTPforAlg << " = "
1555                  << fitPerfEff << " +- " << fitPerfEffErr << " (no incorrect hits)";
1556     if (useRZfilt)
1557       PrintL1trk() << "(The above fitter used the '" << settings_->rzFilterName() << "' r-z track filter.)";
1558   }
1559 
1560   //=== Print tracking performance summary & make tracking efficiency histograms.
1561 
1562   void Histos::endJobAnalysis(const HTrphi::ErrorMonitor* htRphiErrMon) {
1563     // Don't bother producing summary if user didn't request histograms via TFileService in their cfg.
1564     if (not this->enabled())
1565       return;
1566 
1567     // Protection when running in wierd mixed hybrid-TMTT modes.
1568     bool wierdMixedMode = (hisRecoTPinvptForEff_.find("TRACKLET") == hisRecoTPinvptForEff_.end());
1569 
1570     if (settings_->hybrid() && not wierdMixedMode) {
1571       // Produce plots of tracking efficieny after tracklet pattern reco.
1572       this->plotTrackletSeedEfficiency();
1573       this->plotTrackEfficiency("TRACKLET");
1574       this->plotHybridDupRemovalEfficiency();
1575 
1576     } else {
1577       // Produce plots of tracking efficiency using track candidates found after HT.
1578       this->plotTrackEfficiency("HT");
1579 
1580       // Optionally produce plots of tracking efficiency using track candidates found after r-z track filter.
1581       if (ranRZfilter_)
1582         this->plotTrackEfficiency("RZ");
1583     }
1584 
1585     // Produce more plots of tracking efficiency using track candidates after track fit.
1586     for (auto& fitName : trackFitters_) {
1587       this->plotTrackEffAfterFit(fitName);
1588     }
1589 
1590     PrintL1trk() << "=========================================================================";
1591 
1592     // Print r (z) range in which each barrel layer (endcap wheel) appears.
1593     // (Needed by firmware).
1594     PrintL1trk();
1595     PrintL1trk() << "--- r range in which stubs in each barrel layer appear ---";
1596     for (const auto& p : mapBarrelLayerMinR_) {
1597       unsigned int layer = p.first;
1598       PrintL1trk() << "   layer = " << layer << " : " << mapBarrelLayerMinR_[layer] << " < r < "
1599                    << mapBarrelLayerMaxR_[layer];
1600     }
1601     PrintL1trk() << "--- |z| range in which stubs in each endcap wheel appear ---";
1602     for (const auto& p : mapEndcapWheelMinZ_) {
1603       unsigned int layer = p.first;
1604       PrintL1trk() << "   wheel = " << layer << " : " << mapEndcapWheelMinZ_[layer] << " < |z| < "
1605                    << mapEndcapWheelMaxZ_[layer];
1606     }
1607 
1608     // Print (r,|z|) range in which each module type (defined in DigitalStub) appears.
1609     // (Needed by firmware).
1610     PrintL1trk();
1611     PrintL1trk() << "--- (r,|z|) range in which each module type (defined in DigitalStub) appears ---";
1612     for (const auto& p : mapModuleTypeMinR_) {
1613       unsigned int modType = p.first;
1614       PrintL1trk() << "   Module type = " << modType << setprecision(1) << " : r range = ("
1615                    << mapModuleTypeMinR_[modType] << "," << mapModuleTypeMaxR_[modType] << "); z range = ("
1616                    << mapModuleTypeMinZ_[modType] << "," << mapModuleTypeMaxZ_[modType] << ")";
1617     }
1618     // Ugly bodge to allow for modules in barrel layers 1-2 & endcap wheels 3-5 being different.
1619     PrintL1trk() << "and in addition";
1620     for (const auto& p : mapExtraAModuleTypeMinR_) {
1621       unsigned int modType = p.first;
1622       PrintL1trk() << "   Module type = " << modType << setprecision(1) << " : r range = ("
1623                    << mapExtraAModuleTypeMinR_[modType] << "," << mapExtraAModuleTypeMaxR_[modType] << "); z range = ("
1624                    << mapExtraAModuleTypeMinZ_[modType] << "," << mapExtraAModuleTypeMaxZ_[modType] << ")";
1625     }
1626     PrintL1trk() << "and in addition";
1627     for (const auto& p : mapExtraBModuleTypeMinR_) {
1628       unsigned int modType = p.first;
1629       PrintL1trk() << "   Module type = " << modType << setprecision(1) << " : r range = ("
1630                    << mapExtraBModuleTypeMinR_[modType] << "," << mapExtraBModuleTypeMaxR_[modType] << "); z range = ("
1631                    << mapExtraBModuleTypeMinZ_[modType] << "," << mapExtraBModuleTypeMaxZ_[modType] << ")";
1632     }
1633     PrintL1trk() << "and in addition";
1634     for (const auto& p : mapExtraCModuleTypeMinR_) {
1635       unsigned int modType = p.first;
1636       PrintL1trk() << "   Module type = " << modType << setprecision(1) << " : r range = ("
1637                    << mapExtraCModuleTypeMinR_[modType] << "," << mapExtraCModuleTypeMaxR_[modType] << "); z range = ("
1638                    << mapExtraCModuleTypeMinZ_[modType] << "," << mapExtraCModuleTypeMaxZ_[modType] << ")";
1639     }
1640     PrintL1trk() << "and in addition";
1641     for (const auto& p : mapExtraDModuleTypeMinR_) {
1642       unsigned int modType = p.first;
1643       PrintL1trk() << "   Module type = " << modType << setprecision(1) << " : r range = ("
1644                    << mapExtraDModuleTypeMinR_[modType] << "," << mapExtraDModuleTypeMaxR_[modType] << "); z range = ("
1645                    << mapExtraDModuleTypeMinZ_[modType] << "," << mapExtraDModuleTypeMaxZ_[modType] << ")";
1646     }
1647     PrintL1trk();
1648 
1649     if (settings_->hybrid() && not wierdMixedMode) {
1650       //--- Print summary of tracklet pattern reco
1651       this->printTrackletSeedFindingPerformance();
1652       this->printTrackPerformance("TRACKLET");
1653       this->printHybridDupRemovalPerformance();
1654     } else {
1655       //--- Print summary of track-finding performance after HT
1656       this->printTrackPerformance("HT");
1657       //--- Optionally print summary of track-finding performance after r-z track filter.
1658       if (ranRZfilter_)
1659         this->printTrackPerformance("RZ");
1660     }
1661 
1662     //--- Print summary of track-finding performance after helix fit, for each track fitting algorithm used.
1663     for (const string& fitName : trackFitters_) {
1664       this->printFitTrackPerformance(fitName);
1665     }
1666     PrintL1trk() << "=========================================================================";
1667 
1668     if (htRphiErrMon != nullptr && not settings_->hybrid()) {
1669       // Check that stub filling was consistent with known limitations of HT firmware design.
1670 
1671       PrintL1trk() << "Max. |gradients| of stub lines in HT array is: r-phi = " << htRphiErrMon->maxLineGradient;
1672 
1673       if (htRphiErrMon->maxLineGradient > 1.) {
1674         PrintL1trk()
1675             << "WARNING: Line |gradient| exceeds 1, which firmware will not be able to cope with! Please adjust HT "
1676                "array size to avoid this.";
1677 
1678       } else if (htRphiErrMon->numErrorsTypeA > 0.) {
1679         float frac = float(htRphiErrMon->numErrorsTypeA) / float(htRphiErrMon->numErrorsNorm);
1680         PrintL1trk()
1681             << "WARNING: Despite line gradients being less than one, some fraction of HT columns have filled cells "
1682                "with no filled neighbours in W, SW or NW direction. Firmware will object to this! ";
1683         PrintL1trk() << "This fraction = " << frac << " for r-phi HT";
1684 
1685       } else if (htRphiErrMon->numErrorsTypeB > 0.) {
1686         float frac = float(htRphiErrMon->numErrorsTypeB) / float(htRphiErrMon->numErrorsNorm);
1687         PrintL1trk()
1688             << "WARNING: Despite line gradients being less than one, some fraction of HT columns recorded individual "
1689                "stubs being added to more than two cells! Thomas firmware will object to this! ";
1690         PrintL1trk() << "This fraction = " << frac << " for r-phi HT";
1691       }
1692     }
1693 
1694     // Check if GP B approximation cfg params are inconsistent.
1695     if (bApproxMistake_)
1696       PrintL1trk() << "\n WARNING: BApprox cfg params are inconsistent - see printout above.";
1697 
1698     // Restore original ROOT default cfg.
1699     TH1::SetDefaultSumw2(oldSumW2opt_);
1700   }
1701 
1702   //=== Determine "B" parameter, used in GP firmware to allow for tilted modules.
1703 
1704   void Histos::trackerGeometryAnalysis(const list<TrackerModule>& listTrackerModule) {
1705     // Don't bother producing summary if user didn't request histograms via TFileService in their cfg.
1706     if (not this->enabled())
1707       return;
1708 
1709     map<float, float> dataForGraph;
1710     for (const TrackerModule& trackerModule : listTrackerModule) {
1711       if (trackerModule.tiltedBarrel()) {
1712         float paramB = trackerModule.paramB();
1713         float zOverR = std::abs(trackerModule.minZ()) / trackerModule.minR();
1714         dataForGraph[paramB] = zOverR;  // Only store each unique paramB once, to get better histo weights.
1715       }
1716     }
1717 
1718     const int nEntries = dataForGraph.size();
1719     vector<float> vecParamB(nEntries);
1720     vector<float> vecZoverR(nEntries);
1721     unsigned int i = 0;
1722     for (const auto& p : dataForGraph) {
1723       vecParamB[i] = p.first;
1724       vecZoverR[i] = p.second;
1725       i++;
1726     }
1727 
1728     PrintL1trk() << "=========================================================================";
1729     PrintL1trk() << "--- Fit to cfg params for FPGA-friendly approximation to B parameter in GP & KF ---";
1730     PrintL1trk() << "--- (used to allowed for tilted barrel modules)                                 ---";
1731 
1732     TFileDirectory inputDir = fs_->mkdir("InputDataB");
1733     graphBVsZoverR_ = inputDir.make<TGraph>(nEntries, &vecZoverR[0], &vecParamB[0]);
1734     graphBVsZoverR_->SetNameTitle("B vs module Z/R", "; Module Z/R; B");
1735     graphBVsZoverR_->Fit("pol1", "q");
1736     TF1* fittedFunction = graphBVsZoverR_->GetFunction("pol1");
1737     double gradient = fittedFunction->GetParameter(1);
1738     double intercept = fittedFunction->GetParameter(0);
1739     double gradient_err = fittedFunction->GetParError(1);
1740     double intercept_err = fittedFunction->GetParError(0);
1741     PrintL1trk() << "         BApprox_gradient (fitted)  = " << gradient << " +- " << gradient_err;
1742     PrintL1trk() << "         BApprox_intercept (fitted) = " << intercept << " +- " << intercept_err;
1743     PrintL1trk() << "=========================================================================";
1744 
1745     // Check fitted params consistent with those assumed in cfg file.
1746     if (settings_->useApproxB()) {
1747       double gradientDiff = std::abs(gradient - settings_->bApprox_gradient());
1748       double interceptDiff = std::abs(intercept - settings_->bApprox_intercept());
1749       constexpr unsigned int nSigma = 5;
1750       if (gradientDiff > nSigma * gradient_err ||
1751           interceptDiff > nSigma * intercept_err) {  // Uncertainty independent of number of events
1752         PrintL1trk() << "\n WARNING: fitted parameters inconsistent with those specified in cfg file:";
1753         PrintL1trk() << "         BApprox_gradient  (cfg) = " << settings_->bApprox_gradient();
1754         PrintL1trk() << "         BApprox_intercept (cfg) = " << settings_->bApprox_intercept();
1755         bApproxMistake_ = true;  // Note that problem has occurred.
1756       }
1757     }
1758   }
1759 
1760 }  // namespace tmtt