From 963781b3a2147a4feed0f5ef8c2fa85beb7f3d7b Mon Sep 17 00:00:00 2001 From: Thomas Reis Date: Fri, 3 Jul 2026 13:53:45 +0200 Subject: [PATCH 1/4] Add ECAL Phase 2 digis and TP digis validation. --- .../Configuration/python/ecalSimValid_cff.py | 4 +- .../python/globalValidation_cff.py | 8 +- .../plugins/EcalDigisValidationPh2.cc | 322 ++++++++++++++++++ .../python/ecalDigisValidationSequence_cff.py | 12 +- .../plugins/BuildFile.xml | 5 + .../plugins/EcalTPsValidationPh2.cc | 144 ++++++++ .../python/ecalTPsValidationSequence_cff.py | 6 + 7 files changed, 497 insertions(+), 4 deletions(-) create mode 100644 Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc create mode 100644 Validation/EcalTriggerPrimitives/plugins/BuildFile.xml create mode 100644 Validation/EcalTriggerPrimitives/plugins/EcalTPsValidationPh2.cc create mode 100644 Validation/EcalTriggerPrimitives/python/ecalTPsValidationSequence_cff.py diff --git a/Validation/Configuration/python/ecalSimValid_cff.py b/Validation/Configuration/python/ecalSimValid_cff.py index ee1e855028341..4d61bb3a0e410 100644 --- a/Validation/Configuration/python/ecalSimValid_cff.py +++ b/Validation/Configuration/python/ecalSimValid_cff.py @@ -4,10 +4,11 @@ # from Validation.EcalHits.ecalSimHitsValidationSequence_cff import * from Validation.EcalDigis.ecalDigisValidationSequence_cff import * +from Validation.EcalTriggerPrimitives.ecalTPsValidationSequence_cff import * from Validation.EcalRecHits.ecalRecHitsValidationSequence_cff import * from Validation.EcalClusters.ecalClustersValidationSequence_cff import * -ecalSimValid = cms.Sequence(ecalSimHitsValidationSequence+ecalDigisValidationSequence+ecalRecHitsValidationSequence+ecalClustersValidationSequence) +ecalSimValid = cms.Sequence(ecalSimHitsValidationSequence+ecalDigisValidationSequence+ecalTPsValidationSequence+ecalRecHitsValidationSequence+ecalClustersValidationSequence) from DQM.EcalMonitorTasks.EcalMonitorTask_cfi import * from DQM.EcalMonitorTasks.EcalFEDMonitor_cfi import * @@ -24,6 +25,7 @@ validationECALPhase2 = cms.Sequence( ecalSimHitsValidationSequencePhase2* ecalDigisValidationSequencePhase2* + ecalTPsValidationSequencePhase2* ecalRecHitsValidationSequencePhase2* ecalClustersValidationSequence* ecalDQMSequencePhase2 diff --git a/Validation/Configuration/python/globalValidation_cff.py b/Validation/Configuration/python/globalValidation_cff.py index 9fcf1c848e41c..d9427aa567d5a 100644 --- a/Validation/Configuration/python/globalValidation_cff.py +++ b/Validation/Configuration/python/globalValidation_cff.py @@ -9,6 +9,7 @@ from Validation.RecoTrack.TrackValidation_cff import * from Validation.EcalHits.ecalSimHitsValidationSequence_cff import * from Validation.EcalDigis.ecalDigisValidationSequence_cff import * +from Validation.EcalTriggerPrimitives.ecalTPsValidationSequence_cff import * from Validation.EcalRecHits.ecalRecHitsValidationSequence_cff import * from Validation.EcalClusters.ecalClustersValidationSequence_cff import * from Validation.HcalHits.SimHitsValidationSequence_cff import * @@ -73,6 +74,7 @@ + trackingRecHitsValid + ecalSimHitsValidationSequence + ecalDigisValidationSequence + + ecalTPsValidationSequence + ecalRecHitsValidationSequence + ecalClustersValidationSequence + hcalSimHitsValidationSequence @@ -109,7 +111,7 @@ trackerHitsValidation, trackerDigisValidation, trackerRecHitsValidation, trackingRecHitsValid, # the following depends on crossing frame of ecal simhits, which is a bit hard to implement in the fastsim workflow # besides: is this cross frame doing something, or is it a relic from the past? - ecalDigisValidationSequence, ecalRecHitsValidationSequence + ecalDigisValidationSequence, ecalTPsValidationSequence, ecalRecHitsValidationSequence ])) #lite tracking validator to be used in the Validation matrix @@ -162,6 +164,7 @@ globalValidationECAL = cms.Sequence( ecalSimHitsValidationSequence + ecalDigisValidationSequence + + ecalTPsValidationSequence + ecalRecHitsValidationSequence + ecalClustersValidationSequence ) @@ -169,6 +172,7 @@ globalValidationECALOnly = cms.Sequence( ecalSimHitsValidationSequence + ecalDigisValidationSequence + + ecalTPsValidationSequence + ecalRecHitsValidationSequence + pfClusterCaloOnlyValidationSequence ) @@ -177,6 +181,8 @@ phase2_ecal_devel.toReplaceWith(ecalDigisValidationSequence, ecalDigisValidationSequencePhase2) phase2_ecal_devel.toReplaceWith(ecalRecHitsValidationSequence, ecalRecHitsValidationSequencePhase2) phase2_ecal_devel.toReplaceWith(pfClusterCaloOnlyValidationSequence, ecalClustersValidationSequence) +from Configuration.Eras.Modifier_phase2_ecalTP_devel_cff import phase2_ecalTP_devel +phase2_ecalTP_devel.toReplaceWith(ecalTPsValidationSequence, ecalTPsValidationSequencePhase2) # HCAL local reconstruction globalPrevalidationHCAL = cms.Sequence() diff --git a/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc b/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc new file mode 100644 index 0000000000000..7cd88021b943f --- /dev/null +++ b/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc @@ -0,0 +1,322 @@ +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include "DQMServices/Core/interface/DQMEDAnalyzer.h" +#include "DQMServices/Core/interface/DQMStore.h" + +#include "CondFormats/DataRecord/interface/EcalADCToGeVConstantRcd.h" +#include "CondFormats/DataRecord/interface/EcalCATIAGainRatiosRcd.h" +#include "CondFormats/EcalObjects/interface/EcalADCToGeVConstant.h" +#include "CondFormats/EcalObjects/interface/EcalCATIAGainRatios.h" + +#include "SimDataFormats/GeneratorProducts/interface/HepMCProduct.h" +#include "SimDataFormats/EncodedEventId/interface/EncodedEventId.h" +#include "SimDataFormats/CaloHit/interface/PCaloHit.h" + +#include "DataFormats/EcalDigi/interface/EcalDataFrame_Ph2.h" +#include "DataFormats/EcalDigi/interface/EcalDigiCollections.h" +#include "SimDataFormats/CrossingFrame/interface/CrossingFrame.h" +#include "SimDataFormats/CrossingFrame/interface/MixCollection.h" + +#include +#include + +class EcalDigisValidationPh2 : public DQMEDAnalyzer { + typedef std::map > MapType; + +public: + EcalDigisValidationPh2(const edm::ParameterSet& ps); + ~EcalDigisValidationPh2() override = default; + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); + void bookHistograms(DQMStore::IBooker& i, edm::Run const&, edm::EventSetup const&) override; + +protected: + void analyze(edm::Event const& event, edm::EventSetup const& eventSetup) override; + +private: + static auto constexpr kMaxSamples_ = EcalDataFrame_Ph2::MAXSAMPLES; + + const edm::EDGetTokenT hepMCToken_; + const edm::EDGetTokenT digiCollectionToken_; + const edm::EDGetTokenT > crossingFramePCaloHitToken_; + + const edm::ESGetToken adcToGeVToken_; + const edm::ESGetToken gainRatiosToken_; + + MonitorElement* meGunEnergy_; + MonitorElement* meGunEta_; + MonitorElement* meGunPhi_; + + MonitorElement* meDigiSimRatio_; + MonitorElement* meDigiSimRatiogt10ADC_; + MonitorElement* meDigiSimRatiogt100ADC_; + + MonitorElement* meDigiOccupancy_; + MonitorElement* meDigiMultiplicity_; + MonitorElement* meDigiADCGlobal_; + MonitorElement* meDigiADCAnalog_[kMaxSamples_]; + MonitorElement* meDigiADCg10_[kMaxSamples_]; + MonitorElement* meDigiADCg1_[kMaxSamples_]; + MonitorElement* meDigiGain_[kMaxSamples_]; + + MonitorElement* mePedestal_; + MonitorElement* meMaximumgt10ADC_; + MonitorElement* meMaximumgt100ADC_; + MonitorElement* menADCafterSwitch_; +}; + +EcalDigisValidationPh2::EcalDigisValidationPh2(const edm::ParameterSet& ps) + : hepMCToken_(consumes(edm::InputTag(ps.getParameter("moduleLabelMC")))), + digiCollectionToken_(consumes(ps.getParameter("digiCollection"))), + crossingFramePCaloHitToken_(consumes >( + edm::InputTag("mix", ps.getParameter("moduleLabelG4") + std::string("EcalHitsEB")))), + adcToGeVToken_(esConsumes()), + gainRatiosToken_(esConsumes()), + meGunEnergy_(nullptr), + meGunEta_(nullptr), + meGunPhi_(nullptr), + meDigiSimRatio_(nullptr), + meDigiSimRatiogt10ADC_(nullptr), + meDigiSimRatiogt100ADC_(nullptr), + meDigiOccupancy_(nullptr), + meDigiMultiplicity_(nullptr), + meDigiADCGlobal_(nullptr), + mePedestal_(nullptr), + meMaximumgt10ADC_(nullptr), + meMaximumgt100ADC_(nullptr), + menADCafterSwitch_(nullptr) { + for (int i = 0; i < kMaxSamples_; ++i) { + meDigiADCAnalog_[i] = nullptr; + meDigiADCg10_[i] = nullptr; + meDigiADCg1_[i] = nullptr; + meDigiGain_[i] = nullptr; + } +} + +void EcalDigisValidationPh2::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + desc.add("digiCollection", edm::InputTag("simEcalUnsuppressedDigis")); + desc.add("moduleLabelMC", std::string("generatorSmeared")); + desc.add("moduleLabelG4", std::string("g4SimHits")); + descriptions.add("ecalDigisValidationPh2", desc); +} + +void EcalDigisValidationPh2::bookHistograms(DQMStore::IBooker& ibooker, edm::Run const&, edm::EventSetup const&) { + Char_t histo[200]; + + ibooker.setCurrentFolder("EcalDigisV/EcalDigiTask"); + + sprintf(histo, "EcalDigiTask Gun Momentum"); + meGunEnergy_ = ibooker.book1D(histo, histo, 100, 0., 1000.); + + sprintf(histo, "EcalDigiTask Gun Eta"); + meGunEta_ = ibooker.book1D(histo, histo, 700, -3.5, 3.5); + + sprintf(histo, "EcalDigiTask Gun Phi"); + meGunPhi_ = ibooker.book1D(histo, histo, 360, 0., 360.); + + sprintf(histo, "EcalDigiTask maximum Digi over Sim ratio"); + meDigiSimRatio_ = ibooker.book1D(histo, histo, 100, 0., 2.); + + sprintf(histo, "EcalDigiTask maximum Digi over Sim ratio gt 10 ADC"); + meDigiSimRatiogt10ADC_ = ibooker.book1D(histo, histo, 100, 0., 2.); + + sprintf(histo, "EcalDigiTask maximum Digi over Sim ratio gt 100 ADC"); + meDigiSimRatiogt100ADC_ = ibooker.book1D(histo, histo, 100, 0., 2.); + + sprintf(histo, "EcalDigiTask occupancy"); + meDigiOccupancy_ = ibooker.book2D(histo, histo, 360, 0., 360., 170, -85., 85.); + + sprintf(histo, "EcalDigiTask digis multiplicity"); + meDigiMultiplicity_ = ibooker.book1D(histo, histo, 612, 0., 61200); + + sprintf(histo, "EcalDigiTask global pulse shape"); + meDigiADCGlobal_ = ibooker.bookProfile(histo, histo, kMaxSamples_, 0, kMaxSamples_, 10000, 0., 1000.); + + for (int i = 0; i < kMaxSamples_; ++i) { + sprintf(histo, "EcalDigiTask analog pulse %02d", i + 1); + meDigiADCAnalog_[i] = ibooker.book1D(histo, histo, 4000, 0., 400.); + + sprintf(histo, "EcalDigiTask ADC pulse %02d Gain 10", i + 1); + meDigiADCg10_[i] = ibooker.book1D(histo, histo, 4096, -0.5, 4095.5); + + sprintf(histo, "EcalDigiTask ADC pulse %02d Gain 1", i + 1); + meDigiADCg1_[i] = ibooker.book1D(histo, histo, 4096, -0.5, 4095.5); + + sprintf(histo, "EcalDigiTask gain pulse %02d", i + 1); + meDigiGain_[i] = ibooker.book1D(histo, histo, 2, 0, 2); + } + + sprintf(histo, "EcalDigiTask pedestal for pre-sample"); + mePedestal_ = ibooker.book1D(histo, histo, 4096, -0.5, 4095.5); + + sprintf(histo, "EcalDigiTask maximum position gt 10 ADC"); + meMaximumgt10ADC_ = ibooker.book1D(histo, histo, kMaxSamples_, 0., static_cast(kMaxSamples_)); + + sprintf(histo, "EcalDigiTask maximum position gt 100 ADC"); + meMaximumgt100ADC_ = ibooker.book1D(histo, histo, kMaxSamples_, 0., static_cast(kMaxSamples_)); + + sprintf(histo, "EcalDigiTask ADC counts after gain switch"); + menADCafterSwitch_ = ibooker.book1D(histo, histo, kMaxSamples_, 0., static_cast(kMaxSamples_)); +} + +void EcalDigisValidationPh2::analyze(edm::Event const& event, edm::EventSetup const& eventSetup) { + edm::Handle mcEvt; + edm::Handle > crossingFrame; + edm::Handle ecalDigis; + + bool skipMC = false; + event.getByToken(hepMCToken_, mcEvt); + if (!mcEvt.isValid()) { + skipMC = true; + } + + const EBDigiCollectionPh2* digis = nullptr; + + bool doDigis = true; + event.getByToken(digiCollectionToken_, ecalDigis); + if (ecalDigis.isValid()) { + digis = ecalDigis.product(); + if (digis->empty()) + doDigis = false; + } else { + doDigis = false; + } + + if (!skipMC) { + for (HepMC::GenEvent::particle_const_iterator p = mcEvt->GetEvent()->particles_begin(); + p != mcEvt->GetEvent()->particles_end(); + ++p) { + auto const theGunEnergy = (*p)->momentum().e(); + auto const htheta = (*p)->momentum().theta(); + auto const heta = -log(tan(htheta * 0.5)); + auto hphi = (*p)->momentum().phi(); + hphi = (hphi >= 0) ? hphi : hphi + 2 * M_PI; + hphi = hphi / M_PI * 180.; + LogDebug("EventInfo") << "Particle gun type form MC = " << abs((*p)->pdg_id()) << "\n" + << "Energy = " << (*p)->momentum().e() << " Eta = " << heta << " Phi = " << hphi; + + meGunEnergy_->Fill(theGunEnergy); + meGunEta_->Fill(heta); + meGunPhi_->Fill(hphi); + } + } + + if (doDigis) { + event.getByToken(crossingFramePCaloHitToken_, crossingFrame); + const MixCollection barrelHits(crossingFrame.product()); + + MapType ebSimMap; + // loop over simHits + for (auto const& iHit : barrelHits) { + auto const ebid = EBDetId(iHit.id()); + + LogDebug("HitInfo") << " CaloHit " << iHit.getName() << "\n" + << " DetID = " << iHit.id() << " EBDetId = " << ebid.ieta() << " " << ebid.iphi() << "\n" + << " Time = " << iHit.time() << " Event id. = " << iHit.eventId().rawId() << "\n" + << " Track Id = " << iHit.geantTrackId() << "\n" + << " Energy = " << iHit.energy(); + + auto const crystid = ebid.rawId(); + ebSimMap[crystid] += iHit.energy(); + } + + // get conditions + auto const adcToGeV = eventSetup.getData(adcToGeVToken_).getEBValue(); + auto const& gainRatios = eventSetup.getData(gainRatiosToken_); + std::array gainConv = {10., 1.}; + + meDigiMultiplicity_->Fill(digis->size()); + + // loop over Digis + for (unsigned int digi = 0; digi < digis->size(); ++digi) { + auto const& ebdf = (*digis)[digi]; + auto const nrSamples = ebdf.size(); + + const EBDetId ebid(ebdf.id()); + + meDigiOccupancy_->Fill(ebid.iphi(), ebid.ieta()); + + gainConv[0] = gainRatios[ebid]; + + double emax = 0.; + int pmax = 0; + double pedestalPreSample = 0.; + double pedestalPreSampleAnalog = 0.; + int countsAfterGainSwitch = 0; + unsigned int higherGainSample = 0; + int prevGainId = 0; + + std::vector ebAnalogSignal(nrSamples, 0.); + + for (unsigned int sample = 0; sample < nrSamples; ++sample) { + const EcalLiteDTUSample mySample = ebdf[sample]; + ebAnalogSignal[sample] = mySample.adc() * gainConv[mySample.gainId()] * adcToGeV; + if (emax < ebAnalogSignal[sample]) { + emax = ebAnalogSignal[sample]; + pmax = sample; + } + if (sample < 3) { + pedestalPreSample += mySample.adc(); + pedestalPreSampleAnalog += mySample.adc() * gainConv[mySample.gainId()] * adcToGeV; + } + + if (sample > 0 && mySample.gainId() > prevGainId) { + higherGainSample = sample; + countsAfterGainSwitch = 1; + } + if (mySample.gainId() > 0 && sample != higherGainSample) { + ++countsAfterGainSwitch; + } + + LogDebug("DigiInfo") << " sample " << sample << " ADC counts = " << mySample.adc() + << " Gain Id = " << mySample.gainId() << " Analog eq = " << ebAnalogSignal[sample]; + + meDigiADCAnalog_[sample]->Fill(ebAnalogSignal[sample]); + + if (mySample.gainId() == 0) { + meDigiADCg10_[sample]->Fill(mySample.adc()); + } else if (mySample.gainId() == 1) { + meDigiADCg1_[sample]->Fill(mySample.adc()); + } + meDigiGain_[sample]->Fill(mySample.gainId()); + + prevGainId = mySample.gainId(); + } + + pedestalPreSample /= 3.; + pedestalPreSampleAnalog /= 3.; + auto const pmaxGainId = static_cast(ebdf[pmax]).gainId(); + auto const Erec = emax - pedestalPreSampleAnalog * gainConv[pmaxGainId]; + + for (unsigned int sample = 0; sample < nrSamples; ++sample) { + if (Erec > 100. * adcToGeV) + meDigiADCGlobal_->Fill(sample, ebAnalogSignal[sample]); + } + + if (ebSimMap[ebid.rawId()] != 0.) { + LogDebug("DigiInfo") << " Digi / Hit = " << Erec << " / " << ebSimMap[ebid.rawId()] << " gainConv " + << gainConv[pmaxGainId]; + meDigiSimRatio_->Fill(Erec / ebSimMap[ebid.rawId()]); + if (Erec > 10. * adcToGeV) { + meDigiSimRatiogt10ADC_->Fill(Erec / ebSimMap[ebid.rawId()]); + if (Erec > 100. * adcToGeV) + meDigiSimRatiogt100ADC_->Fill(Erec / ebSimMap[ebid.rawId()]); + } + } + + mePedestal_->Fill(pedestalPreSample); + if (Erec > 10. * adcToGeV) { + meMaximumgt10ADC_->Fill(pmax); + if (Erec > 100. * adcToGeV) + meMaximumgt100ADC_->Fill(pmax); + } + menADCafterSwitch_->Fill(countsAfterGainSwitch); + } + } +} + +DEFINE_FWK_MODULE(EcalDigisValidationPh2); diff --git a/Validation/EcalDigis/python/ecalDigisValidationSequence_cff.py b/Validation/EcalDigis/python/ecalDigisValidationSequence_cff.py index 891111d35670c..5f1c47ea5be89 100644 --- a/Validation/EcalDigis/python/ecalDigisValidationSequence_cff.py +++ b/Validation/EcalDigis/python/ecalDigisValidationSequence_cff.py @@ -8,5 +8,13 @@ from Validation.EcalDigis.ecalSelectiveReadoutValidation_cfi import * ecalDigisValidationSequence = cms.Sequence(ecalDigisValidation*ecalBarrelDigisValidation*ecalEndcapDigisValidation*ecalPreshowerDigisValidation*ecalSelectiveReadoutValidation) -ecalDigisValidationPhase2 = ecalDigisValidation.clone(EEdigiCollection=cms.InputTag("None"), ESdigiCollection=cms.InputTag("None")) -ecalDigisValidationSequencePhase2 = cms.Sequence(ecalDigisValidationPhase2*ecalBarrelDigisValidation) +from Validation.EcalDigis.ecalDigisValidationPh2_cfi import * +ecalDigisValidationSequencePhase2 = cms.Sequence(ecalDigisValidationPh2) + +from Configuration.Eras.Modifier_phase2_ecal_devel_cff import phase2_ecal_devel +def _modifyEcalForPh2(process): + process.load("SimCalorimetry.EcalSimProducers.esCATIAGainProducer_cfi") +modifyVal_Phase2Ecal = phase2_ecal_devel.makeProcessModifier(_modifyEcalForPh2) + +from Configuration.ProcessModifiers.premix_stage2_cff import premix_stage2 +(phase2_ecal_devel & premix_stage2).toModify(ecalDigisValidationPh2, digiCollection = 'mixData') diff --git a/Validation/EcalTriggerPrimitives/plugins/BuildFile.xml b/Validation/EcalTriggerPrimitives/plugins/BuildFile.xml new file mode 100644 index 0000000000000..f117b806063b5 --- /dev/null +++ b/Validation/EcalTriggerPrimitives/plugins/BuildFile.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/Validation/EcalTriggerPrimitives/plugins/EcalTPsValidationPh2.cc b/Validation/EcalTriggerPrimitives/plugins/EcalTPsValidationPh2.cc new file mode 100644 index 0000000000000..5526d80bc2e02 --- /dev/null +++ b/Validation/EcalTriggerPrimitives/plugins/EcalTPsValidationPh2.cc @@ -0,0 +1,144 @@ +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include "DQMServices/Core/interface/DQMEDAnalyzer.h" +#include "DQMServices/Core/interface/DQMStore.h" + +#include "DataFormats/EcalDigi/interface/EcalEBPhase2TriggerPrimitiveDigi.h" +#include "DataFormats/EcalDigi/interface/EcalDigiCollections.h" + +class EcalTPsValidationPh2 : public DQMEDAnalyzer { +public: + EcalTPsValidationPh2(const edm::ParameterSet& ps); + ~EcalTPsValidationPh2() override = default; + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); + void bookHistograms(DQMStore::IBooker& i, edm::Run const&, edm::EventSetup const&) override; + +protected: + void analyze(edm::Event const& event, edm::EventSetup const& eventSetup) override; + +private: + // match DataFormats/EcalDigi/src/EcalEBPhase2TriggerPrimitiveDigi.cc + static constexpr unsigned int kMaxSamples_ = 20; + + const edm::EDGetTokenT tpDigiCollectionToken_; + + MonitorElement* meTPDigisMultiplicity_; + MonitorElement* meTPDigiOccupancy_; + MonitorElement* meTPDigiSize_; + MonitorElement* meTPDigiEt_; + MonitorElement* meTPDigiSpike_; + MonitorElement* meTPDigiTime_; + MonitorElement* meTPDigiDebugFlag_; + MonitorElement* meTPDigiSOI_; + + MonitorElement* meTPSampleEt_[kMaxSamples_]; + MonitorElement* meTPSampleSpike_[kMaxSamples_]; + MonitorElement* meTPSampleTime_[kMaxSamples_]; +}; + +EcalTPsValidationPh2::EcalTPsValidationPh2(const edm::ParameterSet& ps) + : tpDigiCollectionToken_( + consumes(ps.getParameter("tpDigiCollection"))), + meTPDigisMultiplicity_(nullptr), + meTPDigiOccupancy_(nullptr), + meTPDigiSize_(nullptr), + meTPDigiEt_(nullptr), + meTPDigiSpike_(nullptr), + meTPDigiTime_(nullptr), + meTPDigiDebugFlag_(nullptr), + meTPDigiSOI_(nullptr) { + for (unsigned int i = 0; i < kMaxSamples_; ++i) { + meTPSampleEt_[i] = nullptr; + meTPSampleSpike_[i] = nullptr; + meTPSampleTime_[i] = nullptr; + } +} + +void EcalTPsValidationPh2::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + desc.add("tpDigiCollection", edm::InputTag("simEcalEBTriggerPrimitivePhase2Digis")); + descriptions.add("ecalTPsValidationPh2", desc); +} + +void EcalTPsValidationPh2::bookHistograms(DQMStore::IBooker& ibooker, edm::Run const&, edm::EventSetup const&) { + Char_t histo[200]; + + ibooker.setCurrentFolder("EcalDigisV/EcalTriggerPrimitivesTask"); + + sprintf(histo, "EcalTPDigiTask TP digis multiplicity"); + meTPDigisMultiplicity_ = ibooker.book1D(histo, histo, 613, 0, 61300); + + sprintf(histo, "EcalTPDigiTask TP digi occupancy"); + meTPDigiOccupancy_ = ibooker.book2D(histo, histo, 360, 0., 360., 170, -85., 85.); + + sprintf(histo, "EcalTPDigiTask TP digi size"); + meTPDigiSize_ = ibooker.book1D(histo, histo, kMaxSamples_, 0, kMaxSamples_); + + sprintf(histo, "EcalTPDigiTask TP digi encoded ET"); + meTPDigiEt_ = ibooker.book1D(histo, histo, 1025, -1, 1024); + + sprintf(histo, "EcalTPDigiTask TP digi spike flag"); + meTPDigiSpike_ = ibooker.book1D(histo, histo, 2, 0, 2); + + sprintf(histo, "EcalTPDigiTask TP digi time"); + meTPDigiTime_ = ibooker.book1D(histo, histo, 33, -1, 32); + + sprintf(histo, "EcalTPDigiTask TP digi debug flag"); + meTPDigiDebugFlag_ = ibooker.book1D(histo, histo, 2, 0, 2); + + sprintf(histo, "EcalTPDigiTask TP digi sample of interest"); + meTPDigiSOI_ = ibooker.book1D(histo, histo, kMaxSamples_ + 1, -1, kMaxSamples_); + + for (unsigned int i = 0; i < kMaxSamples_; ++i) { + sprintf(histo, "EcalTPDigiTask TP sample %02d encoded ET", i); + meTPSampleEt_[i] = ibooker.book1D(histo, histo, 1024, 0, 1024); + + sprintf(histo, "EcalTPDigiTask TP sample %02d spike flag", i); + meTPSampleSpike_[i] = ibooker.book1D(histo, histo, 2, 0, 2); + + sprintf(histo, "EcalTPDigiTask TP sample %02d time", i); + meTPSampleTime_[i] = ibooker.book1D(histo, histo, 32, 0, 32); + } +} + +void EcalTPsValidationPh2::analyze(edm::Event const& event, edm::EventSetup const& eventSetup) { + edm::Handle ecalTPDigis; + const EcalEBPhase2TrigPrimDigiCollection* tpDigis = nullptr; + + event.getByToken(tpDigiCollectionToken_, ecalTPDigis); + if (ecalTPDigis.isValid()) { + tpDigis = ecalTPDigis.product(); + + meTPDigisMultiplicity_->Fill(tpDigis->size()); + + // loop over TP digis + for (unsigned int tpDigiIdx = 0; tpDigiIdx < tpDigis->size(); ++tpDigiIdx) { + auto const& tpDigi = (*tpDigis)[tpDigiIdx]; + + const EBDetId ebid(tpDigi.id()); + meTPDigiOccupancy_->Fill(ebid.iphi(), ebid.ieta()); + + meTPDigiSize_->Fill(tpDigi.size()); + + meTPDigiEt_->Fill(tpDigi.encodedEt()); + meTPDigiSpike_->Fill(tpDigi.l1aSpike()); + meTPDigiTime_->Fill(tpDigi.time()); + meTPDigiDebugFlag_->Fill(tpDigi.isDebug()); + meTPDigiSOI_->Fill(tpDigi.sampleOfInterest()); + + // loop over TP digi samples + for (int sample = 0; sample < tpDigi.size(); ++sample) { + auto const tpSample = tpDigi[sample]; + meTPSampleEt_[sample]->Fill(tpSample.encodedEt()); + meTPSampleSpike_[sample]->Fill(tpSample.l1aSpike()); + meTPSampleTime_[sample]->Fill(tpSample.time()); + } + } + } +} + +DEFINE_FWK_MODULE(EcalTPsValidationPh2); diff --git a/Validation/EcalTriggerPrimitives/python/ecalTPsValidationSequence_cff.py b/Validation/EcalTriggerPrimitives/python/ecalTPsValidationSequence_cff.py new file mode 100644 index 0000000000000..eabf716f928e8 --- /dev/null +++ b/Validation/EcalTriggerPrimitives/python/ecalTPsValidationSequence_cff.py @@ -0,0 +1,6 @@ +import FWCore.ParameterSet.Config as cms + +ecalTPsValidationSequence = cms.Sequence() + +from Validation.EcalTriggerPrimitives.ecalTPsValidationPh2_cfi import * +ecalTPsValidationSequencePhase2 = cms.Sequence(ecalTPsValidationPh2) From fdba5743f26eb1af8e9a4d9003cddf50a8efa9dd Mon Sep 17 00:00:00 2001 From: Thomas Reis Date: Mon, 6 Jul 2026 12:21:02 +0200 Subject: [PATCH 2/4] Implement review comments. --- .../plugins/EcalDigisValidationPh2.cc | 51 ++++++++++--------- .../plugins/EcalTPsValidationPh2.cc | 27 +++++----- 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc b/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc index 7cd88021b943f..90ca6993249e4 100644 --- a/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc +++ b/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc @@ -20,11 +20,13 @@ #include "SimDataFormats/CrossingFrame/interface/CrossingFrame.h" #include "SimDataFormats/CrossingFrame/interface/MixCollection.h" +#include +#include #include #include class EcalDigisValidationPh2 : public DQMEDAnalyzer { - typedef std::map > MapType; + typedef std::map MapType; public: EcalDigisValidationPh2(const edm::ParameterSet& ps); @@ -105,61 +107,59 @@ void EcalDigisValidationPh2::fillDescriptions(edm::ConfigurationDescriptions& de } void EcalDigisValidationPh2::bookHistograms(DQMStore::IBooker& ibooker, edm::Run const&, edm::EventSetup const&) { - Char_t histo[200]; - ibooker.setCurrentFolder("EcalDigisV/EcalDigiTask"); - sprintf(histo, "EcalDigiTask Gun Momentum"); + std::string histo("EcalDigiTask Gun Momentum"); meGunEnergy_ = ibooker.book1D(histo, histo, 100, 0., 1000.); - sprintf(histo, "EcalDigiTask Gun Eta"); + histo = "EcalDigiTask Gun Eta"; meGunEta_ = ibooker.book1D(histo, histo, 700, -3.5, 3.5); - sprintf(histo, "EcalDigiTask Gun Phi"); + histo = "EcalDigiTask Gun Phi"; meGunPhi_ = ibooker.book1D(histo, histo, 360, 0., 360.); - sprintf(histo, "EcalDigiTask maximum Digi over Sim ratio"); + histo = "EcalDigiTask maximum Digi over Sim ratio"; meDigiSimRatio_ = ibooker.book1D(histo, histo, 100, 0., 2.); - sprintf(histo, "EcalDigiTask maximum Digi over Sim ratio gt 10 ADC"); + histo = "EcalDigiTask maximum Digi over Sim ratio gt 10 ADC"; meDigiSimRatiogt10ADC_ = ibooker.book1D(histo, histo, 100, 0., 2.); - sprintf(histo, "EcalDigiTask maximum Digi over Sim ratio gt 100 ADC"); + histo = "EcalDigiTask maximum Digi over Sim ratio gt 100 ADC"; meDigiSimRatiogt100ADC_ = ibooker.book1D(histo, histo, 100, 0., 2.); - sprintf(histo, "EcalDigiTask occupancy"); + histo = "EcalDigiTask occupancy"; meDigiOccupancy_ = ibooker.book2D(histo, histo, 360, 0., 360., 170, -85., 85.); - sprintf(histo, "EcalDigiTask digis multiplicity"); + histo = "EcalDigiTask digis multiplicity"; meDigiMultiplicity_ = ibooker.book1D(histo, histo, 612, 0., 61200); - sprintf(histo, "EcalDigiTask global pulse shape"); + histo = "EcalDigiTask global pulse shape"; meDigiADCGlobal_ = ibooker.bookProfile(histo, histo, kMaxSamples_, 0, kMaxSamples_, 10000, 0., 1000.); for (int i = 0; i < kMaxSamples_; ++i) { - sprintf(histo, "EcalDigiTask analog pulse %02d", i + 1); + histo = std::format("EcalDigiTask analog pulse {:02d}", i + 1); meDigiADCAnalog_[i] = ibooker.book1D(histo, histo, 4000, 0., 400.); - sprintf(histo, "EcalDigiTask ADC pulse %02d Gain 10", i + 1); + histo = std::format("EcalDigiTask ADC pulse {:02d} Gain 10", i + 1); meDigiADCg10_[i] = ibooker.book1D(histo, histo, 4096, -0.5, 4095.5); - sprintf(histo, "EcalDigiTask ADC pulse %02d Gain 1", i + 1); + histo = std::format("EcalDigiTask ADC pulse {:02d} Gain 1", i + 1); meDigiADCg1_[i] = ibooker.book1D(histo, histo, 4096, -0.5, 4095.5); - sprintf(histo, "EcalDigiTask gain pulse %02d", i + 1); + histo = std::format("EcalDigiTask gain pulse {:02d}", i + 1); meDigiGain_[i] = ibooker.book1D(histo, histo, 2, 0, 2); } - sprintf(histo, "EcalDigiTask pedestal for pre-sample"); + histo = "EcalDigiTask pedestal for pre-sample"; mePedestal_ = ibooker.book1D(histo, histo, 4096, -0.5, 4095.5); - sprintf(histo, "EcalDigiTask maximum position gt 10 ADC"); + histo = "EcalDigiTask maximum position gt 10 ADC"; meMaximumgt10ADC_ = ibooker.book1D(histo, histo, kMaxSamples_, 0., static_cast(kMaxSamples_)); - sprintf(histo, "EcalDigiTask maximum position gt 100 ADC"); + histo = "EcalDigiTask maximum position gt 100 ADC"; meMaximumgt100ADC_ = ibooker.book1D(histo, histo, kMaxSamples_, 0., static_cast(kMaxSamples_)); - sprintf(histo, "EcalDigiTask ADC counts after gain switch"); + histo = "EcalDigiTask ADC counts after gain switch"; menADCafterSwitch_ = ibooker.book1D(histo, histo, kMaxSamples_, 0., static_cast(kMaxSamples_)); } @@ -297,14 +297,15 @@ void EcalDigisValidationPh2::analyze(edm::Event const& event, edm::EventSetup co meDigiADCGlobal_->Fill(sample, ebAnalogSignal[sample]); } - if (ebSimMap[ebid.rawId()] != 0.) { - LogDebug("DigiInfo") << " Digi / Hit = " << Erec << " / " << ebSimMap[ebid.rawId()] << " gainConv " + auto const simHit = ebSimMap.find(ebid.rawId()); + if (simHit != ebSimMap.end() && simHit->second != 0.) { + LogDebug("DigiInfo") << " Digi / Hit = " << Erec << " / " << simHit->second << " gainConv " << gainConv[pmaxGainId]; - meDigiSimRatio_->Fill(Erec / ebSimMap[ebid.rawId()]); + meDigiSimRatio_->Fill(Erec / simHit->second); if (Erec > 10. * adcToGeV) { - meDigiSimRatiogt10ADC_->Fill(Erec / ebSimMap[ebid.rawId()]); + meDigiSimRatiogt10ADC_->Fill(Erec / simHit->second); if (Erec > 100. * adcToGeV) - meDigiSimRatiogt100ADC_->Fill(Erec / ebSimMap[ebid.rawId()]); + meDigiSimRatiogt100ADC_->Fill(Erec / simHit->second); } } diff --git a/Validation/EcalTriggerPrimitives/plugins/EcalTPsValidationPh2.cc b/Validation/EcalTriggerPrimitives/plugins/EcalTPsValidationPh2.cc index 5526d80bc2e02..809ed71256df6 100644 --- a/Validation/EcalTriggerPrimitives/plugins/EcalTPsValidationPh2.cc +++ b/Validation/EcalTriggerPrimitives/plugins/EcalTPsValidationPh2.cc @@ -9,6 +9,9 @@ #include "DataFormats/EcalDigi/interface/EcalEBPhase2TriggerPrimitiveDigi.h" #include "DataFormats/EcalDigi/interface/EcalDigiCollections.h" +#include +#include + class EcalTPsValidationPh2 : public DQMEDAnalyzer { public: EcalTPsValidationPh2(const edm::ParameterSet& ps); @@ -65,42 +68,40 @@ void EcalTPsValidationPh2::fillDescriptions(edm::ConfigurationDescriptions& desc } void EcalTPsValidationPh2::bookHistograms(DQMStore::IBooker& ibooker, edm::Run const&, edm::EventSetup const&) { - Char_t histo[200]; - ibooker.setCurrentFolder("EcalDigisV/EcalTriggerPrimitivesTask"); - sprintf(histo, "EcalTPDigiTask TP digis multiplicity"); + std::string histo("EcalTPDigiTask TP digis multiplicity"); meTPDigisMultiplicity_ = ibooker.book1D(histo, histo, 613, 0, 61300); - sprintf(histo, "EcalTPDigiTask TP digi occupancy"); + histo = "EcalTPDigiTask TP digi occupancy"; meTPDigiOccupancy_ = ibooker.book2D(histo, histo, 360, 0., 360., 170, -85., 85.); - sprintf(histo, "EcalTPDigiTask TP digi size"); + histo = "EcalTPDigiTask TP digi size"; meTPDigiSize_ = ibooker.book1D(histo, histo, kMaxSamples_, 0, kMaxSamples_); - sprintf(histo, "EcalTPDigiTask TP digi encoded ET"); + histo = "EcalTPDigiTask TP digi encoded ET"; meTPDigiEt_ = ibooker.book1D(histo, histo, 1025, -1, 1024); - sprintf(histo, "EcalTPDigiTask TP digi spike flag"); + histo = "EcalTPDigiTask TP digi spike flag"; meTPDigiSpike_ = ibooker.book1D(histo, histo, 2, 0, 2); - sprintf(histo, "EcalTPDigiTask TP digi time"); + histo = "EcalTPDigiTask TP digi time"; meTPDigiTime_ = ibooker.book1D(histo, histo, 33, -1, 32); - sprintf(histo, "EcalTPDigiTask TP digi debug flag"); + histo = "EcalTPDigiTask TP digi debug flag"; meTPDigiDebugFlag_ = ibooker.book1D(histo, histo, 2, 0, 2); - sprintf(histo, "EcalTPDigiTask TP digi sample of interest"); + histo = "EcalTPDigiTask TP digi sample of interest"; meTPDigiSOI_ = ibooker.book1D(histo, histo, kMaxSamples_ + 1, -1, kMaxSamples_); for (unsigned int i = 0; i < kMaxSamples_; ++i) { - sprintf(histo, "EcalTPDigiTask TP sample %02d encoded ET", i); + histo = std::format("EcalTPDigiTask TP sample {:02d} encoded ET", i); meTPSampleEt_[i] = ibooker.book1D(histo, histo, 1024, 0, 1024); - sprintf(histo, "EcalTPDigiTask TP sample %02d spike flag", i); + histo = std::format("EcalTPDigiTask TP sample {:02d} spike flag", i); meTPSampleSpike_[i] = ibooker.book1D(histo, histo, 2, 0, 2); - sprintf(histo, "EcalTPDigiTask TP sample %02d time", i); + histo = std::format("EcalTPDigiTask TP sample {:02d} time", i); meTPSampleTime_[i] = ibooker.book1D(histo, histo, 32, 0, 32); } } From 977f132923e84862528af1a97b9420dbf7ca097e Mon Sep 17 00:00:00 2001 From: Thomas Reis Date: Tue, 7 Jul 2026 14:46:29 +0200 Subject: [PATCH 3/4] Fix gain conversion factors for Phase 2 ECAL digi validation. --- Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc b/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc index 90ca6993249e4..6439647b51eed 100644 --- a/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc +++ b/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc @@ -20,6 +20,7 @@ #include "SimDataFormats/CrossingFrame/interface/CrossingFrame.h" #include "SimDataFormats/CrossingFrame/interface/MixCollection.h" +#include #include #include #include @@ -227,7 +228,8 @@ void EcalDigisValidationPh2::analyze(edm::Event const& event, edm::EventSetup co // get conditions auto const adcToGeV = eventSetup.getData(adcToGeVToken_).getEBValue(); auto const& gainRatios = eventSetup.getData(gainRatiosToken_); - std::array gainConv = {10., 1.}; + // The nominal CATIA gains are 10 and 1 when the gain bit is 0 and 1, respectively + std::array gainConv = {1., 10.}; meDigiMultiplicity_->Fill(digis->size()); @@ -240,7 +242,7 @@ void EcalDigisValidationPh2::analyze(edm::Event const& event, edm::EventSetup co meDigiOccupancy_->Fill(ebid.iphi(), ebid.ieta()); - gainConv[0] = gainRatios[ebid]; + gainConv[1] = gainRatios[ebid]; double emax = 0.; int pmax = 0; From 4d1a7522d125b9204478a61dab7685c2260eb8ff Mon Sep 17 00:00:00 2001 From: Thomas Reis Date: Wed, 8 Jul 2026 09:37:55 +0200 Subject: [PATCH 4/4] Use std::abs instead of abs. --- Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc b/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc index 6439647b51eed..124002065491c 100644 --- a/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc +++ b/Validation/EcalDigis/plugins/EcalDigisValidationPh2.cc @@ -21,6 +21,7 @@ #include "SimDataFormats/CrossingFrame/interface/MixCollection.h" #include +#include #include #include #include @@ -197,7 +198,7 @@ void EcalDigisValidationPh2::analyze(edm::Event const& event, edm::EventSetup co auto hphi = (*p)->momentum().phi(); hphi = (hphi >= 0) ? hphi : hphi + 2 * M_PI; hphi = hphi / M_PI * 180.; - LogDebug("EventInfo") << "Particle gun type form MC = " << abs((*p)->pdg_id()) << "\n" + LogDebug("EventInfo") << "Particle gun type form MC = " << std::abs((*p)->pdg_id()) << "\n" << "Energy = " << (*p)->momentum().e() << " Eta = " << heta << " Phi = " << hphi; meGunEnergy_->Fill(theGunEnergy);