/
githubmirror
/
cmssw
Обзор
Документация
Войти
/
githubmirror
/
cmssw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
SimTracker/SiPhase2Digitizer/test/PixelTestBeamValidation.cc
764 строки
36 KB
Shahzad Malik Muzaffar
[SIMULATION] Drop Geometry/CommonDetUnit package
28 май 2026, 12:59
28 май 2026, 12:59
3cef132
Код
Авторство
О чём код?
// // Access Digi collection and creates histograms accumulating // data from the module to different pixel cells, 1x1 cell, // 2x2 cell, etc.. // // Author: J.Duarte-Campderros (IFCA) // Created: 2019-10-02 // // CMSSW Framework #include "FWCore/Framework/interface/MakerMacros.h" #include "FWCore/Framework/interface/ESWatcher.h" #include "Geometry/CommonTopologies/interface/PixelGeomDetUnit.h" // CMSSW Data formats #include "DataFormats/Math/interface/CMSUnits.h" #include "DataFormats/Common/interface/Handle.h" #include "DataFormats/GeometryCommonDetAlgo/interface/MeasurementPoint.h" // system #include <algorithm> // XXX - Be careful the relative position #include "PixelTestBeamValidation.h" // Some needed units (um are more suited to the pixel size of the sensors) using cms_units::operators::operator""_deg; // Analogously to CMSUnits (no um defined, using inverse) constexpr double operator""_inv_um(long double length) { return length * 1e4; } // Energy (keV) -- to be used with the PSimHit::energyLoss with energy in GeV constexpr double operator""_inv_keV(long double energy_in_GeV) { return energy_in_GeV * 1e6; } using Phase2TrackerGeomDetUnit = PixelGeomDetUnit; PixelTestBeamValidation::PixelTestBeamValidation(const edm::ParameterSet& iConfig) : config_(iConfig), geomType_(iConfig.getParameter<std::string>("GeometryType")), //phiValues(iConfig.getParameter<std::vector<double> >("PhiAngles")), thresholdInElectrons_(iConfig.getParameter<double>("ThresholdInElectrons")), electronsPerADC_(iConfig.getParameter<double>("ElectronsPerADC")), tracksEntryAngleX_( iConfig.getUntrackedParameter<std::vector<double>>("TracksEntryAngleX", std::vector<double>())), tracksEntryAngleY_( iConfig.getUntrackedParameter<std::vector<double>>("TracksEntryAngleY", std::vector<double>())), digiToken_(consumes<edm::DetSetVector<PixelDigi>>(iConfig.getParameter<edm::InputTag>("PixelDigiSource"))), digiSimLinkToken_( consumes<edm::DetSetVector<PixelDigiSimLink>>(iConfig.getParameter<edm::InputTag>("PixelDigiSimSource"))), simTrackToken_(consumes<edm::SimTrackContainer>(iConfig.getParameter<edm::InputTag>("SimTrackSource"))), topoToken_(esConsumes<TrackerTopology, TrackerTopologyRcd>()), geomToken_(esConsumes<TrackerGeometry, TrackerDigiGeometryRecord>()), topoBToken_(esConsumes<TrackerTopology, TrackerTopologyRcd, edm::Transition::BeginRun>()), geomBToken_(esConsumes<TrackerGeometry, TrackerDigiGeometryRecord, edm::Transition::BeginRun>()) { LogDebug("PixelTestBeamValidation") << ">>> Construct PixelTestBeamValidation "; // The value to be used for ToT == 0 in electrons electronsAtToT0_ = 0.5 * (thresholdInElectrons_ + electronsPerADC_); const std::vector<edm::InputTag> psimhit_v(config_.getParameter<std::vector<edm::InputTag>>("PSimHitSource")); for (const auto& itag : psimhit_v) { simHitTokens_.push_back(consumes<edm::PSimHitContainer>(itag)); } // Parse the entry angles parameter. Remember the angles are defined in // radians and defined as 0 when perpendicular to the detector plane // --------------------------------------------------------------------- // Helper map to build up the active entry angles std::map<std::string, std::vector<double>*> prov_ref_m; // Get the range of entry angles for the tracks on the detector surfaces, if any if (tracksEntryAngleX_.size() != 0) { prov_ref_m["X"] = &tracksEntryAngleX_; } if (tracksEntryAngleY_.size() != 0) { prov_ref_m["Y"] = &tracksEntryAngleY_; } // translation from string to int std::map<std::string, unsigned int> conversor({{"X", 0}, {"Y", 1}}); // For each range vector do some consistency checks for (const auto& label_v : prov_ref_m) { // If provided 2 if (label_v.second->size() == 2) { // Just order the ranges, lower index the minimum std::sort(label_v.second->begin(), label_v.second->end()); } else if (label_v.second->size() == 1) { // Create the range with a +- 1 deg label_v.second->push_back((*label_v.second)[0] + 1.0_deg); (*label_v.second)[0] -= 1.0_deg; } else { // Not valid, throw cms::Exception("Configuration") << "Setup TrackEntryAngle parameters" << "Invalid number of elements in 'TracksEntryAngle" << label_v.first << ".size()' = " << label_v.second->size() << ". Valid sizes are 1 or 2."; } // convert the angles into its tangent (the check is going to be done // against the tangent dx/dz and dy/dz) (*label_v.second)[0] = std::tan((*label_v.second)[0]); (*label_v.second)[1] = std::tan((*label_v.second)[1]); active_entry_angles_[conversor[label_v.first]] = std::pair<double, double>({(*label_v.second)[0], (*label_v.second)[1]}); } if (prov_ref_m.size() != 0) { // The algorithm is defined in the implementation of _check_input_angles_ use_this_track_ = std::bind(&PixelTestBeamValidation::_check_input_angles_, this, std::placeholders::_1); edm::LogInfo("Configuration") << "Considering hits from tracks entering the detectors between\n " << "Considering hits from tracks entering the detectors between\n " << "\tX-plane: (" << std::atan(active_entry_angles_[0].first) << "," << std::atan(active_entry_angles_[0].second) << ") rad. " << "\tY-plane: (" << std::atan(active_entry_angles_[1].first) << "," << std::atan(active_entry_angles_[1].second) << ") rad. "; } else { // There is no requiremnt, so always process it use_this_track_ = [](const PSimHit*) -> bool { return true; }; } } // // destructor // PixelTestBeamValidation::~PixelTestBeamValidation() { LogDebug("PixelTestBeamValidation") << ">>> Destroy PixelTestBeamValidation "; } // -- DQM Begin Run // void PixelTestBeamValidation::dqmBeginRun(const edm::Run& iRun, const edm::EventSetup& iSetup) { edm::LogInfo("PixelTestBeamValidation") << "Initialize PixelTestBeamValidation "; } // // -- Analyze // void PixelTestBeamValidation::analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup) { // First clear the memoizers m_tId_det_simhits_.clear(); m_illuminated_pixels_.clear(); // Get digis and the simhit links and the simhits edm::Handle<edm::DetSetVector<PixelDigiSimLink>> digiSimLinkHandle; iEvent.getByToken(digiSimLinkToken_, digiSimLinkHandle); const edm::DetSetVector<PixelDigiSimLink>* simdigis = digiSimLinkHandle.product(); edm::Handle<edm::DetSetVector<PixelDigi>> digiHandle; iEvent.getByToken(digiToken_, digiHandle); const edm::DetSetVector<PixelDigi>* digis = digiHandle.product(); // Vector of simHits // XXX : NOt like that, just an example std::vector<const edm::PSimHitContainer*> simhits; simhits.reserve(simHitTokens_.size()); for (const auto& sh_token : simHitTokens_) { edm::Handle<edm::PSimHitContainer> simHitHandle; iEvent.getByToken(sh_token, simHitHandle); if (!simHitHandle.isValid()) { continue; } simhits.push_back(simHitHandle.product()); } // Get SimTrack /*edm::Handle<edm::SimTrackContainer> simTrackHandle; iEvent.getByToken(simTrackToken_, simTrackHandle); const edm::SimTrackContainer * simtracks = simTrackHandle.product();*/ // Geometry description edm::ESWatcher<TrackerDigiGeometryRecord> tkDigiGeomWatcher; if (!tkDigiGeomWatcher.check(iSetup)) { // XXX -- Should raise a Warning?? return; } // Tracker geometry and topology const TrackerTopology* topo = &iSetup.getData(topoToken_); const TrackerGeometry* tkGeom = &iSetup.getData(geomToken_); // Let's loop over the detectors for (auto const& dunit : tkGeom->detUnits()) { if (!isPixelSystem_(dunit)) { continue; } // -------------------------------------------- // Get more info about the detector unit // -- layer, topology (nrows,ncolumns,pitch...) const Phase2TrackerGeomDetUnit* tkDetUnit = dynamic_cast<const Phase2TrackerGeomDetUnit*>(dunit); //const PixelTopology * topo = tkDetUnit->specificTopology(); const auto detId = dunit->geographicalId(); const int layer = topo->layer(detId); // Get the relevant histo key const auto& me_unit = meUnit_(tkDetUnit->type().isBarrel(), layer, topo->side(detId)); // Get the id of the detector unit const unsigned int detId_raw = detId.rawId(); // Loop over the simhits to obtain the list of PSimHits created // in this detector unit std::vector<const PSimHit*> it_simhits; for (const auto* sh_c : simhits) { for (const auto& sh : *sh_c) { if (sh.detUnitId() == detId_raw) { it_simhits.push_back(&sh); //insert and/or reserve (?) } } } if (it_simhits.size() == 0) { continue; } // Find RAW digis (digis) created in this det unit const auto& it_digis = digis->find(detId); //std::cout << "DETECTOR: " << tkDetUnit->type().name() << " ME UNIT: " << me_unit << std::endl; // Loop over the list of PSimHits (i.e. the deposits created // by the primary+secundaries) to check if they are associated with // some digi, that is, if the simdigi link exists and to obtain the list // of channels illuminated for (const auto* psh : it_simhits) { // Check user conditions to accept the hits if (!use_this_track_(psh)) { continue; } // Fill some sim histograms const GlobalPoint tk_ep_gbl(dunit->surface().toGlobal(psh->entryPoint())); vME_track_XYMap_->Fill(tk_ep_gbl.x(), tk_ep_gbl.y()); vME_track_RZMap_->Fill(tk_ep_gbl.z(), std::hypot(tk_ep_gbl.x(), tk_ep_gbl.y())); vME_track_dxdzAngle_[me_unit]->Fill(std::atan2(psh->momentumAtEntry().x(), psh->momentumAtEntry().z())); vME_track_dydzAngle_[me_unit]->Fill(std::atan2(psh->momentumAtEntry().y(), psh->momentumAtEntry().z())); // Obtain the detected position of the sim particle: // the middle point between the entry and the exit const auto psh_pos = tkDetUnit->specificTopology().measurementPosition(psh->localPosition()); // MC Cluster finding: get the channels illuminated during digitization by this PSimHit // based on MC truth info (simdigi links) const auto psh_channels = get_illuminated_channels_(*psh, detId, simdigis); // Get the total charge for this cluster size // and obtain the center of the cluster using a charge-weighted mean int cluster_tot = 0; double cluster_tot_elec = 0.0; int cluster_size = 0; std::pair<std::set<int>, std::set<int>> cluster_size_xy; std::pair<double, double> cluster_position({0.0, 0.0}); std::set<int> used_channel; for (const auto& ch : psh_channels) { // Not re-using the digi XXX if (used_channel.find(ch) != used_channel.end()) { continue; } const PixelDigi& current_digi = get_digi_from_channel_(ch, it_digis); used_channel.insert(ch); // Fill the digi histograms vME_digi_charge1D_[me_unit]->Fill(current_digi.adc()); // Fill maps: get the position in the sensor local frame to convert into global const LocalPoint digi_local_pos( tkDetUnit->specificTopology().localPosition(MeasurementPoint(current_digi.row(), current_digi.column()))); const GlobalPoint digi_global_pos(dunit->surface().toGlobal(digi_local_pos)); vME_digi_XYMap_->Fill(digi_global_pos.x(), digi_global_pos.y()); vME_digi_RZMap_->Fill(digi_global_pos.z(), std::hypot(digi_global_pos.x(), digi_global_pos.y())); // Create the MC-cluster cluster_tot += current_digi.adc(); // Assign the middle value between the threshold and the ElectronPerADC parameter // to the first bin in order to allow ToT = 0 (valid value) const double pixel_charge_elec = (bool(current_digi.adc()) ? (current_digi.adc() * electronsPerADC_) : electronsAtToT0_); cluster_tot_elec += pixel_charge_elec; // Use the center of the pixel cluster_position.first += pixel_charge_elec * (current_digi.row() + 0.5); cluster_position.second += pixel_charge_elec * (current_digi.column() + 0.5); // Size cluster_size_xy.first.insert(current_digi.row()); cluster_size_xy.second.insert(current_digi.column()); ++cluster_size; } // Be careful here, there is 1 entry per each simhit vME_clsize1D_[me_unit]->Fill(cluster_size); vME_clsize1Dx_[me_unit]->Fill(cluster_size_xy.first.size()); vME_clsize1Dy_[me_unit]->Fill(cluster_size_xy.second.size()); // mean weighted cluster_position.first /= cluster_tot_elec; cluster_position.second /= cluster_tot_elec; // -- XXX Be careful, secondaries with already used the digis // are going the be lost (then lost on efficiency) // Efficiency --> It was found a cluster of digis? const bool is_cluster_present = (cluster_size > 0); // Get topology info of the module sensor //-const int n_rows = tkDetUnit->specificTopology().nrows(); //-const int n_cols = tkDetUnit->specificTopology().ncolumns(); const auto pitch = tkDetUnit->specificTopology().pitch(); // Residuals, convert them to longitud units (so far, in units of row, col) const double dx_um = (psh_pos.x() - cluster_position.first) * pitch.first * 1.0_inv_um; const double dy_um = (psh_pos.y() - cluster_position.second) * pitch.second * 1.0_inv_um; if (is_cluster_present) { vME_charge1D_[me_unit]->Fill(cluster_tot); vME_charge_elec1D_[me_unit]->Fill(cluster_tot_elec); vME_dx1D_[me_unit]->Fill(dx_um); vME_dy1D_[me_unit]->Fill(dy_um); vME_dxy2D_[me_unit]->Fill(dx_um, dy_um); // The track energy loss corresponding to that cluster vME_sim_cluster_charge_[me_unit]->Fill(psh->energyLoss() * 1.0_inv_keV, cluster_tot_elec); } // Histograms per cell for (unsigned int i = 0; i < vME_position_cell_[me_unit].size(); ++i) { // Convert the PSimHit center position to the IxI-cell const std::pair<double, double> icell_psh = pixel_cell_transformation_(psh_pos, i, pitch); // Efficiency: (PSimHit matched to a digi-cluster)/PSimHit vME_eff_cell_[me_unit][i]->Fill( icell_psh.first * 1.0_inv_um, icell_psh.second * 1.0_inv_um, is_cluster_present); vME_pshpos_cell_[me_unit][i]->Fill(icell_psh.first * 1.0_inv_um, icell_psh.second * 1.0_inv_um); // Digi clusters related histoos if (is_cluster_present) { // Convert to the i-cell //const std::pair<double,double> icell_digi_cluster = pixel_cell_transformation_(cluster_position,i,pitch); // Position vME_position_cell_[me_unit][i]->Fill(icell_psh.first * 1.0_inv_um, icell_psh.second * 1.0_inv_um); // Residuals vME_dx_cell_[me_unit][i]->Fill(icell_psh.first * 1.0_inv_um, icell_psh.second * 1.0_inv_um, dx_um); vME_dy_cell_[me_unit][i]->Fill(icell_psh.first * 1.0_inv_um, icell_psh.second * 1.0_inv_um, dy_um); // Charge vME_charge_cell_[me_unit][i]->Fill(icell_psh.first * 1.0_inv_um, icell_psh.second * 1.0_inv_um, cluster_tot); vME_charge_elec_cell_[me_unit][i]->Fill( icell_psh.first * 1.0_inv_um, icell_psh.second * 1.0_inv_um, cluster_tot_elec); // Cluster size vME_clsize_cell_[me_unit][i]->Fill(icell_psh.first * 1.0_inv_um, icell_psh.second * 1.0_inv_um, cluster_size); } } } } } // // -- Book Histograms // void PixelTestBeamValidation::bookHistograms(DQMStore::IBooker& ibooker, edm::Run const& iRun, edm::EventSetup const& iSetup) { // Get Geometry to associate a folder to each Pixel subdetector const TrackerGeometry* tkGeom = &iSetup.getData(geomBToken_); // Tracker Topology (layers, modules, side, etc..) const TrackerTopology* topo = &iSetup.getData(topoBToken_); const std::string top_folder = config_.getParameter<std::string>("TopFolderName"); // Histograms independent of the subdetector units ibooker.cd(); ibooker.setCurrentFolder(top_folder); vME_track_XYMap_ = setupH2D_(ibooker, "TrackXY", "Track entering position in the tracker system;x [cm];y [cm];N_{tracksId}"); vME_track_RZMap_ = setupH2D_(ibooker, "TrackRZ", "Track entering position in the tracker system;z [cm];r [cm];N_{tracksId}"); vME_digi_XYMap_ = setupH2D_(ibooker, "DigiXY", "Digi position;x [cm];y [cm];N_{digi}"); vME_digi_RZMap_ = setupH2D_(ibooker, "DigiRZ", "Digi position;z [cm];r [cm];N_{digi}"); // Get all pixel subdetector, create histogram by layers // -- More granularity can be accomplished by modules (1 central + 5 modules: in z, // each one composed by 12 pixel modules (1 long pixel + 2 ROCs) in Phi = 108 pixel-modules for (auto const& dunit : tkGeom->detUnits()) { if (!isPixelSystem_(dunit)) { continue; } //if( ! dtype.isInnerTracker() || ! dtype.isTrackerPixel() ) //{ // continue; //} const auto& dtype = dunit->type(); const auto detId = dunit->geographicalId(); const int layer = topo->layer(detId); // Create the sub-detector histogram if needed // Barrel_Layer/Endcap_Layer_Side const int me_unit = meUnit_(dtype.isBarrel(), layer, topo->side(detId)); if (vME_position_cell_.find(me_unit) == vME_position_cell_.end()) { std::string folder_name(top_folder + "/"); if (dtype.isBarrel()) { folder_name += "Barrel"; } else if (dtype.isEndcap()) { folder_name += "Endcap"; } else { cms::Exception("Geometry") << "Tracker subdetector '" << dtype.subDetector() << "' malformed: does not belong to the Endcap neither the Barrel"; } folder_name += "/Layer" + std::to_string(layer); if (topo->side(detId)) { folder_name += "/Side" + std::to_string(topo->side(detId)); } // Go the proper folder ibooker.cd(); ibooker.setCurrentFolder(folder_name); const TrackerGeomDet* geomDetUnit = tkGeom->idToDetUnit(detId); const Phase2TrackerGeomDetUnit* tkDetUnit = dynamic_cast<const Phase2TrackerGeomDetUnit*>(geomDetUnit); const int nrows = tkDetUnit->specificTopology().nrows(); const int ncols = tkDetUnit->specificTopology().ncolumns(); const auto pitch = tkDetUnit->specificTopology().pitch(); //const double x_size = nrows*pitch.first; //const double y_size = ncols*pitch.second; // And create the histos // Per detector unit histos vME_clsize1D_[me_unit] = setupH1D_(ibooker, "ClusterSize1D", "MC-truth DIGI cluster size;Cluster size;N_{clusters}"); vME_clsize1Dx_[me_unit] = setupH1D_(ibooker, "ClusterSize1Dx", "MC-truth DIGI cluster size in X;Cluster size;N_{clusters}"); vME_clsize1Dy_[me_unit] = setupH1D_(ibooker, "ClusterSize1Dy", "MC-truth DIGI cluster size in Y;Cluster size;N_{clusters}"); vME_charge1D_[me_unit] = setupH1D_(ibooker, "Charge1D", "MC-truth DIGI cluster charge;Cluster charge [ToT];N_{clusters}"); vME_charge_elec1D_[me_unit] = setupH1D_(ibooker, "ChargeElec1D", "MC-truth DIGI cluster charge;Cluster charge [Electrons];N_{clusters}"); vME_track_dxdzAngle_[me_unit] = setupH1D_( ibooker, "TrackAngleDxdz", "Angle between the track-momentum and detector surface (X-plane);#pi/2-#theta_{x} [rad];N_{tracks}"); vME_track_dydzAngle_[me_unit] = setupH1D_( ibooker, "TrackAngleDydz", "Angle between the track-momentum and detector surface (Y-plane);#pi/2-#theta_{y} [rad];N_{tracks}"); vME_dx1D_[me_unit] = setupH1D_( ibooker, "Dx1D", "MC-truth DIGI cluster residuals X;x_{PSimHit}-x^{cluster}_{digi} [#mum];N_{digi clusters}"); vME_dy1D_[me_unit] = setupH1D_( ibooker, "Dy1D", "MC-truth DIGI cluster residual Y;y_{PSimHit}-y^{cluster}_{digi} [#mum];N_{digi clusters}"); vME_dxy2D_[me_unit] = setupH2D_(ibooker, "Dxy2D", "MC-truth DIGI cluster residuals;x_{PSimHit}-x^{cluster}_{digi} " "[#mum];y_{PSimHit}-y^{cluster}_{digi} [#mum];N_{digi clusters}"); vME_digi_charge1D_[me_unit] = setupH1D_(ibooker, "DigiCharge1D", "Digi charge;digi charge [ToT];N_{digi}"); vME_sim_cluster_charge_[me_unit] = setupH2D_(ibooker, "SimClusterCharge", "PSimHit Energy deposit vs. Cluster Charge;deposited E_{sim} [keV];cluster_{charge} [Electrons];"); // The histos per cell // Prepare the ranges: 0- whole sensor, 1- cell 1x1, 2-cell 2x2, const std::vector<std::pair<double, double>> xranges = { std::make_pair<double, double>(0, (nrows - 1) * pitch.first * 1.0_inv_um), std::make_pair<double, double>(0, pitch.first * 1.0_inv_um), std::make_pair<double, double>(0, 2.0 * pitch.first * 1.0_inv_um)}; const std::vector<std::pair<double, double>> yranges = { std::make_pair<double, double>(0, (ncols - 1) * pitch.second * 1.0_inv_um), std::make_pair<double, double>(0, pitch.second * 1.0_inv_um), std::make_pair<double, double>(0, 2.0 * pitch.second * 1.0_inv_um)}; for (unsigned int i = 0; i < xranges.size(); ++i) { const std::string cell("Cell " + std::to_string(i) + "x" + std::to_string(i) + ": "); vME_pshpos_cell_[me_unit].push_back( setupH2D_(ibooker, "Position_" + std::to_string(i), cell + "PSimHit middle point position;x [#mum];y [#mum];N_{clusters}", xranges[i], yranges[i])); vME_position_cell_[me_unit].push_back( setupH2D_(ibooker, "MatchedPosition_" + std::to_string(i), cell + "PSimHit matched to a DIGI cluster position ;x [#mum];y [#mum];N_{clusters}", xranges[i], yranges[i])); vME_eff_cell_[me_unit].push_back(setupProf2D_(ibooker, "Efficiency_" + std::to_string(i), cell + "MC-truth efficiency;x [#mum];y [#mum];<#varepsilon>", xranges[i], yranges[i])); vME_clsize_cell_[me_unit].push_back( setupProf2D_(ibooker, "ClusterSize_" + std::to_string(i), cell + "MC-truth cluster size;x [#mum];y [#mum];<Cluster size>", xranges[i], yranges[i])); vME_charge_cell_[me_unit].push_back(setupProf2D_(ibooker, "Charge_" + std::to_string(i), cell + "MC-truth charge;x [#mum];y [#mum];<ToT>", xranges[i], yranges[i])); vME_charge_elec_cell_[me_unit].push_back(setupProf2D_(ibooker, "Charge_elec_" + std::to_string(i), cell + "MC-truth charge;x [#mum];y [#mum];<Electrons>", xranges[i], yranges[i])); vME_dx_cell_[me_unit].push_back(setupProf2D_(ibooker, "Dx_" + std::to_string(i), cell + "MC-truth residuals;x [#mum];y [#mum];<#Deltax [#mum]>", xranges[i], yranges[i])); vME_dy_cell_[me_unit].push_back(setupProf2D_(ibooker, "Dy_" + std::to_string(i), cell + "MC-truth residuals;x [#mum];y [#mum];<#Deltay [#mum]>", xranges[i], yranges[i])); } edm::LogInfo("PixelTestBeamValidation") << "Booking Histograms in: " << folder_name << " ME UNIT:" << me_unit; edm::LogInfo("PixelTestBeamValidation") << "Booking Histograms in: " << folder_name; } } } bool PixelTestBeamValidation::isPixelSystem_(const GeomDetUnit* dunit) const { const auto& dtype = dunit->type(); if (!dtype.isInnerTracker() || !dtype.isTrackerPixel()) { return false; } return true; } // Helper functions to setup int PixelTestBeamValidation::meUnit_(bool isBarrel, int layer, int side) const { // [isBarrel][layer][side] // [X][XXX][XX] return (static_cast<int>(isBarrel) << 6) | (layer << 3) | side; } PixelTestBeamValidation::MonitorElement* PixelTestBeamValidation::setupH1D_(DQMStore::IBooker& ibooker, const std::string& histoname, const std::string& title) { // Config need to have exactly the same histo name edm::ParameterSet params = config_.getParameter<edm::ParameterSet>(histoname); return ibooker.book1D(histoname, title, params.getParameter<int32_t>("Nxbins"), params.getParameter<double>("xmin"), params.getParameter<double>("xmax")); } PixelTestBeamValidation::MonitorElement* PixelTestBeamValidation::setupH2D_(DQMStore::IBooker& ibooker, const std::string& histoname, const std::string& title) { // Config need to have exactly the same histo name edm::ParameterSet params = config_.getParameter<edm::ParameterSet>(histoname); return ibooker.book2D(histoname, title, params.getParameter<int32_t>("Nxbins"), params.getParameter<double>("xmin"), params.getParameter<double>("xmax"), params.getParameter<int32_t>("Nybins"), params.getParameter<double>("ymin"), params.getParameter<double>("ymax")); } PixelTestBeamValidation::MonitorElement* PixelTestBeamValidation::setupH2D_(DQMStore::IBooker& ibooker, const std::string& histoname, const std::string& title, const std::pair<double, double>& xranges, const std::pair<double, double>& yranges) { // Config need to have exactly the same histo name edm::ParameterSet params = config_.getParameter<edm::ParameterSet>(histoname); return ibooker.book2D(histoname, title, params.getParameter<int32_t>("Nxbins"), xranges.first, xranges.second, params.getParameter<int32_t>("Nybins"), yranges.first, yranges.second); } PixelTestBeamValidation::MonitorElement* PixelTestBeamValidation::setupProf2D_( DQMStore::IBooker& ibooker, const std::string& histoname, const std::string& title, const std::pair<double, double>& xranges, const std::pair<double, double>& yranges) { // Config need to have exactly the same histo name edm::ParameterSet params = config_.getParameter<edm::ParameterSet>(histoname); return ibooker.bookProfile2D(histoname, title, params.getParameter<int32_t>("Nxbins"), xranges.first, xranges.second, params.getParameter<int32_t>("Nybins"), yranges.first, yranges.second, params.getParameter<double>("zmin"), params.getParameter<double>("zmax")); } const PixelDigi& PixelTestBeamValidation::get_digi_from_channel_( int ch, const edm::DetSetVector<PixelDigi>::const_iterator& itdigis) { for (const auto& dh : *itdigis) { if (dh.channel() == ch) { return dh; } } // MAke sense not to find a digi? throw cms::Exception("DIGI Pixel Validation") << "Not found a PixelDig for the given channel: " << ch; } const SimTrack* PixelTestBeamValidation::get_simtrack_from_id_(unsigned int idx, const edm::SimTrackContainer* stc) { for (const auto& st : *stc) { if (st.trackId() == idx) { return &st; } } // Any simtrack correspond to this trackid index //edm::LogWarning("PixelTestBeamValidation::get_simtrack_from_id_") edm::LogInfo("PixelTestBeamValidation::get_simtrack_from_id_") << "Not found any SimTrack with trackId: " << idx; return nullptr; } const std::vector<const PSimHit*> PixelTestBeamValidation::get_simhits_from_trackid_( unsigned int tid, unsigned int detid_raw, const std::vector<const edm::PSimHitContainer*>& psimhits) { // It was already found? if (m_tId_det_simhits_.find(tid) != m_tId_det_simhits_.end()) { // Note that if there were no simhits in detid_raw, now it // is creating an empty std::vector<const edm::PSimHitContainer*> return m_tId_det_simhits_[tid][detid_raw]; } // Otherwise, // Create the new map for the track m_tId_det_simhits_[tid] = std::map<unsigned int, std::vector<const PSimHit*>>(); // and search for it, all the PsimHit found in all detectors // are going to be seeked once, therefore memoizing already for (const auto* sh_c : psimhits) { for (const auto& sh : *sh_c) { if (sh.trackId() == tid) { m_tId_det_simhits_[tid][sh.detUnitId()].push_back(&sh); } } } // And returning what was requested return m_tId_det_simhits_[tid][detid_raw]; } const std::pair<double, double> PixelTestBeamValidation::pixel_cell_transformation_( const MeasurementPoint& pos, unsigned int icell, const std::pair<double, double>& pitch) { return pixel_cell_transformation_(std::pair<double, double>({pos.x(), pos.y()}), icell, pitch); } const std::pair<double, double> PixelTestBeamValidation::pixel_cell_transformation_( const std::pair<double, double>& pos, unsigned int icell, const std::pair<double, double>& pitch) { // Get the position modulo icell // Case the whole detector (icell==0) double xmod = pos.first; double ymod = pos.second; // Actual pixel cells if (icell != 0) { xmod = std::fmod(pos.first, icell); ymod = std::fmod(pos.second, icell); } const double xcell = xmod * pitch.first; const double ycell = ymod * pitch.second; return std::pair<double, double>({xcell, ycell}); } //bool PixelTestBeamValidation::channel_iluminated_by_(const MeasurementPoint & localpos,int channel, double tolerance) const //{ // const auto pos_channel(PixelDigi::channelToPixel(channel)); // if( std::fabs(localpos.x()-pos_channel.first) <= tolerance // && std::fabs(localpos.y()-pos_channel.second) <= tolerance ) // { // return true; // } // return false; //} bool PixelTestBeamValidation::channel_iluminated_by_(const PSimHit& ps, int channel, const PixelGeomDetUnit* tkDetUnit) { // Get the list of pixels illuminated by the PSimHit const auto pixel_list = get_illuminated_pixels_(ps, tkDetUnit); // Get the digi position const auto pos_channel(PixelDigi::channelToPixel(channel)); for (const auto& px_py : pixel_list) { if (px_py.first == pos_channel.first && px_py.second == pos_channel.second) { return true; } } return false; } std::set<int> PixelTestBeamValidation::get_illuminated_channels_(const PSimHit& ps, const DetId& detid, const edm::DetSetVector<PixelDigiSimLink>* simdigis) { // Find simulated digi links (simdigis) created in this det unit const auto& it_simdigilink = simdigis->find(detid); if (it_simdigilink == simdigis->end()) { return std::set<int>(); } std::set<int> channels; for (const auto& hdsim : *it_simdigilink) { if (ps.trackId() == hdsim.SimTrackId()) { channels.insert(hdsim.channel()); } } return channels; } std::set<std::pair<int, int>> PixelTestBeamValidation::get_illuminated_pixels_(const PSimHit& ps, const PixelGeomDetUnit* tkDetUnit) { auto ps_key = reinterpret_cast<std::uintptr_t>(&ps); // -- Check if was already memoized if (m_illuminated_pixels_.find(ps_key) != m_illuminated_pixels_.end()) { return m_illuminated_pixels_[ps_key]; } // Get the entry point - exit point position const double min_x = std::min(ps.entryPoint().x(), ps.exitPoint().x()); const double min_y = std::min(ps.entryPoint().y(), ps.exitPoint().y()); const double max_x = std::max(ps.entryPoint().x(), ps.exitPoint().x()); const double max_y = std::max(ps.entryPoint().y(), ps.exitPoint().y()); // Get the position in readout units for each point const auto min_pos_pre = tkDetUnit->specificTopology().measurementPosition(LocalPoint(min_x, min_y)); const auto max_pos_pre = tkDetUnit->specificTopology().measurementPosition(LocalPoint(max_x, max_y)); // Adding a unit at each side in order to include charge migration const MeasurementPoint min_pos(std::max(0.0, min_pos_pre.x() - 1.0), std::max(0.0, min_pos_pre.y() - 1.0)); const MeasurementPoint max_pos(std::min(max_pos_pre.x() + 1.0, tkDetUnit->specificTopology().nrows() - 1.0), std::min(max_pos_pre.y() + 1.0, tkDetUnit->specificTopology().ncolumns() - 1.0)); // Count how many cells has passed. Use the most conservative rounding: // round for maximums and int (floor) for minimums //const int ncells_x = std::round(max_pos.x())-std::floor(min_pos.x()); //const int ncells_y = std::round(max_pos.y())-std::floor(min_pos.y()); //std::cout << "ENTRANDO --- PSimHit (" << ps_key << ") entry point: " << ps.entryPoint() << " exitPoint: " << ps.exitPoint() // << " Entry (pixel units): " << min_pos // << " Exit (pixel units): " << max_pos << ")" // << " ILLUMINATED PIXELS: "; std::set<std::pair<int, int>> illuminated_pixels; for (unsigned int px = std::floor(min_pos.x()); px <= std::round(max_pos.x()); ++px) { for (unsigned int py = std::floor(min_pos.y()); py <= std::round(max_pos.y()); ++py) { //std::cout << " [" << px << "," << py << "]"; illuminated_pixels.insert(std::pair<int, int>(px, py)); } } //std::cout << " TOTAL PIXELS: " << illuminated_pixels.size() << std::endl; // Memoize, and return what expected. m_illuminated_pixels_[ps_key] = illuminated_pixels; return m_illuminated_pixels_[ps_key]; } bool PixelTestBeamValidation::_check_input_angles_(const PSimHit* psimhit) { // Create a vector to check against the range map where // X axis is in the key 0, Y axis in the key 1 const std::vector<double> entry_tan({psimhit->momentumAtEntry().x() / psimhit->momentumAtEntry().z(), psimhit->momentumAtEntry().y() / psimhit->momentumAtEntry().z()}); for (const auto& axis_ranges : active_entry_angles_) { if (axis_ranges.second.first > entry_tan[axis_ranges.first] || axis_ranges.second.second < entry_tan[axis_ranges.first]) { return false; } } return true; } //define this as a plug-in DEFINE_FWK_MODULE(PixelTestBeamValidation);