diff --git a/Configuration/PyReleaseValidation/README.md b/Configuration/PyReleaseValidation/README.md index ea343404fa59e..ddfb587ac4614 100644 --- a/Configuration/PyReleaseValidation/README.md +++ b/Configuration/PyReleaseValidation/README.md @@ -97,6 +97,8 @@ The offsets currently in use are: * 0.31: Photon energy corrections with DRN architecture * 0.61: ECAL `phase2_ecal_devel` era, on CPU * 0.612: ECAL `phase2_ecal_devel` era, with automatic offload to GPU if available +* 0.6199: ECAL `phase2_ecal_devel` era, on CPU and with premixing stage1+stage2 +* 0.61299: ECAL `phase2_ecal_devel` era, with automatic offload to GPU if available and premixing stage1+stage2 * 0.631: ECAL component-method based digis * 0.632: ECAL component-method based finely-sampled waveforms * 0.633: ECAL phase2 Trigger Primitive diff --git a/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py b/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py index 247d9b172657e..7b848ee27f270 100644 --- a/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py +++ b/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py @@ -2294,8 +2294,9 @@ def __init__(self, digi = {}, reco = {}, harvest = {}, **kwargs): self.__harvest = harvest def setup_(self, step, stepName, stepDict, k, properties): + # run the ECAL devel modules and the Phase 2 ECAL TP + mods = {'--era': stepDict[step][k]['--era']+',phase2_ecal_devel,phase2_ecalTP_devel'} # temporarily remove trigger & downstream steps - mods = {'--era': stepDict[step][k]['--era']+',phase2_ecal_devel'} if 'Digi' in step: mods['-s'] = 'DIGI:pdigi_valid,DIGI2RAW' mods['--custom_conditions'] = 'EcalSimPulseShapePhaseII,EcalSimPulseShapeRcd,frontier://FrontierProd/CMS_CONDITIONS' @@ -2333,71 +2334,108 @@ def condition(self, fragment, stepList, key, hasHarvest): offset = 0.612, ) -# Offline HGCAL NanoAOD workflows -class UpgradeWorkflow_HGCALNano(UpgradeWorkflow): +# ECAL Phase 2 workflow with Alpaka reconstruction and PU from premix +class UpgradeWorkflowPremix_ecalDevel(UpgradeWorkflow): + def __init__(self, digi = {}, reco = {}, harvest = {}, **kwargs): + # adapt the parameters for the UpgradeWorkflow init method + super(UpgradeWorkflowPremix_ecalDevel, self).__init__( + steps = [], + PU = [ + 'GenSimHLBeamSpot14', + 'DigiTrigger', + 'RecoGlobal', + 'RecoGlobalFakeHLT', + 'HARVESTGlobal', + 'HARVESTGlobalFakeHLT', + 'ALCAPhase2', + ], + **kwargs) + self.__digi = digi + self.__reco = reco + self.__harvest = harvest def setup_(self, step, stepName, stepDict, k, properties): - if 'RecoGlobal' in step: - stepDict[stepName][k] = merge([self.step3, stepDict[step][k]]) - else: - stepDict[stepName][k] = merge([stepDict[step][k]]) + # just copy steps + stepDict[stepName][k] = merge([stepDict[step][k]]) + def setupPU_(self, step, stepName, stepDict, k, properties): + # setup for stage 1 + if "GenSim" in stepName: + stepNamePmx = stepName.replace('GenSim','Premix') + if not stepNamePmx in stepDict: stepDict[stepNamePmx] = {} + stepDict[stepNamePmx][k] = merge([ + { + '-s': 'GEN,SIM,DIGI:pdigi_valid', + '--era': stepDict[step][k]['--era']+',phase2_ecal_devel,phase2_ecalTP_devel', + '--datatier': 'PREMIX', + '--eventcontent': 'PREMIX', + '--procModifiers': 'premix_stage1', + '--custom_conditions': 'EcalSimPulseShapePhaseII,EcalSimPulseShapeRcd,frontier://FrontierProd/CMS_CONDITIONS' + }, + stepDict[stepName][k] + ]) + # setup for stage 2 + elif 'Digi' in step or 'Reco' in step: + # run the ECAL devel modules and the Phase 2 ECAL TP + mods = {'--era': stepDict[step][k]['--era']+',phase2_ecal_devel,phase2_ecalTP_devel'} + # temporarily remove trigger & downstream steps + if 'Digi' in step: + mods['-s'] = 'DIGI:pdigi_valid,DATAMIX,DIGI2RAW' + mods['--datamix'] = 'PreMix' + mods['--custom_conditions'] = 'EcalSimPulseShapePhaseII,EcalSimPulseShapeRcd,frontier://FrontierProd/CMS_CONDITIONS' + mods['--filein'] = 'file:step1.root' + mods['--pileup_input'] = 'file:step2.root' + mods |= self.__digi + mods['--procModifiers'] = mods['--procModifiers']+',premix_stage2' if '--procModifiers' in mods else 'premix_stage2' + elif 'Reco' in step: + mods['-s'] = 'RAW2DIGI:RawToDigi_ecalOnly,RECO:reconstruction_ecalOnly,VALIDATION:@ecalOnlyValidation,DQM:@ecalOnly' + mods['--datatier'] = 'GEN-SIM-RECO,DQMIO' + mods['--eventcontent'] = 'FEVTDEBUGHLT,DQM' + mods['--custom_conditions'] = 'EcalSimPulseShapePhaseII,EcalSimPulseShapeRcd,frontier://FrontierProd/CMS_CONDITIONS' + mods |= self.__reco + mods['--procModifiers'] = mods['--procModifiers']+',premix_stage2' if '--procModifiers' in mods else 'premix_stage2' + stepDict[stepName][k] = merge([mods, stepDict[step][k]]) + if 'HARVEST' in stepName: + # run the ECAL devel modules and the Phase 2 ECAL TP + mods = {'--era': stepDict[step][k]['--era']+',phase2_ecal_devel,phase2_ecalTP_devel'} + mods['-s'] = 'HARVESTING:@ecalOnlyValidation+@ecal' + mods |= self.__harvest + stepDict[stepName][k] = merge([mods, stepDict[step][k]]) + # skip ALCA step + if 'ALCA' in step: + stepDict[stepName][k] = None def condition(self, fragment, stepList, key, hasHarvest): - # Apply to all Run4 workflows - return 'Run4' in key - -upgradeWFs['HGCALNano'] = UpgradeWorkflow_HGCALNano( - steps = [ - 'RecoGlobal', - 'HARVESTGlobal', - 'ALCAPhase2', - ], - PU = [ - 'RecoGlobal', - 'HARVESTGlobal', - 'ALCAPhase2', - ], - suffix = '_HGCALNano', - offset = 0.212, -) - -upgradeWFs['HGCALNano'].step3 = { - '-s': 'RAW2DIGI,RECO,RECOSIM,PAT,NANO:@HGCAL,VALIDATION:@phase2Validation+@miniAODValidation,DQM:@phase2+@miniAODDQM', - '--datatier': 'GEN-SIM-RECO,MINIAODSIM,DQMIO,NANOAODSIM', - '--eventcontent': 'FEVTDEBUGHLT,MINIAODSIM,DQM,NANOAODSIM' -} - -# Offline HGCAL NanoAOD with validation objects -class UpgradeWorkflow_HGCALNanoVal(UpgradeWorkflow): - def setup_(self, step, stepName, stepDict, k, properties): - if 'RecoGlobal' in step: - stepDict[stepName][k] = merge([self.step3, stepDict[step][k]]) - else: - stepDict[stepName][k] = merge([stepDict[step][k]]) + if not 'PU' in key: + return False + return any([f in fragment for f in [ + "SingleElectron", + "SingleEFlat", + "SingleGamma", + "CloseByPGun_Barrel_Front", + "TTbar_14TeV", + "ZEE_14", + "DYToLL_M_50_14TeV", + "H125GGgluonfusion_14" + ]]) and not 'Eta1p7_2p7' in fragment and 'Run4' in key - def condition(self, fragment, stepList, key, hasHarvest): - # Apply to all Run4 workflows - return 'Run4' in key + def workflow_(self, workflows, num, fragment, stepList, key): + fragmentTmp = fragment + super(UpgradeWorkflowPremix_ecalDevel,self).workflow_(workflows, num, fragmentTmp, stepList, key) -upgradeWFs['HGCALNanoVal'] = UpgradeWorkflow_HGCALNanoVal( - steps = [ - 'RecoGlobal', - 'HARVESTGlobal', - 'ALCAPhase2', - ], - PU = [ - 'RecoGlobal', - 'HARVESTGlobal', - 'ALCAPhase2', - ], - suffix = '_HGCALNanoVal', - offset = 0.213, +# ECAL developemnt workflow on CPU with premix combined stage1+stage2 +upgradeWFs['ecalDevelPMXS1S2'] = UpgradeWorkflowPremix_ecalDevel( + suffix = '_ecalDevelPMXS1S2', + offset = 0.6199, ) -upgradeWFs['HGCALNanoVal'].step3 = { - '-s': 'RAW2DIGI,RECO,RECOSIM,PAT,NANO:@HGCALVal,VALIDATION:@phase2Validation+@miniAODValidation,DQM:@phase2+@miniAODDQM', - '--datatier': 'GEN-SIM-RECO,MINIAODSIM,DQMIO,NANOAODSIM', - '--eventcontent': 'FEVTDEBUGHLT,MINIAODSIM,DQM,NANOAODSIM' -} +# ECAL developemnt Alpaka workflow with premix combined stage1+stage2 +upgradeWFs['ecalDevelAlpakaPMXS1S2'] = UpgradeWorkflowPremix_ecalDevel( + reco = { + '--procModifiers': 'alpaka', + '--customise' : 'HeterogeneousCore/AlpakaServices/customiseAlpakaServiceMemoryFilling.customiseAlpakaServiceMemoryFilling' + }, + suffix = '_ecalDevelAlpakaPMXS1S2', + offset = 0.61299, +) # ECAL component class UpgradeWorkflow_ECalComponent(UpgradeWorkflow): @@ -2488,6 +2526,72 @@ def condition(self, fragment, stepList, key, hasHarvest): ecalMod = 'ecal_component_finely_sampled_waveforms', ) +# Offline HGCAL NanoAOD workflows +class UpgradeWorkflow_HGCALNano(UpgradeWorkflow): + def setup_(self, step, stepName, stepDict, k, properties): + if 'RecoGlobal' in step: + stepDict[stepName][k] = merge([self.step3, stepDict[step][k]]) + else: + stepDict[stepName][k] = merge([stepDict[step][k]]) + + def condition(self, fragment, stepList, key, hasHarvest): + # Apply to all Run4 workflows + return 'Run4' in key + +upgradeWFs['HGCALNano'] = UpgradeWorkflow_HGCALNano( + steps = [ + 'RecoGlobal', + 'HARVESTGlobal', + 'ALCAPhase2', + ], + PU = [ + 'RecoGlobal', + 'HARVESTGlobal', + 'ALCAPhase2', + ], + suffix = '_HGCALNano', + offset = 0.212, +) + +upgradeWFs['HGCALNano'].step3 = { + '-s': 'RAW2DIGI,RECO,RECOSIM,PAT,NANO:@HGCAL,VALIDATION:@phase2Validation+@miniAODValidation,DQM:@phase2+@miniAODDQM', + '--datatier': 'GEN-SIM-RECO,MINIAODSIM,DQMIO,NANOAODSIM', + '--eventcontent': 'FEVTDEBUGHLT,MINIAODSIM,DQM,NANOAODSIM' +} + +# Offline HGCAL NanoAOD with validation objects +class UpgradeWorkflow_HGCALNanoVal(UpgradeWorkflow): + def setup_(self, step, stepName, stepDict, k, properties): + if 'RecoGlobal' in step: + stepDict[stepName][k] = merge([self.step3, stepDict[step][k]]) + else: + stepDict[stepName][k] = merge([stepDict[step][k]]) + + def condition(self, fragment, stepList, key, hasHarvest): + # Apply to all Run4 workflows + return 'Run4' in key + +upgradeWFs['HGCALNanoVal'] = UpgradeWorkflow_HGCALNanoVal( + steps = [ + 'RecoGlobal', + 'HARVESTGlobal', + 'ALCAPhase2', + ], + PU = [ + 'RecoGlobal', + 'HARVESTGlobal', + 'ALCAPhase2', + ], + suffix = '_HGCALNanoVal', + offset = 0.213, +) + +upgradeWFs['HGCALNanoVal'].step3 = { + '-s': 'RAW2DIGI,RECO,RECOSIM,PAT,NANO:@HGCALVal,VALIDATION:@phase2Validation+@miniAODValidation,DQM:@phase2+@miniAODDQM', + '--datatier': 'GEN-SIM-RECO,MINIAODSIM,DQMIO,NANOAODSIM', + '--eventcontent': 'FEVTDEBUGHLT,MINIAODSIM,DQM,NANOAODSIM' +} + class UpgradeWorkflow_0T(UpgradeWorkflow): def setup_(self, step, stepName, stepDict, k, properties): myGT=stepDict[step][k]['--conditions'] diff --git a/RecoLocalCalo/EcalRecProducers/python/ecalUncalibRecHitPhase2_cff.py b/RecoLocalCalo/EcalRecProducers/python/ecalUncalibRecHitPhase2_cff.py index 3766573b0ddc1..d83314fafbfb0 100644 --- a/RecoLocalCalo/EcalRecProducers/python/ecalUncalibRecHitPhase2_cff.py +++ b/RecoLocalCalo/EcalRecProducers/python/ecalUncalibRecHitPhase2_cff.py @@ -42,3 +42,10 @@ # Convert the uncalibrated rechits from Portable Collection to legacy format ecalUncalibRecHitPhase2 )) + +# Get the digis from the mixing module for premixing +from Configuration.Eras.Modifier_phase2_ecal_devel_cff import phase2_ecal_devel +from Configuration.ProcessModifiers.premix_stage2_cff import premix_stage2 +(phase2_ecal_devel & premix_stage2 & ~alpaka).toModify(ecalUncalibRecHitPhase2, BarrelDigis = 'mixData') +(phase2_ecal_devel & premix_stage2).toModify(ecalUncalibRecHitPhase2Legacy, BarrelDigis = 'mixData') +(phase2_ecal_devel & premix_stage2).toModify(simEcalUnsuppressedDigisSoA, BarrelDigis = 'mixData') diff --git a/SimCalorimetry/Configuration/python/SimCalorimetry_EventContent_cff.py b/SimCalorimetry/Configuration/python/SimCalorimetry_EventContent_cff.py index ae1ff68357822..6c4403a4101ee 100644 --- a/SimCalorimetry/Configuration/python/SimCalorimetry_EventContent_cff.py +++ b/SimCalorimetry/Configuration/python/SimCalorimetry_EventContent_cff.py @@ -52,7 +52,15 @@ run3_ecal_devel.toModify(SimCalorimetryRAW.outputCommands, func=lambda outputCommands: outputCommands.append('keep EBDigiCollection_simEcalUnsuppressedDigis_*_*') ) from Configuration.Eras.Modifier_phase2_ecal_devel_cff import phase2_ecal_devel -phase2_ecal_devel.toModify(SimCalorimetryFEVTDEBUG.outputCommands, func=lambda outputCommands: outputCommands.append('keep *_ecal*_*_*') ) +_phase2_ecal_extraCommands = cms.PSet( # using PSet in order to potentially customize with Modifier + v = cms.vstring('drop EBDigiCollection_*_*_*', 'drop EEDigiCollection_*_*_*', 'drop ESDigiCollection_*_*_*', 'keep *_simEcalUnsuppressedDigis_*_*', 'keep *_ecal*_*_*'), +) +phase2_ecal_devel.toModify(SimCalorimetryFEVTDEBUG, outputCommands = SimCalorimetryFEVTDEBUG.outputCommands + _phase2_ecal_extraCommands.v) +phase2_ecal_devel.toModify(SimCalorimetryPREMIX, outputCommands = SimCalorimetryPREMIX.outputCommands + _phase2_ecal_extraCommands.v) +phase2_ecal_devel.toModify(SimCalorimetryRAW, outputCommands = SimCalorimetryRAW.outputCommands + _phase2_ecal_extraCommands.v) + +from Configuration.ProcessModifiers.premix_stage2_cff import premix_stage2 +premix_stage2.toModify( SimCalorimetryFEVTDEBUG.outputCommands, func=lambda outputCommands: outputCommands.append('keep EBDigiCollectionPh2_mixData_*_*') ) from Configuration.Eras.Modifier_phase2_hcal_cff import phase2_hcal phase2_hcal.toModify(SimCalorimetryFEVTDEBUG.outputCommands, func=lambda outputCommands: outputCommands.append('keep *_DMHcalDigis_*_*') ) @@ -78,7 +86,6 @@ v = cms.vstring('keep *_simHGCalUnsuppressedDigis_EE_*', 'keep *_simHGCalUnsuppressedDigis_HEfront_*', 'keep *_simHGCalUnsuppressedDigis_HEback_*', 'keep *_mix_MergedCaloTruth*_*', 'keep *_mix_MergedMtdTruth_*', 'keep *_mix_MergedMtdTruthLC_*', 'keep *_mix_MergedMtdTruthST_*'), ) # For phase2 premixing switch the sim digi collections to the ones including pileup -from Configuration.ProcessModifiers.premix_stage2_cff import premix_stage2 premix_stage2.toModify(_phase2_hgc_extraCommands, v = ['keep *_mixData_HGCDigisEE_*', 'keep *_mixData_HGCDigisHEfront_*', 'keep *_mixData_HGCDigisHEback_*', 'keep *_mixData_MergedCaloTruth*_*', 'keep *_mix_MergedMtdTruth_*', 'keep *_mixData_MergedMtdTruthLC_*', 'keep *_mix_MergedMtdTruthST_*']) phase2_hgcal.toModify( SimCalorimetryRAW, outputCommands = SimCalorimetryRAW.outputCommands + _phase2_hgc_extraCommands.v ) diff --git a/SimCalorimetry/EcalEBTrigPrimProducers/python/ecalEBTriggerPrimitivePhase2Digis_cfi.py b/SimCalorimetry/EcalEBTrigPrimProducers/python/ecalEBTriggerPrimitivePhase2Digis_cfi.py index fd567eac36e9c..872732538d30c 100644 --- a/SimCalorimetry/EcalEBTrigPrimProducers/python/ecalEBTriggerPrimitivePhase2Digis_cfi.py +++ b/SimCalorimetry/EcalEBTrigPrimProducers/python/ecalEBTriggerPrimitivePhase2Digis_cfi.py @@ -14,4 +14,6 @@ from Configuration.Eras.Modifier_phase2_ecalTP_devel_cff import phase2_ecalTP_devel +from Configuration.ProcessModifiers.premix_stage2_cff import premix_stage2 phase2_ecalTP_devel.toModify( simEcalEBTriggerPrimitivePhase2Digis) +(phase2_ecalTP_devel & premix_stage2).toModify(simEcalEBTriggerPrimitivePhase2Digis, barrelEcalDigis = 'mixData') diff --git a/SimCalorimetry/EcalSimAlgos/interface/EcalSignalGeneratorPh2.h b/SimCalorimetry/EcalSimAlgos/interface/EcalSignalGeneratorPh2.h new file mode 100644 index 0000000000000..23483bf114453 --- /dev/null +++ b/SimCalorimetry/EcalSimAlgos/interface/EcalSignalGeneratorPh2.h @@ -0,0 +1,110 @@ +#ifndef SimCalorimetry_EcalSimAlgos_EcalSignalGeneratorPh2_h +#define SimCalorimetry_EcalSimAlgos_EcalSignalGeneratorPh2_h + +#include "FWCore/Framework/interface/ConsumesCollector.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventPrincipal.h" +#include "FWCore/Framework/interface/RunPrincipal.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "DataFormats/Common/interface/Handle.h" +#include "DataFormats/EcalDetId/interface/EBDetId.h" +#include "DataFormats/EcalDigi/interface/EcalConstants.h" +#include "DataFormats/EcalDigi/interface/EcalDigiCollections.h" +#include "CalibFormats/CaloObjects/interface/CaloTSamples.h" +#include "CondFormats/DataRecord/interface/EcalADCToGeVConstantRcd.h" +#include "CondFormats/DataRecord/interface/EcalCATIAGainRatiosRcd.h" +#include "CondFormats/DataRecord/interface/EcalIntercalibConstantsMCRcd.h" +#include "CondFormats/EcalObjects/interface/EcalADCToGeVConstant.h" +#include "CondFormats/EcalObjects/interface/EcalCATIAGainRatios.h" +#include "CondFormats/EcalObjects/interface/EcalIntercalibConstantsMC.h" +#include "SimCalorimetry/EcalSimAlgos/interface/EcalBaseSignalGenerator.h" +#include "SimCalorimetry/EcalSimAlgos/interface/EcalDigitizerTraits.h" + +// needed for LC'/LC correction for time dependent MC +#include "CalibCalorimetry/EcalLaserCorrection/interface/EcalLaserDbService.h" +#include "CalibCalorimetry/EcalLaserCorrection/interface/EcalLaserDbRecord.h" +#include "CalibCalorimetry/EcalLaserCorrection/interface/EcalLaserDbRecordMC.h" + +/** Converts digis back into analog signals, to be used + * as noise + */ + +namespace edm { + class ModuleCallingContext; +} + +template +class EcalSignalGeneratorPh2 : public EcalBaseSignalGenerator { +public: + typedef typename ECALDIGITIZERTRAITS::Digi DIGI; + typedef typename ECALDIGITIZERTRAITS::DigiCollection COLLECTION; + + typedef std::unordered_map CalibCache; + + EcalSignalGeneratorPh2() : EcalBaseSignalGenerator() {} + EcalSignalGeneratorPh2(const EcalSignalGeneratorPh2&) = delete; + EcalSignalGeneratorPh2& operator=(const EcalSignalGeneratorPh2&) = delete; + + EcalSignalGeneratorPh2(edm::ConsumesCollector& cc, + const edm::InputTag& inputTag, + const double ebs25notCont, + const double peToA, + const bool timeDependent = false); + + ~EcalSignalGeneratorPh2() override = default; + + void initializeEvent(const edm::Event* event, const edm::EventSetup* eventSetup); + /// some users use EventPrincipals, not Events. We support both + void initializeEvent(const edm::EventPrincipal* eventPrincipal, const edm::EventSetup* eventSetup); + + virtual void fill(edm::ModuleCallingContext const* mcc); + +private: + inline bool validDigi(const DIGI& digi) { + for (int id = 0; id < digi.size(); ++id) { + if (digi[id].adc() > 0) { + return true; + } + } + return false; + } + + void fillNoiseSignals() override {} + void fillNoiseSignals(CLHEP::HepRandomEngine*) override {} + + CaloSamples samplesInPE(const DIGI& digi); + + const edm::ESGetToken gainRatiosToken_; + const edm::ESGetToken interCalibConstantsMCToken_; + const edm::ESGetToken adcToGeVConstantToken_; + edm::ESGetToken laserDbToken_; + edm::ESGetToken laserDbMCToken_; + + /// these fields are set in initializeEvent() + const edm::Event* theEvent_; + const edm::EventPrincipal* theEventPrincipal_; + + const EcalCATIAGainRatios* gainRatios_; + + /// these come from the ParameterSet + const edm::InputTag theInputTag_; + const edm::EDGetTokenT tok_; + + const double ebs25notCont_; + const double peToA_; + + double maxEne_; // max attainable energy in the ecal barrel + + const EcalIntercalibConstantsMC* ical_; + + const bool timeDependent_; + edm::TimeValue_t iTime_; + CalibCache valueLCCache_LC_; + CalibCache valueLCCache_LC_prime_; + const EcalLaserDbService* lasercals_; + const EcalLaserDbService* lasercals_prime_; +}; + +typedef EcalSignalGeneratorPh2 EBSignalGeneratorPh2; +#endif diff --git a/SimCalorimetry/EcalSimAlgos/src/EcalSignalGeneratorPh2.cc b/SimCalorimetry/EcalSimAlgos/src/EcalSignalGeneratorPh2.cc new file mode 100644 index 0000000000000..ee0343874e729 --- /dev/null +++ b/SimCalorimetry/EcalSimAlgos/src/EcalSignalGeneratorPh2.cc @@ -0,0 +1,204 @@ +#include "SimCalorimetry/EcalSimAlgos/interface/EcalSignalGeneratorPh2.h" + +#include + +template <> +EcalSignalGeneratorPh2::EcalSignalGeneratorPh2(edm::ConsumesCollector& cc, + const edm::InputTag& inputTag, + const double ebs25notCont, + const double peToA, + const bool timeDependent) + : EcalBaseSignalGenerator(), + gainRatiosToken_(cc.esConsumes()), + interCalibConstantsMCToken_(cc.esConsumes()), + adcToGeVConstantToken_(cc.esConsumes()), + theEvent_(nullptr), + theEventPrincipal_(nullptr), + gainRatios_(nullptr), + theInputTag_(inputTag), + tok_(cc.consumes(inputTag)), + ebs25notCont_(ebs25notCont), + peToA_(peToA), + ical_(nullptr), + timeDependent_(timeDependent), + lasercals_(nullptr), + lasercals_prime_(nullptr) { + if (timeDependent_) { + laserDbToken_ = cc.esConsumes(); + laserDbMCToken_ = cc.esConsumes(); + } +} + +template <> +void EcalSignalGeneratorPh2::initializeEvent(const edm::Event* event, + const edm::EventSetup* eventSetup) { + theEvent_ = event; + gainRatios_ = &eventSetup->getData(gainRatiosToken_); // find the gains + // Ecal Intercalibration Constants + ical_ = &eventSetup->getData(interCalibConstantsMCToken_); + // adc to GeV + auto const& agc = eventSetup->getData(adcToGeVConstantToken_); + maxEne_ = agc.getEBValue() * ecalPh2::gains[0] * ecalPh2::MAXADC * ebs25notCont_; + + if (timeDependent_) { + //---- + // + auto const eventTimeValue = theEvent_->getRun().runAuxiliary().beginTime().value(); + // + // The "time" will have to match in the generation of the tag + // for the MC from ECAL (apd/pn, alpha, whatever time dependent is needed) + // + iTime_ = eventTimeValue; + + // Ecal LaserCorrection Constants for laser correction ratio + lasercals_ = &eventSetup->getData(laserDbToken_); + + // + // the "prime" is exactly the same as the usual laser service, BUT + // it has only 1 IOV, so that effectively you are dividing IOV_n / IOV_0 + // NB: in the creation of the tag make sure the "prime" (MC) tag is prepared properly! + // NB again: if many IOVs also in "MC" tag, then fancy things could be perfomed ... left for the future + // + lasercals_prime_ = &eventSetup->getData(laserDbMCToken_); + + //clear the laser cache for each event time + CalibCache().swap(valueLCCache_LC_); + CalibCache().swap(valueLCCache_LC_prime_); //--- also the "prime" ... yes + //---- + } +} + +template <> +void EcalSignalGeneratorPh2::initializeEvent(const edm::EventPrincipal* eventPrincipal, + const edm::EventSetup* eventSetup) { + theEventPrincipal_ = eventPrincipal; + gainRatios_ = &eventSetup->getData(gainRatiosToken_); // find the gains + // Ecal Intercalibration Constants + ical_ = &eventSetup->getData(interCalibConstantsMCToken_); + // adc to GeV + auto const& agc = eventSetup->getData(adcToGeVConstantToken_); + maxEne_ = agc.getEBValue() * ecalPh2::gains[0] * ecalPh2::MAXADC * ebs25notCont_; + + if (timeDependent_) { + //---- + edm::TimeValue_t eventTimeValue = 0; + if (theEventPrincipal_) { + // + eventTimeValue = theEventPrincipal_->runPrincipal().beginTime().value(); + // + // The "time" will have to match in the generation of the tag + // for the MC from ECAL (apd/pn, alpha, whatever time dependent is needed) + // + } else { + edm::LogError("EcalSignalGeneratorPh2") << " theEventPrincipal not defined??? " << std::endl; + } + iTime_ = eventTimeValue; + + // Ecal LaserCorrection Constants for laser correction ratio + lasercals_ = &eventSetup->getData(laserDbToken_); + lasercals_prime_ = &eventSetup->getData(laserDbMCToken_); + + //clear the laser cache for each event time + CalibCache().swap(valueLCCache_LC_); + CalibCache().swap(valueLCCache_LC_prime_); //--- also the "prime" ... yes + //---- + } +} + +template <> +CaloSamples EcalSignalGeneratorPh2::samplesInPE(const DIGI& digi) { + const auto detId = digi.id(); + + double icalconst = 1.; // find the correct value. + auto const& icalMap = ical_->getMap(); + auto icalit = icalMap.find(detId); + if (icalit != icalMap.end()) { + icalconst = *icalit; + } + + auto const gainRatio = (*gainRatios_)[detId]; + + auto const lsbBase = maxEne_ / ecalPh2::MAXADC; + std::array const LSB = {lsbBase / gainRatio, lsbBase}; + + LogDebug("EcalSignalGeneratorPh2") << "Intercalibration: " << icalconst << ", LSBs: " << LSB[0] << " " << LSB[1] + << ", gain ratio: " << gainRatio << ", max. energy: " << maxEne_; + + CaloSamples result(detId, digi.size()); + + // correction factor for premixed sample: ratio of laser corrections + // LC' / LC (see formula) + double value_LC = 1.; + double value_LC_prime = 1.; + if (timeDependent_) { + auto const& evtTimeStamp = edm::Timestamp(iTime_); + + // LC that depends with time + auto cache = valueLCCache_LC_.find(detId); + if (cache != valueLCCache_LC_.end()) { + value_LC = cache->second; + } else { + value_LC = lasercals_->getLaserCorrection(detId, evtTimeStamp); + valueLCCache_LC_.emplace(detId, value_LC); + } + + // LC at the beginning of the time (first IOV of the GT == first time) + // Using the different "tag", the one with "MC" + cache = valueLCCache_LC_prime_.find(detId); + if (cache != valueLCCache_LC_prime_.end()) { + value_LC_prime = cache->second; + } else { + value_LC_prime = lasercals_prime_->getLaserCorrection(detId, evtTimeStamp); + valueLCCache_LC_prime_.emplace(detId, value_LC_prime); + } + } + auto const correction_factor_for_premixed_sample_transparency = value_LC_prime / value_LC; + + for (int isample = 0; isample < digi.size(); ++isample) { + auto const gainId = digi[isample].gainId(); + result[isample] = float(digi[isample].adc()) * LSB[gainId] * icalconst / peToA_ * + correction_factor_for_premixed_sample_transparency; + } + + LogDebug("EcalSignalGeneratorPh2").log([&](auto& li) { + li << "Noise input: " << digi; + li << "\nConverted noise sample:\n"; + for (int isample = 0; isample < digi.size(); ++isample) { + li << " " << result[isample]; + } + }); + + return result; +} + +template <> +void EcalSignalGeneratorPh2::fill(edm::ModuleCallingContext const* mcc) { + theNoiseSignals.clear(); + edm::Handle pDigis; + const COLLECTION* digis = nullptr; + // try accessing by whatever is set, Event or EventPrincipal + if (theEvent_) { + if (theEvent_->getByToken(tok_, pDigis)) { + digis = pDigis.product(); // get a ptr to the product + } else { + throw cms::Exception("EcalSignalGeneratorPh2") << "Cannot find input data " << theInputTag_; + } + } else if (theEventPrincipal_) { + auto const digisPTR = edm::getProductByTag(*theEventPrincipal_, theInputTag_, mcc); + if (digisPTR) { + digis = digisPTR->product(); + } + } else { + throw cms::Exception("EcalSignalGeneratorPh2") << "No Event or EventPrincipal was set"; + } + + if (digis) { + // loop over digis, adding these to the existing maps + for (typename COLLECTION::const_iterator it = digis->begin(); it != digis->end(); ++it) { + // need to convert to something useful + if (validDigi(*it)) { + theNoiseSignals.push_back(samplesInPE(*it)); + } + } + } +} diff --git a/SimCalorimetry/EcalSimProducers/interface/EcalDigiProducer_Ph2.h b/SimCalorimetry/EcalSimProducers/interface/EcalDigiProducer_Ph2.h index 30ab4dbd325be..5ced8fcb95e31 100644 --- a/SimCalorimetry/EcalSimProducers/interface/EcalDigiProducer_Ph2.h +++ b/SimCalorimetry/EcalSimProducers/interface/EcalDigiProducer_Ph2.h @@ -124,7 +124,6 @@ class EcalDigiProducer_Ph2 : public DigiAccumulatorMixMod { private: const bool m_PreMix1; - const bool m_PreMix2; const edm::EDGetTokenT> m_HitsEBToken; diff --git a/SimCalorimetry/EcalSimProducers/plugins/PreMixingEcalPh2Worker.cc b/SimCalorimetry/EcalSimProducers/plugins/PreMixingEcalPh2Worker.cc new file mode 100644 index 0000000000000..10dac7b1d7b03 --- /dev/null +++ b/SimCalorimetry/EcalSimProducers/plugins/PreMixingEcalPh2Worker.cc @@ -0,0 +1,80 @@ +#include "FWCore/Framework/interface/ConsumesCollector.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/ProducesCollector.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "SimGeneral/MixingModule/interface/PileUpEventPrincipal.h" + +#include "DataFormats/EcalDigi/interface/EcalDigiCollections.h" +#include "SimCalorimetry/EcalSimAlgos/interface/EcalSignalGeneratorPh2.h" +#include "SimCalorimetry/EcalSimProducers/interface/EcalDigiProducer_Ph2.h" + +#include "SimGeneral/PreMixingModule/interface/PreMixingWorker.h" +#include "SimGeneral/PreMixingModule/interface/PreMixingWorkerFactory.h" + +class PreMixingEcalPh2Worker : public PreMixingWorker { +public: + PreMixingEcalPh2Worker(const edm::ParameterSet &ps, edm::ProducesCollector, edm::ConsumesCollector &&iC); + ~PreMixingEcalPh2Worker() override = default; + + PreMixingEcalPh2Worker(const PreMixingEcalPh2Worker &) = delete; + PreMixingEcalPh2Worker &operator=(const PreMixingEcalPh2Worker &) = delete; + + void beginLuminosityBlock(edm::LuminosityBlock const &lumi, edm::EventSetup const &setup) override; + + void initializeEvent(edm::Event const &e, edm::EventSetup const &ES) override; + void addSignals(edm::Event const &e, edm::EventSetup const &ES) override; + void addPileups(PileUpEventPrincipal const &pep, edm::EventSetup const &es) override; + void put(edm::Event &e, edm::EventSetup const &iSetup, std::vector const &ps, int bs) override; + +private: + EBSignalGeneratorPh2 theEBSignalGenerator_; + EcalDigiProducer_Ph2 myEcalDigitizer_; +}; + +// Constructor +PreMixingEcalPh2Worker::PreMixingEcalPh2Worker(const edm::ParameterSet &ps, + edm::ProducesCollector producesCollector, + edm::ConsumesCollector &&iC) + : theEBSignalGenerator_(iC, + ps.getParameter("EBPileInputTag"), + ps.getParameter("EBs25notContainment"), + ps.getParameter("photoelectronsToAnalogBarrel"), + ps.getParameter("timeDependent")), + myEcalDigitizer_(ps, iC) { + producesCollector.produces(ps.getParameter("EBDigiCollectionDM")); + + myEcalDigitizer_.setEBNoiseSignalGenerator(&theEBSignalGenerator_); +} + +void PreMixingEcalPh2Worker::initializeEvent(const edm::Event &e, const edm::EventSetup &ES) { + myEcalDigitizer_.initializeEvent(e, ES); +} + +void PreMixingEcalPh2Worker::addSignals(const edm::Event &e, const edm::EventSetup &ES) { + myEcalDigitizer_.accumulate(e, ES); +} + +void PreMixingEcalPh2Worker::addPileups(const PileUpEventPrincipal &pep, const edm::EventSetup &ES) { + LogDebug("PreMixingEcalPh2Worker") << "\n===============> adding pileups from event " << pep.principal().id() + << " for bunchcrossing " << pep.bunchCrossing(); + + theEBSignalGenerator_.initializeEvent(&pep.principal(), &ES); + + // add noise signals using incoming digis + theEBSignalGenerator_.fill(pep.moduleCallingContext()); +} + +void PreMixingEcalPh2Worker::put(edm::Event &e, + const edm::EventSetup &ES, + std::vector const &ps, + int bs) { + myEcalDigitizer_.finalizeEvent(e, ES); +} + +void PreMixingEcalPh2Worker::beginLuminosityBlock(edm::LuminosityBlock const &lumi, edm::EventSetup const &setup) { + myEcalDigitizer_.beginLuminosityBlock(lumi, setup); +} + +DEFINE_PREMIXING_WORKER(PreMixingEcalPh2Worker); diff --git a/SimCalorimetry/EcalSimProducers/python/ecalDigiParameters_Ph2_cff.py b/SimCalorimetry/EcalSimProducers/python/ecalDigiParameters_Ph2_cff.py index d692fd21de0e9..c0cfc7e4338b2 100644 --- a/SimCalorimetry/EcalSimProducers/python/ecalDigiParameters_Ph2_cff.py +++ b/SimCalorimetry/EcalSimProducers/python/ecalDigiParameters_Ph2_cff.py @@ -14,9 +14,7 @@ 1.00000, 0.73354, 0.64442, 0.58851, 0.55425, 0.53082, 0.51916, 0.51097, 0.50732, 0.50409, 0.40449,0.40449,0.40449,0.40449,0.40449,0.40449) , - EcalPreMixStage1 = cms.bool(False), - EcalPreMixStage2 = cms.bool(False) - + EcalPreMixStage1 = cms.bool(False) ) from Configuration.ProcessModifiers.premix_stage1_cff import premix_stage1 diff --git a/SimCalorimetry/EcalSimProducers/python/ecalSimParameterMap_cff.py b/SimCalorimetry/EcalSimProducers/python/ecalSimParameterMap_cff.py index c88bc9b0c5bd2..d57a6c70d7fc5 100644 --- a/SimCalorimetry/EcalSimProducers/python/ecalSimParameterMap_cff.py +++ b/SimCalorimetry/EcalSimProducers/python/ecalSimParameterMap_cff.py @@ -20,6 +20,7 @@ simHitToPhotoelectronsBarrel = cms.double(2250.0), syncPhase = cms.bool(True), doPhotostatistics = cms.bool(True), - photoelectronsToAnalogBarrel = cms.double(0.000444444) + photoelectronsToAnalogBarrel = cms.double(0.000444444), + timeDependent = cms.bool(False) ) diff --git a/SimCalorimetry/EcalSimProducers/src/EcalDigiProducer_Ph2.cc b/SimCalorimetry/EcalSimProducers/src/EcalDigiProducer_Ph2.cc index 9d2733c286654..bc80d2936b2e5 100644 --- a/SimCalorimetry/EcalSimProducers/src/EcalDigiProducer_Ph2.cc +++ b/SimCalorimetry/EcalSimProducers/src/EcalDigiProducer_Ph2.cc @@ -139,7 +139,6 @@ EcalDigiProducer_Ph2::EcalDigiProducer_Ph2(const edm::ParameterSet& params, edm: &m_ComponentShapes)), m_PreMix1(params.getParameter("EcalPreMixStage1")), - m_PreMix2(params.getParameter("EcalPreMixStage2")), m_HitsEBToken(iC.consumes>(edm::InputTag(m_hitsProducerTag, "EcalHitsEB"))), m_APDDigitizer(nullptr), diff --git a/SimGeneral/PreMixingModule/python/mixOne_premix_on_sim_cfi.py b/SimGeneral/PreMixingModule/python/mixOne_premix_on_sim_cfi.py index 241fde39bb22a..d33c3928bebab 100644 --- a/SimGeneral/PreMixingModule/python/mixOne_premix_on_sim_cfi.py +++ b/SimGeneral/PreMixingModule/python/mixOne_premix_on_sim_cfi.py @@ -223,6 +223,7 @@ from Configuration.Eras.Modifier_phase2_common_cff import phase2_common from Configuration.Eras.Modifier_phase2_tracker_cff import phase2_tracker from Configuration.Eras.Modifier_phase2_timing_layer_cff import phase2_timing_layer +from Configuration.Eras.Modifier_phase2_ecal_devel_cff import phase2_ecal_devel from Configuration.Eras.Modifier_phase2_hcal_cff import phase2_hcal from Configuration.Eras.Modifier_phase2_hgcal_cff import phase2_hgcal from Configuration.Eras.Modifier_phase2_hfnose_cff import phase2_hfnose @@ -285,8 +286,19 @@ ) ) # ECAL -phase2_common.toModify (mixData, workers=dict(ecal=dict(doES=False))) -phase2_hgcal.toModify(mixData, workers=dict(ecal=dict(doEE=False))) +(phase2_common & ~phase2_ecal_devel).toModify (mixData, workers=dict(ecal=dict(doES=False))) +phase2_ecal_devel.toModify(mixData, + workers = dict( + ecal = cms.PSet( + ecalDigitizer.clone(accumulatorType = None, makeDigiSimLinks=None), + workerType = cms.string("PreMixingEcalPh2Worker"), + EBdigiProducerSig = cms.InputTag("simEcalUnsuppressedDigis"), + EBPileInputTag = cms.InputTag("simEcalUnsuppressedDigis"), + EBDigiCollectionDM = cms.string(''), + ) + ) +) +(phase2_hgcal & ~phase2_ecal_devel).toModify(mixData, workers=dict(ecal=dict(doEE=False))) # HGCAL phase2_hgcal.toModify(mixData,