.. _program_listing_file_Root_PhotonCalibrator.cxx: Program Listing for File PhotonCalibrator.cxx ============================================= |exhale_lsh| :ref:`Return to documentation for file ` (``Root/PhotonCalibrator.cxx``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp /******************************************************* * * Interface to CP Photon calibration tool(s). * * The tool applies: * * -) scale corrections for DATA * -) smearing corrections for MC * (data VS. MC check is done by the CP tool internally) * * M. Milesi (marco.milesi@cern.ch) * *******************************************************/ // c++ include(s): #include // EL include(s): #include #include #include // EDM include(s): #include #include #include #include #include #include #include #include #include #include #include // package include(s): #include #include #include #include "ElectronPhotonFourMomentumCorrection/EgammaCalibrationAndSmearingTool.h" #include "ElectronPhotonSelectorTools/AsgPhotonIsEMSelector.h" #include "EGammaVariableCorrection/ElectronPhotonVariableCorrectionTool.h" #include // apparently needed for egammaPIDs but was included in HelperClasses too? #include "ElectronPhotonSelectorTools/egammaPIDdefs.h" using HelperClasses::ToolName; // this is needed to distribute the algorithm to the workers ClassImp(PhotonCalibrator) PhotonCalibrator :: PhotonCalibrator () : Algorithm("PhotonCalibrator") { } EL::StatusCode PhotonCalibrator :: setupJob (EL::Job& job) { // Here you put code that sets up the job on the submission object // so that it is ready to work with your algorithm, e.g. you can // request the D3PDReader service or add output files. Any code you // put here could instead also go into the submission script. The // sole advantage of putting it here is that it gets automatically // activated/deactivated when you add/remove the algorithm from your // job, which may or may not be of value to you. ANA_MSG_INFO( "Calling setupJob"); job.useXAOD (); xAOD::Init( "PhotonCalibrator" ).ignore(); // call before opening first file return EL::StatusCode::SUCCESS; } EL::StatusCode PhotonCalibrator :: histInitialize () { // Here you do everything that needs to be done at the very // beginning on each worker node, e.g. create histograms and output // trees. This method gets called before any input files are // connected. ANA_CHECK( xAH::Algorithm::algInitialize()); return EL::StatusCode::SUCCESS; } EL::StatusCode PhotonCalibrator :: fileExecute () { // Here you do everything that needs to be done exactly once for every // single file, e.g. collect a list of all lumi-blocks processed return EL::StatusCode::SUCCESS; } EL::StatusCode PhotonCalibrator :: changeInput (bool /*firstFile*/) { // Here you do everything you need to do when we change input files, // e.g. resetting branch addresses on trees. If you are using // D3PDReader or a similar service this method is not needed. return EL::StatusCode::SUCCESS; } EL::StatusCode PhotonCalibrator :: initialize () { // Here you do everything that you need to do after the first input // file has been connected and before the first event is processed, // e.g. create additional histograms based on which variables are // available in the input files. You can also create all of your // histograms and trees in here, but be aware that this method // doesn't get called if no events are processed. So any objects // you create here won't be available in the output if you have no // input events. ANA_MSG_INFO( "Initializing PhotonCalibrator Interface... "); m_event = wk()->xaodEvent(); m_store = wk()->xaodStore(); ANA_MSG_INFO( "Number of events in file: " << m_event->getEntries() ); if ( m_inContainerName.empty() ) { ANA_MSG_ERROR( "InputContainer is empty!"); return EL::StatusCode::FAILURE; } m_outAuxContainerName = m_outContainerName + "Aux."; // the period is very important! // shallow copies are made with this output container name m_outSCContainerName = m_outContainerName + "ShallowCopy"; m_outSCAuxContainerName = m_outSCContainerName + "Aux."; // the period is very important! // initialize the CP::EgammaCalibrationAndSmearingTool // const std::string CalibToolName = m_name + "_EgammaCalibrationAndSmearingTool_Photons"; if ( asg::ToolStore::contains(CalibToolName.c_str()) ) { m_EgammaCalibrationAndSmearingTool = asg::ToolStore::get(CalibToolName.c_str()); } else { m_EgammaCalibrationAndSmearingTool = new CP::EgammaCalibrationAndSmearingTool(CalibToolName.c_str()); } ANA_CHECK( m_EgammaCalibrationAndSmearingTool->setProperty("ESModel", m_esModel)); ANA_CHECK( m_EgammaCalibrationAndSmearingTool->setProperty("decorrelationModel", m_decorrelationModel)); if(m_randomRunNumber>0) ANA_CHECK( m_EgammaCalibrationAndSmearingTool->setProperty("randomRunNumber", m_randomRunNumber)); //Backwards compatibility if (m_useAFII || m_useAF3) m_forceFastSim = true; if ( isFastSim() ){ ANA_MSG_INFO( "Setting simulation flavour to Fast Sim"); ANA_CHECK( m_EgammaCalibrationAndSmearingTool->setProperty("useFastSim", 1)); } else { ANA_CHECK( m_EgammaCalibrationAndSmearingTool->setProperty("useFastSim", 0)); } ANA_CHECK( m_EgammaCalibrationAndSmearingTool->initialize()); m_EgammaCalibrationAndSmearingTool->msg().setLevel( msg().level() ); // Get a list of recommended systematics for this tool // //const CP::SystematicRegistry& systReg = CP::SystematicRegistry::getInstance(); const CP::SystematicSet& recSyst = m_EgammaCalibrationAndSmearingTool->recommendedSystematics();; ANA_MSG_INFO(" Initializing Photon Calibrator Systematics :"); m_systList = HelperFunctions::getListofSystematics( recSyst, m_systName, m_systVal, msg() ); ANA_MSG_INFO("Will be using EgammaCalibrationAndSmearingTool systematic:"); auto SystPhotonsNames = std::make_unique< std::vector< std::string > >(); for ( const auto& syst_it : m_systList ) { SystPhotonsNames->push_back(syst_it.name()); ANA_MSG_INFO("\t " << syst_it.name()); } ANA_CHECK(m_store->record(std::move(SystPhotonsNames), "photons_Syst"+m_name )); //isEM selector tools //------------------ //create the selectors // Tight const std::string TightSelectorName = m_name + "_PhotonTightIsEMSelector"; if ( asg::ToolStore::contains(TightSelectorName.c_str()) ) { m_photonTightIsEMSelector = asg::ToolStore::get(TightSelectorName.c_str()); } else { m_photonTightIsEMSelector = new AsgPhotonIsEMSelector ( TightSelectorName.c_str() ); } m_photonTightIsEMSelector->msg().setLevel( msg().level() ); // Medium const std::string MediumSelectorName = m_name + "_PhotonMediumIsEMSelector"; if ( asg::ToolStore::contains(MediumSelectorName.c_str()) ) { m_photonMediumIsEMSelector = asg::ToolStore::get(MediumSelectorName.c_str()); } else { m_photonMediumIsEMSelector = new AsgPhotonIsEMSelector ( MediumSelectorName.c_str() ); } m_photonMediumIsEMSelector->msg().setLevel( msg().level() ); // Loose const std::string LooseSelectorName = m_name + "_PhotonLooseIsEMSelector"; if ( asg::ToolStore::contains(LooseSelectorName.c_str()) ) { m_photonLooseIsEMSelector = asg::ToolStore::get(LooseSelectorName.c_str()); } else { m_photonLooseIsEMSelector = new AsgPhotonIsEMSelector ( LooseSelectorName.c_str() ); } m_photonLooseIsEMSelector->msg().setLevel( msg().level() ); //set the type of selection ANA_CHECK( m_photonTightIsEMSelector->setProperty("isEMMask", egammaPID::PhotonTight)); ANA_CHECK( m_photonMediumIsEMSelector->setProperty("isEMMask", egammaPID::PhotonMedium)); ANA_CHECK( m_photonLooseIsEMSelector->setProperty("isEMMask", egammaPID::PhotonLoose)); //set the configuration file // todo : monitor the config files! ANA_CHECK( m_photonTightIsEMSelector->setProperty("ConfigFile", m_tightIDConfigPath)); ANA_CHECK( m_photonMediumIsEMSelector->setProperty("ConfigFile",m_mediumIDConfigPath)); ANA_CHECK( m_photonLooseIsEMSelector->setProperty("ConfigFile", m_looseIDConfigPath)); ANA_CHECK( m_photonTightIsEMSelector->initialize()); ANA_CHECK( m_photonMediumIsEMSelector->initialize()); ANA_CHECK( m_photonLooseIsEMSelector->initialize()); // *********************************************************** // // Make a list of systematics to be used, based on configuration input // Use HelperFunctions::getListofSystematics() for this! // // fudge MC tool //-------------- const std::string VarCorrectionToolName = m_name + "VarCorrectionTool"; if ( asg::ToolStore::contains(VarCorrectionToolName.c_str()) ) { m_photonVarCorrectionTool = asg::ToolStore::get(VarCorrectionToolName.c_str()); } else { m_photonVarCorrectionTool = new ElectronPhotonVariableCorrectionTool(VarCorrectionToolName.c_str()); } m_photonVarCorrectionTool->msg().setLevel( msg().level() ); std::string configFilePath = "EGammaVariableCorrection/TUNE23/ElPhVariableNominalCorrection.conf"; m_photonVarCorrectionTool->setProperty("ConfigFile", configFilePath); ANA_CHECK( m_photonVarCorrectionTool->initialize()); if (isMC()) { int dataType = PATCore::ParticleDataType::Data; if ( isFastSim() ) { dataType = PATCore::ParticleDataType::Fast; } else { dataType = PATCore::ParticleDataType::Full; } ANA_MSG_DEBUG("isSimulation=" << ( isMC() ? "Y" : "N") << " Simulation type: " << ( isFastSim() ? ( isAF3() ? "AF3" : "AFII") : "FullSim" ) << " selected dataType=" << dataType ); // photon efficiency correction tool //---------------------------------- //create the tools if( !m_overridePhotonCalibMap.empty() ){ ANA_MSG_WARNING("Overriding photon calibration map to " << m_overridePhotonCalibMap); ANA_CHECK( m_photonTightEffTool_handle .setProperty("MapFilePath", m_overridePhotonCalibMap) ); ANA_CHECK( m_photonMediumEffTool_handle.setProperty("MapFilePath", m_overridePhotonCalibMap) ); ANA_CHECK( m_photonLooseEffTool_handle .setProperty("MapFilePath", m_overridePhotonCalibMap) ); } // set data type ANA_CHECK( m_photonTightEffTool_handle. setProperty("ForceDataType", dataType)); ANA_CHECK( m_photonMediumEffTool_handle.setProperty("ForceDataType", dataType)); ANA_CHECK( m_photonLooseEffTool_handle. setProperty("ForceDataType", dataType)); // set debug levels ANA_CHECK( m_photonTightEffTool_handle. setProperty("OutputLevel", msg().level())); ANA_CHECK( m_photonMediumEffTool_handle.setProperty("OutputLevel", msg().level())); ANA_CHECK( m_photonLooseEffTool_handle. setProperty("OutputLevel", msg().level())); //initialize ANA_CHECK( m_photonTightEffTool_handle.retrieve()); ANA_CHECK( m_photonMediumEffTool_handle.retrieve()); ANA_CHECK( m_photonLooseEffTool_handle.retrieve()); } //IsolationCorrectionTool ANA_CHECK(m_isolationCorrectionTool_handle.setProperty("OutputLevel", msg().level())); ANA_CHECK(m_isolationCorrectionTool_handle.retrieve()); ANA_MSG_INFO( "PhotonCalibrator Interface succesfully initialized!" ); return EL::StatusCode::SUCCESS; } EL::StatusCode PhotonCalibrator :: execute () { // Here you do everything that needs to be done on every single // events, e.g. read input variables, apply cuts, and fill // histograms and trees. This is where most of your actual analysis // code will go. ANA_MSG_DEBUG("Applying Photon Calibration ... "); // get the collection from TEvent or TStore // const xAOD::EventInfo* eventInfo(nullptr); ANA_CHECK( HelperFunctions::retrieve(eventInfo, m_eventInfoContainerName, m_event, m_store, msg()) ); const xAOD::PhotonContainer* inPhotons(nullptr); ANA_CHECK( HelperFunctions::retrieve(inPhotons, m_inContainerName, m_event, m_store, msg()) ); ANA_MSG_DEBUG("Retrieve has been completed with container name = " << m_inContainerName); // loop over available systematics - remember syst == EMPTY_STRING --> baseline // prepare a vector of the names of CDV containers // must be a pointer to be recorded in TStore // auto vecOutContainerNames = std::make_unique< std::vector< std::string > >(); for ( const auto& syst_it : m_systList ) { ANA_MSG_DEBUG("Systematic Loop for m_systList=" << syst_it.name() ); // discard photon systematics // //if ( (syst_it.name()).find("PH_", 0) != std::string::npos ) { continue; } std::string outSCContainerName(m_outSCContainerName); std::string outSCAuxContainerName(m_outSCAuxContainerName); std::string outContainerName(m_outContainerName); // always append the name of the variation, including nominal which is an empty string // outSCContainerName += syst_it.name(); outSCAuxContainerName += syst_it.name(); outContainerName += syst_it.name(); vecOutContainerNames->push_back( syst_it.name() ); // apply syst // ANA_MSG_DEBUG("syst_it.name()=" << syst_it.name()); if ( m_EgammaCalibrationAndSmearingTool->applySystematicVariation(syst_it) != EL::StatusCode::SUCCESS ) { ANA_MSG_ERROR( "Failed to configure EgammaCalibrationAndSmearingTool for systematic " << syst_it.name()); return EL::StatusCode::FAILURE; } ANA_MSG_DEBUG("Systematics applied"); // create shallow copy for calibration - one per syst // std::pair< xAOD::PhotonContainer*, xAOD::ShallowAuxContainer* > calibPhotonsSC = xAOD::shallowCopyContainer( *inPhotons ); // create ConstDataVector to be eventually stored in TStore // ConstDataVector* calibPhotonsCDV = new ConstDataVector(SG::VIEW_ELEMENTS); calibPhotonsCDV->reserve( calibPhotonsSC.first->size() ); // now calibrate! // four momentum calibration unsigned int idx(0); for ( auto phSC_itr : *(calibPhotonsSC.first) ) { // set smearing seeding if needed - no need for this after Base,2.1.26 // m_EgammaCalibrationAndSmearingTool->setRandomSeed(eventInfo->eventNumber() + 100 * idx); // ANA_MSG_DEBUG("Checking photon " << idx << " raw pt = " << phSC_itr->pt()*1e-3 << " GeV " ); if ( phSC_itr->pt() > 7e3 && !(phSC_itr->caloCluster()) ){ ANA_MSG_WARNING( "photon "<author() & xAOD::EgammaParameters::AuthorPhoton) || (phSC_itr->author() & xAOD::EgammaParameters::AuthorAmbiguous) ) { if ( m_EgammaCalibrationAndSmearingTool->applyCorrection( *phSC_itr ) != CP::CorrectionCode::Ok ) { ANA_MSG_WARNING( "Problem in CP::EgammaCalibrationAndSmearingTool::applyCorrection()"); } if ( m_isolationCorrectionTool_handle->applyCorrection( *phSC_itr ) != CP::CorrectionCode::Ok ) { ANA_MSG_WARNING( "Problem in CP::IsolationCorrection::applyCorrection()"); } } ANA_MSG_DEBUG("Calibrated pt with systematic: " << syst_it.name() << " , pt = " << phSC_itr->pt() * 1e-3 << " GeV"); ANA_CHECK( decorate(phSC_itr)); ++idx; } // close calibration loop if ( !xAOD::setOriginalObjectLink(*inPhotons, *(calibPhotonsSC.first)) ) { ANA_MSG_ERROR( "Failed to set original object links -- MET rebuilding cannot proceed."); } // save pointers in ConstDataVector with same order // ANA_CHECK( HelperFunctions::makeSubsetCont(calibPhotonsSC.first, calibPhotonsCDV, msg())); // Sort after copying to CDV. if ( m_sort ) { std::sort( calibPhotonsCDV->begin(), calibPhotonsCDV->end(), HelperFunctions::sort_pt ); } // add SC container to TStore // ANA_CHECK( m_store->record( calibPhotonsSC.first, outSCContainerName )); ANA_CHECK( m_store->record( calibPhotonsSC.second, outSCAuxContainerName )); // add ConstDataVector to TStore // ANA_CHECK( m_store->record( calibPhotonsCDV, outContainerName)); } // close loop on systematics // add vector to TStore // ANA_CHECK( m_store->record( std::move(vecOutContainerNames), m_outputAlgoSystNames)); // look what we have in TStore // if(msgLvl(MSG::VERBOSE)) m_store->print(); return EL::StatusCode::SUCCESS; } EL::StatusCode PhotonCalibrator :: postExecute () { // Here you do everything that needs to be done after the main event // processing. This is typically very rare, particularly in user // code. It is mainly used in implementing the NTupleSvc. ANA_MSG_DEBUG("Calling postExecute"); return EL::StatusCode::SUCCESS; } EL::StatusCode PhotonCalibrator :: finalize () { // This method is the mirror image of initialize(), meaning it gets // called after the last event has been processed on the worker node // and allows you to finish up any objects you created in // initialize() before they are written to disk. This is actually // fairly rare, since this happens separately for each worker node. // Most of the time you want to do your post-processing on the // submission node after all your histogram outputs have been // merged. This is different from histFinalize() in that it only // gets called on worker nodes that processed input events. ANA_MSG_INFO( "Deleting tool instances..."); if ( m_EgammaCalibrationAndSmearingTool ) { delete m_EgammaCalibrationAndSmearingTool; m_EgammaCalibrationAndSmearingTool = nullptr; } if ( m_photonVarCorrectionTool ) { delete m_photonVarCorrectionTool; m_photonVarCorrectionTool = nullptr; } if ( m_photonTightIsEMSelector ) { delete m_photonTightIsEMSelector; m_photonTightIsEMSelector = nullptr; } if (m_photonMediumIsEMSelector) { delete m_photonMediumIsEMSelector; m_photonMediumIsEMSelector = nullptr; } if (m_photonLooseIsEMSelector) { delete m_photonLooseIsEMSelector; m_photonLooseIsEMSelector = nullptr; } ANA_MSG_INFO( "Finalization done."); return EL::StatusCode::SUCCESS; } EL::StatusCode PhotonCalibrator :: histFinalize () { // This method is the mirror image of histInitialize(), meaning it // gets called after the last event has been processed on the worker // node and allows you to finish up any objects you created in // histInitialize() before they are written to disk. This is // actually fairly rare, since this happens separately for each // worker node. Most of the time you want to do your // post-processing on the submission node after all your histogram // outputs have been merged. This is different from finalize() in // that it gets called on all worker nodes regardless of whether // they processed input events. ANA_MSG_INFO( "Calling histFinalize"); ANA_CHECK( xAH::Algorithm::algFinalize()); return EL::StatusCode::SUCCESS; } EL::StatusCode PhotonCalibrator :: decorate(xAOD::Photon* photon) { // (1) apply fudge factors and (2) evaluate the ID quality bool isTight(false); bool isMedium(false); bool isLoose(false); if (m_readIDFlagsFromDerivation){ static SG::AuxElement::ConstAccessor< char > LHDecisionTight( "DFCommonPhotonsIsEMTight" ); static SG::AuxElement::ConstAccessor< char > LHDecisionMedium( "DFCommonPhotonsIsEMMedium" ); static SG::AuxElement::ConstAccessor< char > LHDecisionLoose( "DFCommonPhotonsIsEMLoose" ); if (LHDecisionTight.isAvailable( *photon )) isTight = LHDecisionTight( *photon ); if (LHDecisionMedium.isAvailable( *photon )) isMedium = LHDecisionMedium( *photon ); if (LHDecisionLoose.isAvailable( *photon )) isLoose = LHDecisionLoose( *photon ); } else { if( isMC() && !isFastSim() ){ if(m_photonVarCorrectionTool->applyCorrection(*photon) == CP::CorrectionCode::Error){ ANA_MSG_ERROR( "photonVarCorrectionTool->applyCorrection(*photon) returned CP::CorrectionCode::Error"); return EL::StatusCode::FAILURE; } } isTight = bool(m_photonTightIsEMSelector->accept(photon)); isMedium = bool(m_photonMediumIsEMSelector->accept(photon)); isLoose = bool(m_photonLooseIsEMSelector->accept(photon)); } photon->auxdecor< bool >( "PhotonID_Tight" ) = isTight; photon->auxdecor< bool >( "PhotonID_Medium" ) = isMedium; photon->auxdecor< bool >( "PhotonID_Loose" ) = isLoose; ANA_MSG_DEBUG("isTight="<<(isTight?"Y":"N")<<" isMedium="<<(isMedium?"Y":"N")<<" isLoose="<<(isLoose?"Y":"N") ); // (3) set efficiency correction if (isMC()) { const xAOD::CaloCluster* cluster = photon->caloCluster(); float cluster_eta = 10; float cluster_et = 0; if (cluster) { cluster_eta = cluster->etaBE(2); if (cluster_eta != 0.0) { cluster_et = cluster->e() / cosh(cluster_eta); } } bool inCrack = abs(cluster_eta)>1.37 && abs(cluster_eta)<1.52; // photon SF double photonTightEffSF(1.), photonMediumEffSF(1.), photonLooseEffSF(1.); double photonTightEffSFError(0.), photonMediumEffSFError(0.), photonLooseEffSFError(0.); // configuration files not yet available for 13 TeV :( //sf only available after basic kinematic selection if(cluster_et > 10000. && fabs(cluster_eta) < 2.37 && !inCrack){ // SF if(m_photonTightEffTool_handle->getEfficiencyScaleFactor(*photon, photonTightEffSF) == CP::CorrectionCode::Error){ ANA_MSG_ERROR("getEfficiencyScaleFactor returned CP::CorrectionCode::Error"); return EL::StatusCode::FAILURE; } if(m_photonMediumEffTool_handle->getEfficiencyScaleFactor(*photon, photonMediumEffSF) == CP::CorrectionCode::Error){ ANA_MSG_ERROR("getEfficiencyScaleFactor returned CP::CorrectionCode::Error"); return EL::StatusCode::FAILURE; } if(m_photonLooseEffTool_handle->getEfficiencyScaleFactor(*photon, photonLooseEffSF) == CP::CorrectionCode::Error){ ANA_MSG_ERROR("getEfficiencyScaleFactor returned CP::CorrectionCode::Error"); return EL::StatusCode::FAILURE; } // SF error if(m_photonTightEffTool_handle->getEfficiencyScaleFactorError(*photon, photonTightEffSFError) == CP::CorrectionCode::Error){ ANA_MSG_ERROR("getEfficiencyScaleFactorError returned CP::CorrectionCode::Error"); return EL::StatusCode::FAILURE; } if(m_photonMediumEffTool_handle->getEfficiencyScaleFactorError(*photon, photonMediumEffSFError) == CP::CorrectionCode::Error){ ANA_MSG_ERROR("getEfficiencyScaleFactorError returned CP::CorrectionCode::Error"); return EL::StatusCode::FAILURE; } if(m_photonLooseEffTool_handle->getEfficiencyScaleFactorError(*photon, photonLooseEffSFError) == CP::CorrectionCode::Error){ ANA_MSG_ERROR("getEfficiencyScaleFactorError returned CP::CorrectionCode::Error"); return EL::StatusCode::FAILURE; } } photon->auxdecor< float >( "PhotonID_Tight_EffSF" ) = photonTightEffSF; photon->auxdecor< float >( "PhotonID_Medium_EffSF" ) = photonMediumEffSF; photon->auxdecor< float >( "PhotonID_Loose_EffSF" ) = photonLooseEffSF; photon->auxdecor< float >( "PhotonID_Tight_EffSF_Error" ) = photonTightEffSFError; photon->auxdecor< float >( "PhotonID_Medium_EffSF_Error" ) = photonMediumEffSFError; photon->auxdecor< float >( "PhotonID_Loose_EffSF_Error" ) = photonLooseEffSFError; ANA_MSG_DEBUG("Tight=" << photonTightEffSF << "(" << photonTightEffSFError << ")" "Medium=" << photonMediumEffSF << "(" << photonMediumEffSFError << ")" "Loose=" << photonLooseEffSF << "(" << photonLooseEffSFError << ")"); } return EL::StatusCode::SUCCESS; }