From 951de23e8db3ea2bdcff84db8892bdddf51ad73a Mon Sep 17 00:00:00 2001 From: Felix Friedrich <felixf@cern.ch> Date: Thu, 26 Jun 2014 14:24:49 +0200 Subject: [PATCH] remove calculation of some cluster variables (now done in tauRec) (TauDiscriminant-01-08-00) --- .../TauID/TauDiscriminant/DEVELOPERS | 13 + PhysicsAnalysis/TauID/TauDiscriminant/README | 1 + .../TauID/TauDiscriminant/README.rst | 80 ++ .../Root/BoostedDecisionTree.cxx | 38 + .../TauDiscriminant/Root/CommonLikelihood.cxx | 626 ++++++++++++++ .../TauDiscriminant/Root/CutsDecisionTree.cxx | 30 + .../TauID/TauDiscriminant/Root/EMFCluster.cxx | 75 ++ .../TauID/TauDiscriminant/Root/LinkDef.h | 38 + .../TauID/TauDiscriminant/Root/MethodBDT.cxx | 60 ++ .../TauID/TauDiscriminant/Root/MethodBase.cxx | 6 + .../TauID/TauDiscriminant/Root/MethodCuts.cxx | 58 ++ .../TauDiscriminant/Root/MethodDummy.cxx | 23 + .../TauID/TauDiscriminant/Root/MethodLLH.cxx | 57 ++ .../TauDiscriminant/Root/MethodTransform.cxx | 60 ++ .../TauID/TauDiscriminant/Root/Node.cxx | 11 + .../TauDiscriminant/Root/NoiseCorrIsol.cxx | 210 +++++ .../TauID/TauDiscriminant/Root/Pi0Finder.cxx | 526 ++++++++++++ .../Root/TauDetailsManagerStandalone.cxx | 356 ++++++++ .../TauDiscriminant/Root/TauIDReader.cxx | 774 ++++++++++++++++++ .../TauDiscriminant/Root/Transformation.cxx | 32 + .../TauID/TauDiscriminant/Root/TreeReader.cxx | 748 +++++++++++++++++ .../TauID/TauDiscriminant/Root/TreeVector.cxx | 6 + .../TauID/TauDiscriminant/Root/Types.cxx | 5 + .../TauDiscriminant/BoostedDecisionTree.h | 37 + .../TauDiscriminant/CommonLikelihood.h | 158 ++++ .../TauDiscriminant/CutsDecisionTree.h | 32 + .../TauDiscriminant/EMFCluster.h | 70 ++ .../TauDiscriminant/FakeTauBits.h | 90 ++ .../TauDiscriminant/FakeTauScores.h | 93 +++ .../TauDiscriminant/MethodBDT.h | 95 +++ .../TauDiscriminant/MethodBase.h | 177 ++++ .../TauDiscriminant/MethodCuts.h | 98 +++ .../TauDiscriminant/MethodDummy.h | 61 ++ .../TauDiscriminant/MethodLLH.h | 81 ++ .../TauDiscriminant/MethodTransform.h | 94 +++ .../TauDiscriminant/TauDiscriminant/Node.h | 371 +++++++++ .../TauDiscriminant/NoiseCorrIsol.h | 62 ++ .../TauDiscriminant/Pi0Finder.h | 123 +++ .../TauDiscriminant/TauDiscriminant/TauCuts.h | 48 ++ .../TauDiscriminant/TauCutsEleVeto.h | 48 ++ .../TauDiscriminant/TauDetails.h | 146 ++++ .../TauDiscriminant/TauDetailsManager.h | 151 ++++ .../TauDetailsManagerStandalone.h | 176 ++++ .../TauDiscriminant/TauDiscriBuilder.h | 45 + .../TauDiscriminant/TauDiscriToolBase.h | 58 ++ .../TauDiscriminant/TauDiscriminantDict.h | 15 + .../TauDiscriminant/TauEleBDT.h | 88 ++ .../TauDiscriminant/TauIDReader.h | 149 ++++ .../TauDiscriminant/TauJetBDT.h | 95 +++ .../TauDiscriminant/TauDiscriminant/TauLLH.h | 60 ++ .../TauDiscriminant/TauMuonVeto.h | 44 + .../TauDiscriminant/TauPi0BDT.h | 76 ++ .../TauDiscriminant/TauPi0Clusters.h | 72 ++ .../TauDiscriminant/Transformation.h | 37 + .../TauDiscriminant/TreeReader.h | 118 +++ .../TauDiscriminant/TreeVector.h | 42 + .../TauDiscriminant/TauDiscriminant/Types.h | 24 + .../TauDiscriminant/selection.xml | 10 + .../TauDiscriminant/cmt/Makefile.RootCore | 5 + .../TauDiscriminant/cmt/Makefile.Standalone | 108 +++ .../TauID/TauDiscriminant/cmt/requirements | 54 ++ .../TauDiscriminant/python/TauDiscriGetter.py | 168 ++++ .../run/TauEnergyCalibration_jobOption.py | 39 + .../run/TauIDAnalysisExample.C | 68 ++ .../run/TauIDAnalysisExample.py | 121 +++ .../TauID/TauDiscriminant/run/jobOptions.py | 33 + .../TauDiscriminant/run/minJobOptions.py | 24 + .../TauDiscriminant/run/tauIDReader_LLH.py | 127 +++ .../TauID/TauDiscriminant/run/tauid-redo | 236 ++++++ .../TauID/TauDiscriminant/setup.sh | 21 + .../share/EnergyCalibration.root | Bin 0 -> 57427 bytes .../TauDiscriminant/share/LMTCutsLLH.root | Bin 0 -> 13034 bytes .../share/TauDiscri_jobOptions.py | 2 + .../share/bkg.bits.jet.BDT.txt | 179 ++++ .../TauDiscriminant/share/cuts.eBDT.root | Bin 0 -> 7067 bytes .../TauID/TauDiscriminant/share/cuts.txt | 93 +++ .../TauID/TauDiscriminant/share/pdfs_jet.root | Bin 0 -> 30945 bytes .../TauID/TauDiscriminant/share/pdfs_tau.root | Bin 0 -> 29529 bytes .../TauDiscriminant/share/pi0Primary.BDT.bin | Bin 0 -> 87847 bytes .../share/pi0Secondary.BDT.bin | Bin 0 -> 7351 bytes .../share/sig.bits.jet.BDT.txt | 359 ++++++++ .../share/sig.trans.jet.BDT.root | Bin 0 -> 11887 bytes .../TauID/TauDiscriminant/src/FakeTauBits.cxx | 5 + .../TauDiscriminant/src/FakeTauScores.cxx | 5 + .../TauID/TauDiscriminant/src/TauCuts.cxx | 75 ++ .../TauDiscriminant/src/TauCutsEleVeto.cxx | 206 +++++ .../TauDiscriminant/src/TauDetailsManager.cxx | 441 ++++++++++ .../TauDiscriminant/src/TauDiscriBuilder.cxx | 209 +++++ .../TauDiscriminant/src/TauDiscriToolBase.cxx | 14 + .../TauID/TauDiscriminant/src/TauEleBDT.cxx | 209 +++++ .../TauID/TauDiscriminant/src/TauJetBDT.cxx | 245 ++++++ .../TauID/TauDiscriminant/src/TauLLH.cxx | 85 ++ .../TauID/TauDiscriminant/src/TauMuonVeto.cxx | 70 ++ .../TauID/TauDiscriminant/src/TauPi0BDT.cxx | 107 +++ .../TauDiscriminant/src/TauPi0Clusters.cxx | 185 +++++ .../src/components/TauDiscri_entries.cxx | 32 + .../src/components/TauDiscri_load.cxx | 3 + .../TauID/TauDiscriminant/svn-authors | 22 + 98 files changed, 10527 insertions(+) create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/DEVELOPERS create mode 120000 PhysicsAnalysis/TauID/TauDiscriminant/README create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/README.rst create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/BoostedDecisionTree.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/CommonLikelihood.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/CutsDecisionTree.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/EMFCluster.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/LinkDef.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodBDT.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodBase.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodCuts.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodDummy.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodLLH.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodTransform.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/Node.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/NoiseCorrIsol.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/Pi0Finder.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/TauDetailsManagerStandalone.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/TauIDReader.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/Transformation.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/TreeReader.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/TreeVector.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/Root/Types.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/BoostedDecisionTree.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/CommonLikelihood.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/CutsDecisionTree.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/EMFCluster.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/FakeTauBits.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/FakeTauScores.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodBDT.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodBase.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodCuts.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodDummy.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodLLH.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodTransform.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Node.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/NoiseCorrIsol.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Pi0Finder.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauCuts.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauCutsEleVeto.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDetails.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDetailsManager.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDetailsManagerStandalone.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDiscriBuilder.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDiscriToolBase.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDiscriminantDict.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauEleBDT.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauIDReader.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauJetBDT.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauLLH.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauMuonVeto.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauPi0BDT.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauPi0Clusters.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Transformation.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TreeReader.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TreeVector.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Types.h create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/selection.xml create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/cmt/Makefile.RootCore create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/cmt/Makefile.Standalone create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/cmt/requirements create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/python/TauDiscriGetter.py create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/run/TauEnergyCalibration_jobOption.py create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/run/TauIDAnalysisExample.C create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/run/TauIDAnalysisExample.py create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/run/jobOptions.py create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/run/minJobOptions.py create mode 100755 PhysicsAnalysis/TauID/TauDiscriminant/run/tauIDReader_LLH.py create mode 100755 PhysicsAnalysis/TauID/TauDiscriminant/run/tauid-redo create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/setup.sh create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/share/EnergyCalibration.root create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/share/LMTCutsLLH.root create mode 100755 PhysicsAnalysis/TauID/TauDiscriminant/share/TauDiscri_jobOptions.py create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/share/bkg.bits.jet.BDT.txt create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/share/cuts.eBDT.root create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/share/cuts.txt create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/share/pdfs_jet.root create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/share/pdfs_tau.root create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/share/pi0Primary.BDT.bin create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/share/pi0Secondary.BDT.bin create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/share/sig.bits.jet.BDT.txt create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/share/sig.trans.jet.BDT.root create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/src/FakeTauBits.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/src/FakeTauScores.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/src/TauCuts.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/src/TauCutsEleVeto.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/src/TauDetailsManager.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/src/TauDiscriBuilder.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/src/TauDiscriToolBase.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/src/TauEleBDT.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/src/TauJetBDT.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/src/TauLLH.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/src/TauMuonVeto.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/src/TauPi0BDT.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/src/TauPi0Clusters.cxx create mode 100755 PhysicsAnalysis/TauID/TauDiscriminant/src/components/TauDiscri_entries.cxx create mode 100755 PhysicsAnalysis/TauID/TauDiscriminant/src/components/TauDiscri_load.cxx create mode 100644 PhysicsAnalysis/TauID/TauDiscriminant/svn-authors diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/DEVELOPERS b/PhysicsAnalysis/TauID/TauDiscriminant/DEVELOPERS new file mode 100644 index 00000000000..5db36bd3a0c --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/DEVELOPERS @@ -0,0 +1,13 @@ +A Message to Developers +----------------------- + + + + +* Your Athena-based algorithms MUST inherit from +TauDiscriToolBase and implement the interface there. + +* If you want your id method to be useable by +TauIDReader on ROOT ntuples, your underlying id +class MUST inherit from MethodBase (and implement +the interface) and MUST NOT depend on Athena-based headers. diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/README b/PhysicsAnalysis/TauID/TauDiscriminant/README new file mode 120000 index 00000000000..92cacd28535 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/README @@ -0,0 +1 @@ +README.rst \ No newline at end of file diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/README.rst b/PhysicsAnalysis/TauID/TauDiscriminant/README.rst new file mode 100644 index 00000000000..e1dd4978875 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/README.rst @@ -0,0 +1,80 @@ +.. -*- mode: rst -*- + +Compilation within Athena +========================= + +To compile TauDiscriminant for use in Athena:: + + cd cmt + make + cd .. + + +Standalone Compilation +====================== + +Note: this does not require Athena in any way (setup or installed) +Note: that means **DO NOT SETUP ATHENA BEFORE DOING THE FOLLOWING** +(See "Known Problems" below) + +To compile a standalone library for use with ROOT and Python:: + + cd cmt + make -f Makefile.Standalone + cd .. + +This produces the shared object lib/libTauDiscriminant.so +Put this shared object in your ``LD_LIBRARY_PATH`` by executing:: + + source setup.sh + +The library may now be loaded in CINT like this:: + + gSystem->Load("libTauDiscriminant.so"); + +or in Python like this:: + + import ROOT + ROOT.gSystem.Load("libTauDiscriminant.so") + +Now you may follow the same procedure as in run/tauid-redo:: + + import ROOT + ROOT.gSystem.Load("libTauDiscriminant.so") + from ROOT import TauID + reader = TauID.TauIDReader(True) + # etc. + + +Recalculate Tau ID on D3PD (ROOT ntuples) +========================================= + +Compile TauDiscriminant by one of the two methods above and source setup.sh +Then execute tauid-redo:: + + tauid-redo *.root + +This will create new D3PDs with a suffix appended to the filenames +which contain branches for the newly calculated discriminants. +For more information execute:: + + tauid-redo --help + + +Known Problems +============== + +When running tauid-redo after a standalone compilation it might crash with:: + + AttributeError: type object 'TauID' has no attribute 'Types' + +This is most likely because you have Athena setup. Don't setup Athena. +Just use the default Python/ROOT installation on your system. + + +Additional Tools +================ + +Tools used to train BDTs, apply MVAs to ROOT ntuples, make performance plots, +convert TMVA BDT xml or MethodCuts files into TauDiscriminant format, etc. +are in the "taumva" package. taumva is now available from TauDiscriminantTools. diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/BoostedDecisionTree.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/BoostedDecisionTree.cxx new file mode 100644 index 00000000000..b14d54b1c35 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/BoostedDecisionTree.cxx @@ -0,0 +1,38 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: BoostedDecisionTree.cxx + * + * Author: Noel Dawe (end1@sfu.ca) + */ + +#include "TauDiscriminant/BoostedDecisionTree.h" + +float BoostedDecisionTree::response() const { + + float sum = 0.; + float norm = 0.; + Node* currentNode = 0; + DecisionNode* decision = 0; + LeafNode<float>* leafNode = 0; + vector<pair<Node*,float> >::const_iterator tree = this->trees.begin(); + while(tree != this->trees.end()) { + currentNode = (*tree).first; + while (!currentNode->isLeaf()) { + decision = static_cast<DecisionNode*>(currentNode); + if (decision->goRight()) { + currentNode = decision->getRightChild(); + } else { + currentNode = decision->getLeftChild(); + } + if (!currentNode) return -200.; + } + leafNode = static_cast<LeafNode<float>*>(currentNode); + sum += ((*tree).second)*leafNode->getValue(); + norm += (*tree).second; + ++tree; + } + return norm > 0. ? sum/norm : -100.; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/CommonLikelihood.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/CommonLikelihood.cxx new file mode 100644 index 00000000000..0c990748003 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/CommonLikelihood.cxx @@ -0,0 +1,626 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: CommonLikelihood.cxx + * + * Author: Martin Flechl (mflechl@cern.ch) + * Marcin Wolter (marcin.wolter@cern.ch) + * updated 16 May 2011 + */ + +#include "TauDiscriminant/CommonLikelihood.h" +#include <cmath> + + +TString m=""; +const double SMALL = 1.e-6; + +bool CommonLikelihood::build(const string& filename) { + + if (filename != ""){ //otherwise try defaults from constructor + vector<string> substrings; + this->splitString(filename,substrings,","); + if (substrings.size()==3){ + m_tauFilename=substrings[0]; + m_jetFilename=substrings[1]; + m_cutFilename=substrings[2]; + } else{ + //to do: otherwise, try defaults..... + print("Exactly 3 files required, e.g. \"pdf_taus.root,pdf_jet.root,LMTCutsLLH.root\".",0); + } + m="PDF files: tau="+m_tauFilename+", jet="+m_jetFilename+", cuts="+m_cutFilename; + print(m,0); + } + + return (this->readPDFHistograms() && this->readLMTCuts() && this->smoothPDFHistograms()); +} + +int CommonLikelihood::response(int ilmt, int /*option*/) const { + if(ilmt < 0 || ilmt > 2) + return 0; + std::vector<TGraph*> cuts; + int prongcat = m_prongindex; + if(prongcat==0) + cuts=m_vLMTCuts1P; + else if(prongcat==1) + cuts=m_vLMTCuts3P; + else + return 0; + if(cuts.size()!=3) + return 0; + double cut = cuts.at(ilmt)->Eval(m_et/1000.); + if ( m_llh>cut ) return 1; + else return 0; +} + +bool CommonLikelihood::calcLLHValue(const map<string,const float*>* floatVariables, + const map<string,const int*>* intVariables, int option=0){ + //option 0: safe llh; 1: default llh; 2: use whatever vars given in maps above + + m="In calcLLHValue, option="; m+=option; + print(m,2); + + m_llh=-999; + + map<string,const float*>::const_iterator it_floats; + map<string,const int*>::const_iterator it_ints; + + map<string,float> allVariables; + map<string,float>::const_iterator it_all; + + int author; + it_ints = intVariables->find("AUTHOR"); + if (it_ints == intVariables->end()) { + it_floats = floatVariables->find("AUTHOR"); + if (it_floats == floatVariables->end()) { + print("Cannot find AUTHOR in booked float or int variables!",0); + return false; + } else{ + author=(int)*(it_floats->second); + } + } else{ + author=*(it_ints->second); + } + if ( author==2 ){ + print("Author==2, assigning llh value -1111!",1); + m_llh=-1111; return true; + } //as tauRec does + + it_floats = floatVariables->find("PT"); + if (it_floats == floatVariables->end()) { + print("Cannot find PT in booked float variables!",0); + return false; + } + float et=*(it_floats->second); + + + it_floats = floatVariables->find("ETA"); + if (it_floats == floatVariables->end()) { + print("Cannot find ETA in booked float variables!",0); + return false; + } + float eta=*(it_floats->second); + if ( fabs(eta)>2.5 ){ print("Not within eta range",2); m_llh=-96; return true;} //as tauRec does + + it_ints = intVariables->find("NUMTRACK"); + if (it_ints == intVariables->end()) { + print("Cannot find NUMTRACK in booked int variables!",0); + return false; + } + int numtrack=*(it_ints->second); + if ( numtrack<1 ) { print("0 tracks",2); m_llh=-97; return true;} //as tauRec does + m_prongindex=0; //1pr + if (numtrack>=2) m_prongindex=1; //3pr + m_ntau[m_prongindex]++; +/* + it_ints = intVariables->find("NUMPI0"); + if (it_ints == intVariables->end()) { + it_ints = intVariables->find("NPI0"); + if (it_ints == intVariables->end()) { + print("Cannot find NUMPI0 in booked int variables!",0); + return false; + } + } + int numpi0=*(it_ints->second); +*/ + int nvtx=1; + it_ints = intVariables->find("NUM_PILEUP_AND_PRIMARY_VERTICES"); + if (it_ints == intVariables->end()) { + print("Cannot find NUM_PILEUP_AND_PRIMARY_VERTICES in booked int variables!",0); + print("Setting value to 1 and will try running, but the output will not be valid.",0); + } else nvtx=*(it_ints->second); + m_nvtx=nvtx; + + m="author: "; m+=author; m+=", et:"; m+=et; m+=", eta:"; m+=eta; + m+=", numtrack:"; m+=numtrack; //m+=", numpi0:"; m+=numpi0; + print(m,1); + + + allVariables = getVariables(floatVariables, intVariables, numtrack, author, option); + + + + m="nInts: "; m+=intVariables->size(); m+=", nFloats: "; m+=floatVariables->size(); + m+=", nAll: "; m+=allVariables.size(); + m+=", numtrack="; m+=numtrack; + print(m,1); + //print(m,0); + + //check if all vars are there + if (option==0){ //safeLLH + if ( ( numtrack==1 && (allVariables.size()!=NVAR_SAFE_1P) ) || ( numtrack>=2 && (allVariables.size()!=NVAR_SAFE_3P) ) ){ + print("Not all safe variables found... giving up! Use the llhall option to run over a specific set of variables.",0); + return false; + } + } + + + double calcLH=0; + + print("Start filling vars",2); + + for(it_all=allVariables.begin(); it_all!=allVariables.end(); ++it_all){ + m="Var: "+it_all->first; + int ivar=this->varNameToNumber(it_all->first); + if (ivar<0){ print("ERROR: Unknown Variable "+it_all->first,0+(m_ntau[m_prongindex]>1)); continue; } + m+=", var #"; m+=ivar; m+=", value="; m+=it_all->second; + print(m,1); + + calcLH+=getSingleLLHRatio(ivar, numtrack, author, et, nvtx, (float) it_all->second); + } + + m_et = et; + m_llh=calcLH; + return true; +} + + +map<string,float> CommonLikelihood::getVariables(const map<string,const float*>* floatVariables, const map<string,const int*>* intVariables, const int numtrack,const int author, const int option) const{ + + + + const string use_safe[2][NVAR_SAFE_3P]={ + {"CORRCENTFRAC","CORRFTRK","TRKAVGDIST","NUMWIDETRACK","IPSIGLEADTRK",""}, //1PR + {"CORRCENTFRAC","CORRFTRK","TRKAVGDIST","DRMAX","MASSTRKSYS","TRFLIGHTPATHSIG"}}; //3PR + + const string use_def[2][NVAR_DEF]={ + {"TRKAVGDIST","CORRFTRK","IPSIGLEADTRK","DRMAX","MASSTRKSYS","TRFLIGHTPATHSIG","NUMWIDETRACK","CORRCENTFRAC"}, + {"TRKAVGDIST","CORRFTRK","IPSIGLEADTRK","DRMAX","MASSTRKSYS","TRFLIGHTPATHSIG","NUMWIDETRACK","CORRCENTFRAC"} + }; +/* {"EMRADIUS","ISOLFRAC","STRIPWIDTH2","NSTRIP","ETHAD2ETTRACKS","ETEM2ETTRACKS","ETTRACKS2ET","", "", "", "", + "NISOLTRK","MVISEFLOW","IPZ0SINTHETASIGLEADTRK","IPSIGLEADLOOSETRK",""}, + {"EMRADIUS","ISOLFRAC","STRIPWIDTH2","NSTRIP","ETHAD2ETTRACKS","ETEM2ETTRACKS","ETTRACKS2ET","DRMIN","DRMAX","TRKWIDTH2","MASSTRKSYS", + "NISOLTRK","MVISEFLOW","", "IPSIGLEADLOOSETRK","TRFLIGHTPATHSIG"}}; +*/ + const string use_author3[NVAR_DEF] = {"","","","","","","","","","TRKWIDTH2","MASSTRKSYS","NISOLTRK","MVISEFLOW","IPZ0SINTHETASIGLEADTRK","","TRFLIGHTPATHSIG"}; + const string use_3trk[NVAR_DEF] = {"","","","","","","","","","TRKWIDTH2","MASSTRKSYS","","","","",""}; + + + map<string,const float*>::const_iterator it_floats; + map<string,const int*>::const_iterator it_ints; + + int prong=m_prongindex; //1pr + + map<string, float> allVariables; + + + float et = 1.; + it_floats = floatVariables->find("ET"); + if (it_floats != floatVariables->end()) { + et=*(it_floats->second); + } + else et=99.; + + + switch (option){ + case 0: //safe + for(unsigned int i=0; i<NVAR_SAFE_3P; i++) { + if (use_safe[prong][i] != "") { + it_floats = floatVariables->find(use_safe[prong][i]); + if (it_floats != floatVariables->end()) { + if ( it_floats->first=="ETTRACKS2ET" ){ + print("Modified etTracks2Et",2); + if (fabs(et)<SMALL) allVariables[it_floats->first]= *(it_floats->second)/et; + else allVariables[it_floats->first] = 999.; + } + else allVariables[it_floats->first]= *(it_floats->second); + } + + it_ints = intVariables->find(use_safe[prong][i]); + if (it_ints != intVariables->end()) { + allVariables[it_ints->first]= *(it_ints->second); + } + + } + } + break; + case 1: //def + if ( author==1 ){ //no track-seed + for(unsigned int i=0; i<NVAR_DEF; i++) { + if (use_author3[i] != "") { + it_floats = floatVariables->find(use_author3[i]); + if (it_floats != floatVariables->end()) { + allVariables[it_floats->first]= *(it_floats->second); + } + + it_ints = intVariables->find(use_author3[i]); + if (it_ints != intVariables->end()) { + allVariables[it_ints->first]= *(it_ints->second); + } + } + } + } + else if ( numtrack!=3 ){ //not exactly 3 tracks + for(unsigned int i=0; i<NVAR_DEF; i++) { + if (use_3trk[i] != "") { + it_floats = floatVariables->find(use_3trk[i]); + if (it_floats != floatVariables->end()) { + allVariables[it_floats->first]= *(it_floats->second); + } + + it_ints = intVariables->find(use_3trk[i]); + if (it_ints != intVariables->end()) { + allVariables[it_ints->first]= *(it_ints->second); + } + } + } + } + else { + for(unsigned int i=0; i<NVAR_DEF; i++) { + if (use_def[prong][i] != "") { + it_floats = floatVariables->find(use_def[prong][i]); + if (it_floats != floatVariables->end()) { + allVariables[it_floats->first]= *(it_floats->second); + } + + it_ints = intVariables->find(use_def[prong][i]); + if (it_ints != intVariables->end()) { + allVariables[it_ints->first]= *(it_ints->second); + } + } + } + } + break; + default: + print("ERROR: getVariables, option > 1",0); + break;;//take any var + } + + return allVariables; + +} + + + + + +float CommonLikelihood::getSingleLLHRatio(const int ivar, const int numtrack, const int author, const float et, const int nvtx, const float value){ + + float LLHR = this->getSimpleSingleLLHRatio( ivar, numtrack, author, et, nvtx, value ); + + //for now hard-coding the pt-bin boundaries (45,100), should be automatized... + float border[]={45.,100.}; + for(int b=0;b<2;b++){ + float closetoborder=et/1000.-(border[b]); + + double uppBorder = 10.0; + double lowBorder = 10.0; + + if( border[b] >= 100. && numtrack == 1 && !(m_doTrigger) ) { + uppBorder = 60.0; + lowBorder = 30.0; + } + + if( closetoborder >= 0 && fabs(closetoborder) < uppBorder ) { + float nextbin = (border[b]-lowBorder/2.0)*1000.0; + float LLHRnext = this->getSimpleSingleLLHRatio( ivar, numtrack, author, nextbin, nvtx, value ); + LLHR = LLHR*((uppBorder+fabs(closetoborder))/(uppBorder*2.0)) + LLHRnext*((uppBorder-fabs(closetoborder))/(uppBorder*2.0)); + } + + + if( closetoborder < 0 && fabs(closetoborder) < lowBorder ) { + float nextbin = (border[b]+uppBorder/2.0)*1000.0; + float LLHRnext = this->getSimpleSingleLLHRatio( ivar, numtrack, author, nextbin, nvtx, value ); + LLHR = LLHR*((lowBorder+fabs(closetoborder))/(lowBorder*2.0)) + LLHRnext*((lowBorder-fabs(closetoborder))/(lowBorder*2.0)); + } + } + return LLHR; +} + + + +float CommonLikelihood::getSimpleSingleLLHRatio(const int ivar, const int numtrack, const int author, const float et, const int nvtx, const float value){ + + const std::string prongs[]={"","1prong","","3prong"}; + const std::string classes[]={"both","calo"}; + + int prongcat=1; int authorcat=0; + if(numtrack >= 2){ prongcat=3; authorcat=0; } + if(author==2) return -1111; + std::string prongType=prongs[prongcat]; + std::string authorType=classes[authorcat]; + + char text[100]; + sprintf(text,"_v%d",ivar); + std::string hNameLong = "hpdf"; + hNameLong+=+"_"+prongType; + hNameLong+=+"_"+authorType; + hNameLong.append(text); + TH3F *hratio = m_pdfHistogramsRatio[hNameLong]; + + m="tau nentries: "; m+=hratio->GetEntries(); m+=", nbins: "; m+=hratio->GetNbinsX(); + print(m,2); + TAxis *xaxis = hratio->GetXaxis(); + TAxis *yaxis = hratio->GetYaxis(); + TAxis *zaxis = hratio->GetZaxis(); + + float xMin = xaxis->GetXmin(); + float xMax = xaxis->GetXmax(); // + + m=""; m+=xMin; m+=" - "; m+=xMax; + print(m,2); + float etMax = yaxis->GetXmax(); + float vtxMax = zaxis->GetXmax(); + + int p_nvtx=nvtx; + float temp_et=et; + if ( nvtx>vtxMax ) p_nvtx=(int) vtxMax; + if ( temp_et/1000.0>etMax ) temp_et=(etMax*1000)-1; + if (value<xMin) return 0; + + float varLL = this->Interpolate(hratio,value,temp_et/1000.0,p_nvtx); + + m="llhratio value of this var: "; m+=varLL; + print(m,1); + + return varLL; +} + + + +bool CommonLikelihood::readPDFHistograms() { + print("in readPDFHistograms()",2); + + m_tauFile = new TFile(m_tauFilename.c_str()); + m_jetFile = new TFile(m_jetFilename.c_str()); + + const int nProngdirs=2; + const int nClassdirs=1; + const std::string prongs[nProngdirs]={"1prong","3prong"}; + const std::string classes[nClassdirs]={"both"/*,"calo"*/}; + + for (int iProng=0; iProng<nProngdirs; iProng++) { + for (int iClass=0; iClass<nClassdirs; iClass++) { + std::string prongDir = prongs[iProng]; + std::string classDir = classes[iClass]; + for (int ivar=0; ivar<=NVAR; ivar++) { + + char text[100]; + sprintf(text,"_v%d",ivar); + std::string hNameLong = "hpdf"; + hNameLong+=+"_"+prongDir; + hNameLong+=+"_"+classDir; + hNameLong.append(text); + std::string hname = prongDir+"/"+classDir+"/"+hNameLong; + + TH3F* hTmp_tau = (TH3F*)m_tauFile->Get(hname.c_str()); + TH3F* hTmp_jet = (TH3F*)m_jetFile->Get(hname.c_str()); + + m_pdfHistogramsTau[hNameLong] = (TH3F*)hTmp_tau; + m_pdfHistogramsJet[hNameLong] = (TH3F*)hTmp_jet; + + } + } + } + + return true; +} + +bool CommonLikelihood::readLMTCuts() { + print("in readLMTCuts()",2); + + m_cutFile = new TFile(m_cutFilename.c_str()); + if(m_cutFile==0) return false; //assert(m_cutFile!=0); + tg_loose_cuts_1P = (TGraph*) m_cutFile->Get("1prong/loose"); + tg_medium_cuts_1P = (TGraph*) m_cutFile->Get("1prong/medium"); + tg_tight_cuts_1P = (TGraph*) m_cutFile->Get("1prong/tight"); + + if(tg_loose_cuts_1P==0 || tg_medium_cuts_1P==0 || tg_tight_cuts_1P==0) + return false; + m_vLMTCuts1P.push_back(tg_loose_cuts_1P); + m_vLMTCuts1P.push_back(tg_medium_cuts_1P); + m_vLMTCuts1P.push_back(tg_tight_cuts_1P); + tg_loose_cuts_3P = (TGraph*) m_cutFile->Get("3prong/loose"); + tg_medium_cuts_3P = (TGraph*) m_cutFile->Get("3prong/medium"); + tg_tight_cuts_3P = (TGraph*) m_cutFile->Get("3prong/tight"); + + if(tg_loose_cuts_3P==0 || tg_medium_cuts_3P==0 || tg_tight_cuts_3P==0) + return false; + m_vLMTCuts3P.push_back(tg_loose_cuts_3P); + m_vLMTCuts3P.push_back(tg_medium_cuts_3P); + m_vLMTCuts3P.push_back(tg_tight_cuts_3P); + + return true; +} + + +bool CommonLikelihood::smoothPDFHistograms() { + print("in smoothPDFHistograms()",2); + + const int nProngdirs=2; + const int nClassdirs=1; + const std::string prongs[nProngdirs]={"1prong","3prong"}; + const std::string classes[nClassdirs]={"both"/*,"calo"*/}; + + for (int iProng=0; iProng<nProngdirs; iProng++) { + for (int iClass=0; iClass<nClassdirs; iClass++) { + std::string prongDir = prongs[iProng]; + std::string classDir = classes[iClass]; + for (int ivar=0; ivar<=NVAR; ivar++) { + char text[100]; + sprintf(text,"_v%d",ivar); + std::string hNameLong = "hpdf"; + hNameLong+=+"_"+prongDir; + hNameLong+=+"_"+classDir; + hNameLong.append(text); + if (m_pdfHistogramsTau[hNameLong] && m_pdfHistogramsJet[hNameLong]){ + if (m_smooth) { + this->smooth3D(m_pdfHistogramsTau[hNameLong]); + this->smooth3D(m_pdfHistogramsJet[hNameLong]); + } + m_pdfHistogramsRatio[hNameLong] = this->divideLog(m_pdfHistogramsTau[hNameLong],m_pdfHistogramsJet[hNameLong]); + } + } + } + } + return true; +} + +void CommonLikelihood::smooth3D(TH3F* hTmp){ + + for (int i=1;i<=hTmp->GetNbinsY();i++){ + for (int j=1;j<=hTmp->GetNbinsZ();j++){ + TH1D* tmp = hTmp->ProjectionX("projX",i,i,j,j,""); + tmp->Smooth(5); + for (int k=1;k<=tmp->GetNbinsX();k++) + hTmp->SetBinContent(k,i,j,tmp->GetBinContent(k)); + delete tmp; tmp=0; + } + } +} + +TH3F* CommonLikelihood::divideLog(TH3F* hTmpTau, TH3F* hTmpJet){ + if ( + hTmpTau->GetNbinsX() != hTmpJet->GetNbinsX() || + hTmpTau->GetNbinsY() != hTmpJet->GetNbinsY() || + hTmpTau->GetNbinsZ() != hTmpJet->GetNbinsZ() + ) return 0; + TH3F* hTmpRatio = new TH3F(*hTmpTau); + hTmpRatio->Reset(); + for (int i=0;i<=hTmpTau->GetNbinsY()+1;i++){ + for (int j=0;j<=hTmpTau->GetNbinsZ()+1;j++){ + for (int k=0;k<=hTmpTau->GetNbinsX()+1;k++) { + float tauLL = hTmpTau->GetBinContent(k,i,j); + float jetLL = hTmpJet->GetBinContent(k,i,j); + if(fabs(jetLL)<SMALL) jetLL = SMALL; + if(!tauLL) tauLL = SMALL; + float varLL=TMath::Log(tauLL/jetLL); + hTmpRatio->SetBinContent(k,i,j,varLL); + } + } + } + return hTmpRatio; +} + +Double_t CommonLikelihood::Interpolate(TH3F* hist, Double_t x, Double_t y, Double_t z) +{ + // Given a point x, approximates the value via linear interpolation + // based on the two nearest bin centers + + + Int_t ibin = hist->FindBin(x,y,z); + Int_t xbin, ybin, zbin; + hist->GetBinXYZ(ibin, xbin, ybin, zbin); + if (!m_smooth) return hist->GetBinContent(ibin); + + Double_t x0,x1,y0,y1; + + if(xbin<=1 || xbin>=hist->GetNbinsX()) { + return hist->GetBinContent(ibin); + } else { + if(x<=hist->GetXaxis()->GetBinCenter(xbin)) { + y0 = hist->GetBinContent(xbin-1, ybin, zbin); + x0 = hist->GetXaxis()->GetBinCenter(xbin-1); + y1 = hist->GetBinContent(xbin, ybin, zbin); + x1 = hist->GetXaxis()->GetBinCenter(xbin); + } else { + y0 = hist->GetBinContent(xbin, ybin, zbin); + x0 = hist->GetXaxis()->GetBinCenter(xbin); + y1 = hist->GetBinContent(xbin+1, ybin, zbin); + x1 = hist->GetXaxis()->GetBinCenter(xbin+1); + } + if (fabs(x1-x0)<SMALL && fabs(x1-x0)!=0.) return y0 + (x-x0)*((y1-y0)/(x1-x0)); + else return 999.; + } +} + +int CommonLikelihood::varNameToNumber(std::string varname) const { + if(varname=="emRadius" || varname=="EMRADIUS" ) return 0; + if(varname=="isolFrac" || varname=="ISOLFRAC" ) return 1; + if(varname=="stripWidth2" || varname=="STRIPWIDTH2" ) return 2; + if(varname=="nStrip" || varname=="NSTRIP" ) return 3; + if(varname=="etHad2etTracks" || varname=="ETHAD2ETTRACKS" ) return 4; + if(varname=="etEM2etTracks" || varname=="ETEM2ETTRACKS" ) return 5; + if(varname=="etTracks2et" || varname=="ETTRACKS2ET" ) return 6; + if(varname=="etEM2Et" || varname=="ETEM2ET" || varname=="EMFRACTIONCALIB" || varname=="EMFRACTIONATEMSCALE" ) return 7; + if(varname=="etOverPtLeadTrk" || varname=="ETOVERPTLEADTRK" ) return 8; + if(varname=="dRmin" || varname=="DRMIN" ) return 9; + if(varname=="dRmax" || varname=="DRMAX" ) return 10; + if(varname=="trkWidth2" || varname=="TRKWIDTH2" ) return 11; + if(varname=="massTrkSys" || varname=="MASSTRKSYS" ) return 12; + if(varname=="nIsolTrk" || varname=="NISOLTRK" ) return 13; + if(varname=="MVisEflow" || varname=="MVISEFLOW" ) return 14; + if(varname=="ipZ0SinThetaSigLeadTrk" || varname=="IPZ0SINTHETASIGLEADTRK" ) return 15; + if(varname=="ipSigLeadLooseTrk" || varname=="IPSIGLEADLOOSETRK" ) return 16; + if(varname=="trFlightPathSig" || varname=="TRFLIGHTPATHSIG" ) return 17; + if(varname=="centFrac" || varname=="CENTFRAC" ) return 18; + if(varname=="numEffClus" || varname=="NUMEFFCLUS" ) return 19; + if(varname=="trkAvgDist" || varname=="TRKAVGDIST" ) return 20; + if(varname=="topoInvMass" || varname=="TOPOINVMASS" ) return 21; + if(varname=="calRadius" || varname=="CALRADIUS" ) return 22; + + if(varname=="ipSigLeadTrk" || varname=="IPSIGLEADTRK" ) return 23; + if(varname=="benchdRLeadTrkLeadCluster" || varname=="BENCHDRLEADTRKLEADCLUSTER" ) return 24; + if(varname=="benchdRLeadTrk2ndLeadCluster" || varname=="BENCHDRLEADTRK2NDLEADCLUSTER" ) return 25; + if(varname=="benchdRLeadCluster2ndLeadCluster" || varname=="BENCHDRLEADCLUSTER2NDLEADCLUSTER" ) return 26; + if(varname=="lead2ClusterEOverAllCusterE" || varname=="LEAD2CLUSTEREOVERALLCLUSTERE" ) return 27; + if(varname=="geoTrackRadius" || varname=="GEOTRACKRADIUS" ) return 28; + if(varname=="geoTrackMass" || varname=="GEOTRACKMASS" ) return 29; + if(varname=="geoCentFrac" || varname=="GEOCENTFRAC" ) return 30; + if(varname=="geoTopoInvMass" || varname=="GEOTOPOINVMASS" ) return 31; + if(varname=="geoCoreEnergyFraction" || varname=="GEOCOREENERGYFRACTION" ) return 32; + if(varname=="geoCoreClusterEMRadius" || varname=="GEOCORECLUSTEREMRADIUS" ) return 33; + if(varname=="geodRLeadTrkLeadCluster" || varname=="GEODRLEADTRKLEADCLUSTER" ) return 34; + if(varname=="geodRLeadTrk2ndLeadCluster" || varname=="GEODRLEADTRK2NDLEADCLUSTER" ) return 35; + if(varname=="geodRLeadCluster2ndLeadCluster" || varname=="GEODRLEADCLUSTER2NDLEADCLUSTER" ) return 36; + if(varname=="geoEClusterOverETau" || varname=="GEOECLUSTEROVERETAU" ) return 37; + if(varname=="NClusters" || varname=="NCLUSTERS" ) return 38; + if(varname=="NeffClusters" || varname=="NEFFCLUSTERS" ) return 39; + if(varname=="effTopoInvMass" || varname=="EFFTOPOINVMASS" ) return 40; + if(varname=="effdRLeadTrkLeadCluster" || varname=="EFFDRLEADTRKLEADCLUSTER" ) return 41; + if(varname=="effdRLeadTrk2ndLeadCluster" || varname=="EFFDRLEADTRK2NDLEADCLUSTER" ) return 42; + if(varname=="effdRLeadCluster2ndLeadCluster" || varname=="EFFDRLEADCLUSTER2NDLEADCLUSTER" ) return 43; + if(varname=="effEClusterOverETau" || varname=="EFFECLUSTEROVERETAU" ) return 44; + if(varname=="Eiso" || varname=="EISO" ) return 45; + if(varname=="ClusterEMRadius" || varname=="CLUSTEREMRADIUS" ) return 46; + if(varname=="ClusterCentFrac" || varname=="CLUSTERCENTFRAC" ) return 47; + if(varname=="effEMRadius" || varname=="EFFEMRADIUS" ) return 48; + if(varname=="effCentFrac" || varname=="EFFCENTFRAC" ) return 49; + if(varname=="numWideTrack" || varname=="NUMWIDETRACK" ) return 50; + if(varname=="charge" || varname=="CHARGE" ) return 51; + if(varname=="nPi0" || varname=="NPI0" ) return 52; + if(varname=="corrcentFrac" || varname=="CORRCENTFRAC" ) return 53; + if(varname=="corrfTrk" || varname=="CORRFTRK" ) return 56; + + + print("ERROR: Variable name not corresponding to a PDF variable: "+varname,2); + return -1; +} + +void CommonLikelihood::splitString(const string& str, vector<string>& substrings, const string& delimiters) const{ + // Skip delimiters at beginning. + string::size_type lastPos = str.find_first_not_of(delimiters, 0); + // Find first "non-delimiter". + string::size_type pos = str.find_first_of(delimiters, lastPos); + + while (string::npos != pos || string::npos != lastPos){ + // Found a token, add it to the vector. + substrings.push_back(str.substr(lastPos, pos - lastPos)); + // Skip delimiters. Note the "not_of" + lastPos = str.find_first_not_of(delimiters, pos); + // Find next "non-delimiter" + pos = str.find_first_of(delimiters, lastPos); + } +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/CutsDecisionTree.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/CutsDecisionTree.cxx new file mode 100644 index 00000000000..fbc709b6466 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/CutsDecisionTree.cxx @@ -0,0 +1,30 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: Cuts.cxx + * + * Author: Noel Dawe (end1@sfu.ca) + */ + +#include "TauDiscriminant/CutsDecisionTree.h" + +float CutsDecisionTree::response(unsigned int level) const { + + DecisionNode* decision = 0; + LeafNode<float>* leafNode = 0; + if (level >= this->trees.size()) return false; + Node* currentNode = this->trees[level].first; + while (!currentNode->isLeaf()) { + decision = static_cast<DecisionNode*>(currentNode); + if (decision->goRight()) { + currentNode = decision->getRightChild(); + } else { + currentNode = decision->getLeftChild(); + } + if (!currentNode) return false; + } + leafNode = static_cast<LeafNode<float>*>(currentNode); + return leafNode->getValue(); +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/EMFCluster.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/EMFCluster.cxx new file mode 100644 index 00000000000..bac23ddbcc6 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/EMFCluster.cxx @@ -0,0 +1,75 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//*******************************************************// +// Name: EMFCluster.cxx // +// Author: Michel Trottier-McDonald <mtm@cern.ch> // +// Description: A simple class to house cluster // +// TLorentzVectors and their associated fractions of // +// energy in different calorimeter layers // +//*******************************************************// + +#include "TauDiscriminant/EMFCluster.h" + +//--------------------------------------------------------- +// Default Constructor +//--------------------------------------------------------- +EMFCluster::EMFCluster() +{} + + +//--------------------------------------------------------- +// Initiate TLorentzVector Contructor +//--------------------------------------------------------- +EMFCluster::EMFCluster(double pt) +{ + m_cluster = TLorentzVector(pt, 0.0, 0.0, 0.0); + m_PSSF = 0.0; + m_EM2F = 0.0; + m_EM3F = 0.0; +} + + + +//--------------------------------------------------------- +// Main constructor +//--------------------------------------------------------- +EMFCluster::EMFCluster(const TLorentzVector& inCluster, + double inPSSF, + double inEM2F, + double inEM3F) +{ + m_cluster = inCluster; + + m_PSSF = inPSSF; + m_EM2F = inEM2F; + m_EM3F = inEM3F; + + update(); +} + + +//--------------------------------------------------------- +// Destructor +//--------------------------------------------------------- +EMFCluster::~EMFCluster() +{} + + +//----------------------------------------------------------- +// Update method +//----------------------------------------------------------- +void EMFCluster::update() +{ + m_HADF = 1 - m_PSSF - m_EM2F - m_EM3F; + m_pseudoHADF = 1 - m_PSSF - m_EM2F; + + double clE = m_cluster.E(); + + m_PSSE = m_PSSF*clE; + m_EM2E = m_EM2F*clE; + m_EM3E = m_EM3F*clE; + m_HADE = m_HADF*clE; + m_pseudoHADE = m_pseudoHADF*clE; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/LinkDef.h b/PhysicsAnalysis/TauID/TauDiscriminant/Root/LinkDef.h new file mode 100644 index 00000000000..c8efc8d9deb --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/LinkDef.h @@ -0,0 +1,38 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef __TAUDISCRIMINANT__ +#define __TAUDISCRIMINANT__ + +#include "TauDiscriminant/MethodBase.h" +#include "TauDiscriminant/MethodBDT.h" +#include "TauDiscriminant/MethodCuts.h" +#include "TauDiscriminant/MethodDummy.h" +#include "TauDiscriminant/MethodLLH.h" +#include "TauDiscriminant/MethodTransform.h" +#include "TauDiscriminant/Types.h" +#include "TauDiscriminant/TauIDReader.h" +#include "TauDiscriminant/TauDetailsManagerStandalone.h" + +#ifdef __CINT__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ namespace TauID; +#pragma link C++ namespace TauID::Types; + +#pragma link C++ enum TauID::Types::MethodType; +#pragma link C++ class TauID::TauIDReader; +#pragma link C++ class TauID::TauDetailsManagerStandalone; +#pragma link C++ class TauID::MethodBase; +#pragma link C++ class TauID::MethodDummy; +#pragma link C++ class TauID::MethodTransform; +#pragma link C++ class TauID::MethodBDT; +#pragma link C++ class TauID::MethodCuts; +#pragma link C++ class TauID::MethodLLH; + +#endif +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodBDT.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodBDT.cxx new file mode 100644 index 00000000000..93648af524f --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodBDT.cxx @@ -0,0 +1,60 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: MethodBDT.cxx + * + * Author: Noel Dawe (end1@sfu.ca) + */ + +#include "TauDiscriminant/MethodBDT.h" + +using namespace TauID; + +float MethodBDT::response() const +{ + if (!this->isBuilt) return -101.; + BoostedDecisionTree* bdt = getCurrentCategory(); + return bdt ? bdt->response() : -201.; +} + +bool MethodBDT::build(const string& filename, bool checkTree) +{ + #ifdef __STANDALONE + TreeReader reader(this->verbose); + #else + TreeReader reader; + #endif + reader.setVariables(&this->floatVariables, &this->intVariables); + this->categoryTree = reader.build(filename,checkTree); + if (this->categoryTree != 0) + { + this->isBuilt = true; + return true; + } + return false; +} + +BoostedDecisionTree* MethodBDT::getCurrentCategory() const +{ + PointerLeafNode<BoostedDecisionTree>* leafNode; + DecisionNode* decision; + Node* currentNode = this->categoryTree; + if (!currentNode) return 0; + while (!currentNode->isLeaf()) + { + decision = static_cast<DecisionNode*>(currentNode); + if (decision->goRight()) + { + currentNode = decision->getRightChild(); + } + else + { + currentNode = decision->getLeftChild(); + } + if (!currentNode) return 0; + } + leafNode = static_cast<PointerLeafNode<BoostedDecisionTree>*>(currentNode); + return leafNode->getValue(); +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodBase.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodBase.cxx new file mode 100644 index 00000000000..4e4b0cc1b0a --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodBase.cxx @@ -0,0 +1,6 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "TauDiscriminant/MethodBase.h" diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodCuts.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodCuts.cxx new file mode 100644 index 00000000000..b2d260eb74d --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodCuts.cxx @@ -0,0 +1,58 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: CutsMethod.cxx + * + * Author: Noel Dawe (end1@sfu.ca) + */ + +#include "TauDiscriminant/MethodCuts.h" + +using namespace TauID; + +float MethodCuts::response(unsigned int level) const +{ + if (!this->isBuilt) return 0.; + CutsDecisionTree* cuts = getCurrentCategory(); + return cuts ? cuts->response(level) : 0.; +} + +bool MethodCuts::build(const string& filename, bool checkTree) +{ + #ifdef __STANDALONE + TreeReader reader(this->verbose); + #else + TreeReader reader; + #endif + reader.setVariables(&this->floatVariables,&this->intVariables); + this->categoryTree = reader.build(filename,checkTree); + if (this->categoryTree != 0) + { + this->isBuilt = true; + return true; + } + return false; +} + +CutsDecisionTree* MethodCuts::getCurrentCategory() const +{ + PointerLeafNode<CutsDecisionTree>* leafNode; + DecisionNode* decision; + Node* currentNode = this->categoryTree; + while (!currentNode->isLeaf()) + { + decision = static_cast<DecisionNode*>(currentNode); + if (decision->goRight()) + { + currentNode = decision->getRightChild(); + } + else + { + currentNode = decision->getLeftChild(); + } + } + leafNode = static_cast<PointerLeafNode<CutsDecisionTree>*>(currentNode); + return leafNode->getValue(); +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodDummy.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodDummy.cxx new file mode 100644 index 00000000000..d90dd811bc8 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodDummy.cxx @@ -0,0 +1,23 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: MethodDummy.cxx + * + * Author: Noel Dawe (end1@sfu.ca) + */ + +#include "TauDiscriminant/MethodDummy.h" + +using namespace TauID; + +float MethodDummy::response() const +{ + return 0.; +} + +bool MethodDummy::build(const string&, bool) +{ + return true; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodLLH.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodLLH.cxx new file mode 100644 index 00000000000..7fbdec7a05e --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodLLH.cxx @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: MethodLLH.cxx + * + * Author: Martin Flechl (mflechl@cern.ch) + */ + +#include "TauDiscriminant/MethodLLH.h" + +using namespace TauID; + +float MethodLLH::response(unsigned int level) const { + + if (llh){ + std::string m="MethodLLH: Calling calcLLHValue, level="; m+=level; m+=",name="; m+=getName(); + print(m); + + if (level==0) { + + llh->calcLLHValue(&this->floatVariables,&this->intVariables,m_option); + + } + + float llhratio=llh->getLLHValue(); + + + if (level==3) return llhratio; + else return llh->response(level,m_option); + } else{ + return -99; + } +} + +bool MethodLLH::build(const string& filename, bool check) { + + print("In MethodLLH::build"); + print("Reminder: The safe and default likelihood will only return the same values as during"); + print(" reconstruction if all required variables are given. This is currently not checked."); + + if (this->getName()=="llhsafe") m_option=0; + else if (this->getName()=="llhdef") m_option=1; + else m_option=2; + + #ifdef __STANDALONE + llh = new CommonLikelihood(this->verbose); + #else + llh = new CommonLikelihood(); + #endif + + check = llh->build(filename); + this->isBuilt=check; + + return check; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodTransform.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodTransform.cxx new file mode 100644 index 00000000000..1a0f0b89de7 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/MethodTransform.cxx @@ -0,0 +1,60 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: MethodTransform.cxx + * + * Author: Noel Dawe (end1@sfu.ca) + */ + +#include "TauDiscriminant/MethodTransform.h" + +using namespace TauID; + +float MethodTransform::response() const +{ + if (!this->isBuilt) return -101.; + Transformation* trans = getCurrentCategory(); + return trans ? trans->response() : -201.; +} + +bool MethodTransform::build(const string& filename, bool checkTree) +{ + #ifdef __STANDALONE + TreeReader reader(this->verbose); + #else + TreeReader reader; + #endif + reader.setVariables(&this->floatVariables,&this->intVariables); + this->categoryTree = reader.build(filename,checkTree); + if (this->categoryTree != 0) + { + this->isBuilt = true; + return true; + } + return false; +} + +Transformation* MethodTransform::getCurrentCategory() const +{ + PointerLeafNode<Transformation>* leafNode; + DecisionNode* decision; + Node* currentNode = this->categoryTree; + if (!currentNode) return 0; + while (!currentNode->isLeaf()) + { + decision = static_cast<DecisionNode*>(currentNode); + if (decision->goRight()) + { + currentNode = decision->getRightChild(); + } + else + { + currentNode = decision->getLeftChild(); + } + if (!currentNode) return 0; + } + leafNode = static_cast<PointerLeafNode<Transformation>*>(currentNode); + return leafNode->getValue(); +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/Node.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/Node.cxx new file mode 100644 index 00000000000..17924b97e6c --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/Node.cxx @@ -0,0 +1,11 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: Node.cxx + * + * Author: Noel Dawe (end1@sfu.ca) + */ + +#include "TauDiscriminant/Node.h" diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/NoiseCorrIsol.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/NoiseCorrIsol.cxx new file mode 100644 index 00000000000..deb0c56587a --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/NoiseCorrIsol.cxx @@ -0,0 +1,210 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//*******************************************************// +// Name: NoiseCorrIsol.cxx // +// Author: Michel Trottier-McDonald <mtm@cern.ch> // +// Description: A class to provide isolation based // +// pileup/underlying event correction to the clusters // +// of tau decays // +//*******************************************************// + +#include "TauDiscriminant/NoiseCorrIsol.h" +#include "math.h" +#include <iostream> + +//--------------------------------------------------------- +// Default Constructor +//--------------------------------------------------------- +NoiseCorrIsol::NoiseCorrIsol() +{} + + +//--------------------------------------------------------- +// Main constructor 1 +//--------------------------------------------------------- +NoiseCorrIsol::NoiseCorrIsol(const TLorentzVector& tau, + const std::vector<TLorentzVector>& clusters, + double innerDR, + double outerDR, + bool eff) + : m_clusters(clusters), + m_tau(tau), + m_innerDR(innerDR), + m_outerDR(outerDR), + m_eff(eff) +{ + m_areaRatio = areaRatio(); +} + + +//--------------------------------------------------------- +// Main constructor 2 +//--------------------------------------------------------- +NoiseCorrIsol::NoiseCorrIsol(const TLorentzVector& tau, + const std::vector<EMFCluster>& clusters, + double innerDR, + double outerDR, + bool eff) + : m_EMFClusters(clusters), + m_tau(tau), + m_innerDR(innerDR), + m_outerDR(outerDR), + m_eff(eff) +{ + m_areaRatio = areaRatio(); +} + + +//--------------------------------------------------------- +// Destructor +//--------------------------------------------------------- +NoiseCorrIsol::~NoiseCorrIsol() +{} + + +//--------------------------------------------------------- +// Ratio of areas calculation +//--------------------------------------------------------- +double NoiseCorrIsol::areaRatio() +{ + double delta = m_outerDR*m_outerDR - m_innerDR*m_innerDR; + if(delta != 0) + return (m_innerDR*m_innerDR)/(delta); + + else return 99999999.0; +} + + +//--------------------------------------------------------- +// Correcting clusters (pure TLorentzVectors) +//--------------------------------------------------------- +std::vector<TLorentzVector> NoiseCorrIsol::correctedClustersTLV() +{ + + // Calculate correction + std::vector<TLorentzVector> innerClusters; + int nCl = (int)m_clusters.size(); + double outerPt = 0; + + //Obtain isolation ring energy (outerE) and inner clusters + for(int i = 0; i < nCl; ++i) + { + double dR = m_tau.DeltaR(m_clusters.at(i)); + + if( (dR < m_outerDR)&&(dR > m_innerDR) ) + outerPt += m_clusters.at(i).Pt(); + + if( dR < m_innerDR ) + innerClusters.push_back(m_clusters.at(i)); + } + + int nInCl = (int)innerClusters.size(); + + double correction = 0.0; + if(nInCl != 0) correction = (outerPt * m_areaRatio) / nInCl; + std::vector<TLorentzVector> finalClusters; + + //Apply correction + for(int i = 0; i < nInCl; ++i) + { + double correctedPt = innerClusters.at(i).Pt() - correction; + double Eta = innerClusters.at(i).Eta(); + double Phi = innerClusters.at(i).Phi(); + + if(correctedPt > 0) //Reject clusters with smaller E than the correction E + { + TLorentzVector corrCluster; + corrCluster.SetPtEtaPhiM(correctedPt, Eta, Phi, 0); + finalClusters.push_back(corrCluster); + } + } + + return finalClusters; +} + + + +//--------------------------------------------------------- +// Correcting clusters (EMFClusters) +//--------------------------------------------------------- +std::vector<EMFCluster> NoiseCorrIsol::correctedClusters() +{ + + // Calculate correction + std::vector<EMFCluster> innerClusters; + int nCl = (int)m_EMFClusters.size(); + double outerPt = 0; + + //Obtain isolation ring energy (outerE) and inner clusters + for(int i = 0; i < nCl; ++i) + { + double dR = m_tau.DeltaR(m_EMFClusters.at(i).TLV()); + + if( (dR < m_outerDR)&&(dR > m_innerDR) ) + outerPt += m_EMFClusters.at(i).TLV().Pt(); + + if( dR < m_innerDR ) + innerClusters.push_back(m_EMFClusters.at(i)); + } + + int nInCl = (int)innerClusters.size(); + double correction = 0.0; + if(nInCl>0) correction = (outerPt * m_areaRatio) / nInCl; + std::vector<EMFCluster> finalClusters; + + //Apply correction + for(int i = 0; i < nInCl; ++i) + { + double correctedPt = innerClusters.at(i).TLV().Pt() - correction; + double Eta = innerClusters.at(i).TLV().Eta(); + double Phi = innerClusters.at(i).TLV().Phi(); + + if(correctedPt > 0) //Reject clusters with smaller E than the correction E + { + TLorentzVector corrCluster; + corrCluster.SetPtEtaPhiM(correctedPt, Eta, Phi, 0); + EMFCluster corrEMFCluster(corrCluster, innerClusters.at(i).PSSF(), innerClusters.at(i).EM2F(), innerClusters.at(i).EM3F()); + finalClusters.push_back(corrEMFCluster); + } + } + + if(m_eff) return effClusters(finalClusters); + return finalClusters; +} + + +//--------------------------------------------------------- +// Calculating effective clusters (post-correction) +//--------------------------------------------------------- +bool EComp(const EMFCluster& iCluster, const EMFCluster& jCluster) +{ return (iCluster.TLV().E() > jCluster.TLV().E()); } + +std::vector<EMFCluster> NoiseCorrIsol::effClusters(const std::vector<EMFCluster>& inputClusters) +{ + int nInputClusters = (int)inputClusters.size(); + std::vector<EMFCluster> inClusters = inputClusters; + + double SumSquare = 0; + double SquareSum = 0; + + for(int i = 0; i < nInputClusters; ++i) + { + double E = inClusters.at(i).TLV().E(); + SquareSum += E; + SumSquare += E*E; + } + + double NEff = 0; + if(SumSquare != 0.0) NEff = ceil((SquareSum*SquareSum)/SumSquare); + + std::sort(inClusters.begin(), inClusters.end(), EComp); + + std::vector<EMFCluster> outputClusters; + + for(int i = 0; i < NEff; ++i) + outputClusters.push_back(inClusters.at(i)); + + return outputClusters; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/Pi0Finder.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/Pi0Finder.cxx new file mode 100644 index 00000000000..382924c1888 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/Pi0Finder.cxx @@ -0,0 +1,526 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//*******************************************************// +// Name: Pi0Finder.cxx // +// Author: Michel Trottier-McDonald <mtm@cern.ch> // +// Description: Main class to find which clusters are // +// the pi0s in tau decays involving neutral pions // +//*******************************************************// + +#include "TauDiscriminant/Pi0Finder.h" +#include "TauDiscriminant/NoiseCorrIsol.h" +#include "math.h" +#include <iostream> + + +//--------------------------------------------------------- +// Default Constructor +//--------------------------------------------------------- +Pi0Finder::Pi0Finder() +{} + + + +//--------------------------------------------------------- +// Constructor 1 +//--------------------------------------------------------- +Pi0Finder::Pi0Finder(const std::vector<TLorentzVector>& tracks, + const std::vector<EMFCluster>& clusters, + bool twoPi0s, + double resImportance, + double turnOnPoint, + double turnOnRate, + double PSSFactor, + double EM2Factor, + double twoPi0Strength, + bool usePseudoHADF, + bool effClusters ) : m_tracks(tracks), + m_usePseudoHADF(usePseudoHADF), + m_twoPi0s(twoPi0s), + m_resImportance(resImportance), + m_turnOnPoint(turnOnPoint), + m_turnOnRate(turnOnRate), + m_PSSFactor(PSSFactor), + m_EM2Factor(EM2Factor), + m_twoPi0Strength(twoPi0Strength), + m_caloE(0), + m_caloHADE(0), + m_trkE(0), + m_trkHADF(0), + m_doubleCountingE(0), + m_applyCorrCluster1(false), + m_applyCorrCluster2(false), + m_keepCluster1(false), + m_keepCluster2(false), + m_noMatch(true), + m_selEMFCluster1(0.000001), + m_selEMFCluster2(0.000001), + m_selEMFClusterNotCorr1(0.000001), + m_selEMFClusterNotCorr2(0.000001) +{ + TLorentzVector trksys; + for(unsigned int i = 0; i < m_tracks.size(); ++i) + trksys += m_tracks[i]; + + NoiseCorrIsol NCI(trksys, clusters, 0.3, 0.4, effClusters); + m_EMFClusters = NCI.correctedClusters(); + + execute(); +} + + +//--------------------------------------------------------- +// Constructor 2 +//--------------------------------------------------------- +Pi0Finder::Pi0Finder(const std::vector<TLorentzVector>& tracks, + const std::vector<TLorentzVector>& clusters, + const std::vector<float>& PSSFs, + const std::vector<float>& EM2Fs, + const std::vector<float>& EM3Fs, + bool twoPi0s, + double resImportance, + double turnOnPoint, + double turnOnRate, + double PSSFactor, + double EM2Factor, + double twoPi0Strength, + bool usePseudoHADF, + bool effClusters ) : m_tracks(tracks), + m_usePseudoHADF(usePseudoHADF), + m_twoPi0s(twoPi0s), + m_resImportance(resImportance), + m_turnOnPoint(turnOnPoint), + m_turnOnRate(turnOnRate), + m_PSSFactor(PSSFactor), + m_EM2Factor(EM2Factor), + m_twoPi0Strength(twoPi0Strength), + m_caloE(0), + m_caloHADE(0), + m_trkE(0), + m_trkHADF(0), + m_doubleCountingE(0), + m_applyCorrCluster1(false), + m_applyCorrCluster2(false), + m_keepCluster1(false), + m_keepCluster2(false), + m_noMatch(true), + m_selEMFCluster1(0.000001), + m_selEMFCluster2(0.000001), + m_selEMFClusterNotCorr1(0.000001), + m_selEMFClusterNotCorr2(0.000001) +{ + std::vector<EMFCluster> tmpEMFClusters = convertToEMFClusters(clusters, PSSFs, EM2Fs, EM3Fs); + for(unsigned int i = 0; i < m_tracks.size(); ++i) + m_trkSys += m_tracks[i]; + NoiseCorrIsol NCI(m_trkSys, tmpEMFClusters, 0.3, 0.4, effClusters); + m_EMFClusters = NCI.correctedClusters(); + execute(); +} + + +//--------------------------------------------------------- +// Destructor +//--------------------------------------------------------- +Pi0Finder::~Pi0Finder() +{} + + +//--------------------------------------------------------- +// Execute the pi0 finding +//--------------------------------------------------------- +void Pi0Finder::execute() +{ + preSelParameters(); + if(m_twoPi0s) select2(); + else select(); + + postSelParameters(); + + if(m_keepCluster1) + { + if(m_applyCorrCluster1) m_selEMFCluster1 = correct(m_selEMFClusterNotCorr1); + else m_selEMFCluster1 = m_selEMFClusterNotCorr1; + } + + if(m_keepCluster2) + { + if(m_applyCorrCluster2) m_selEMFCluster2 = correct(m_selEMFClusterNotCorr2); + else m_selEMFCluster2 = m_selEMFClusterNotCorr2; + } +} + + +//--------------------------------------------------------- +// Parameters to be used in the selection +//--------------------------------------------------------- +void Pi0Finder::preSelParameters() +{ + //Build the track system + int ntracks = (int)m_tracks.size(); + + m_trkE = 0; + + for(int i = 0; i < ntracks; ++i) + m_trkE += m_tracks.at(i).E(); + + //Calculate calo quantities + int nclusters = (int)m_EMFClusters.size(); + m_caloE = 0; + m_caloHADE = 0; + + for(int i = 0; i < nclusters; ++i) + { + double clE = m_EMFClusters.at(i).TLV().E(); + double clHADE = m_EMFClusters.at(i).pseudoHADE(); + if(!m_usePseudoHADF) + clHADE = m_EMFClusters.at(i).HADE(); + + m_caloE += clE; + m_caloHADE += clHADE; + } + if(m_trkE != 0) m_trkHADF = m_caloHADE/m_trkE; +} + + +//--------------------------------------------------------- +// Calculate scores and select cluster with highest score +//--------------------------------------------------------- +void Pi0Finder::select() +{ + double pi0ScoreMin = 0.0; + EMFCluster cl1; + int nclusters = (int)m_EMFClusters.size(); + + for(int i = 0; i < nclusters; ++i) + { + double clE = m_EMFClusters.at(i).TLV().E(); + double HADF = m_EMFClusters.at(i).HADF(); + double rawRecoE = m_caloE - m_trkE; + double rawERes = 999999.0; + if(rawRecoE != 0) rawERes = sqrt(fabs(clE/rawRecoE - 1.0)); + double PSSE = m_EMFClusters.at(i).PSSE(); + double pi0Score = PSSE/(HADF + m_resImportance*rawERes + 0.0000001); + if(pi0Score > pi0ScoreMin) + { + pi0ScoreMin = pi0Score; + cl1 = m_EMFClusters.at(i); + m_noMatch = false; + } + } + if(!m_noMatch) + m_selEMFClusterNotCorr1 = cl1; +} + + + +//--------------------------------------------------------- +// Calculate scores and select pair of clusters with +// highest score +//--------------------------------------------------------- +void Pi0Finder::select2() +{ + double pi0ScoreMin = 0.0; + EMFCluster cl1; + EMFCluster cl2; + + int nclusters = (int)m_EMFClusters.size(); + + for(int i = 0; i < nclusters; ++i) + { + + double clE1 = m_EMFClusters.at(i).TLV().E(); + double clEta1 = m_EMFClusters.at(i).TLV().Eta(); + double HADF1 = m_EMFClusters.at(i).HADF(); + double rawRecoE1 = m_caloE - m_trkE; + double rawERes1 = 9999999.0; + if(rawRecoE1 != 0) rawERes1 = sqrt(fabs(clE1/rawRecoE1 - 1.0)); + double PSSE1 = m_EMFClusters.at(i).PSSE(); + + double pi0Score1 = PSSE1/(HADF1 + m_resImportance*rawERes1 + 0.0000001); + + if((pi0Score1 > pi0ScoreMin) && (fabs(clEta1) < 5.0)) + { + pi0ScoreMin = pi0Score1; + cl1 = m_EMFClusters.at(i); + TLorentzVector empty; + EMFCluster EMFempty(empty, 0, 0, 0); + cl2 = EMFempty; + m_noMatch = false; + m_keepCluster1 = true; + m_keepCluster2 = false; + } + + for(int j = 0; j < nclusters; ++j) + { + if(j > i) // Do not pair a cluster with itself + { + double clE_i = m_EMFClusters.at(i).TLV().E(); + double clE_j = m_EMFClusters.at(j).TLV().E(); + double clEta_i = m_EMFClusters.at(i).TLV().Eta(); + double clEta_j = m_EMFClusters.at(j).TLV().Eta(); + double HADE_i = m_EMFClusters.at(i).HADE(); + double HADE_j = m_EMFClusters.at(j).HADE(); + double clE = clE_i + clE_j; + double HADF = 0.0; + if(clE != 0) HADF = (HADE_i + HADE_j)/clE; + double rawRecoE = m_caloE - m_trkE; + double rawERes = 999999.0; + if(rawRecoE != 0) rawERes = sqrt(fabs(clE/rawRecoE - 1.0)); + double PSSE_i = m_EMFClusters.at(i).PSSE(); + double PSSE_j = m_EMFClusters.at(j).PSSE(); + double PSSE = PSSE_i + PSSE_j; + + double pi0Score = m_twoPi0Strength*PSSE/(HADF + m_resImportance*rawERes + 0.0000001); + + if((pi0Score > pi0ScoreMin) &&(fabs(clEta_i) < 5.0 && fabs(clEta_j) < 5.0)) + { + pi0ScoreMin = pi0Score; + cl1 = m_EMFClusters.at(i); + cl2 = m_EMFClusters.at(j); + m_noMatch = false; + m_keepCluster1 = true; + m_keepCluster2 = true; + } + } + } + } + if(!m_noMatch) + { + m_selEMFClusterNotCorr1 = cl1; + m_selEMFClusterNotCorr2 = cl2; + } +} + + + + +//--------------------------------------------------------- +// Parameters to be used in the correction +//--------------------------------------------------------- +void Pi0Finder::postSelParameters() +{ + double clE1 = 0.0; + double clEta1 = 10.0; + double clE2 = 0.0; + double clEta2 = 10.0; + + if(m_keepCluster1) + { + clE1 = m_selEMFClusterNotCorr1.TLV().E(); + clEta1 = m_selEMFClusterNotCorr1.TLV().Eta(); + } + + if(m_keepCluster2) + { + clE2 = m_selEMFClusterNotCorr2.TLV().E(); + clEta2 = m_selEMFClusterNotCorr2.TLV().Eta(); + } + + + double DCTwoClusters = 1.0; + double DCCluster1 = 1.0; + double DCCluster2 = 1.0; + + if(m_caloE > 0.0) + { + DCTwoClusters = (clE1 + clE2 + m_trkE)/m_caloE; + DCCluster1 = (clE1 + m_trkE)/m_caloE; + DCCluster2 = (clE2 + m_trkE)/m_caloE; + + } + + bool TwoClusterCorrection = (DCTwoClusters > m_turnOnPoint); + bool Cluster1Correction = (DCCluster1 > m_turnOnPoint); + bool Cluster2Correction = (DCCluster1 > m_turnOnPoint); + + if((clE1 > 0.0 && clEta1 < 5.0) && (clE2 > 0.0 && clEta2 < 5.0)) + { + m_doubleCountingE = DCTwoClusters; + + m_keepCluster1 = true; + m_keepCluster2 = true; + + if(TwoClusterCorrection) + { + if(Cluster1Correction) m_applyCorrCluster1 = true; + if(Cluster2Correction) m_applyCorrCluster2 = true; + + if(!Cluster1Correction && !Cluster2Correction) + { + if(DCCluster1 > DCCluster2) m_applyCorrCluster1 = true; + else m_applyCorrCluster2 = true; + } + } + } + + else if((clE1 == 0.0 || clEta1 > 5.0) && (clE2 > 0.0 && clEta2 < 5.0)) + { + m_doubleCountingE = DCCluster2; + m_keepCluster1 = false; + m_keepCluster2 = true; + if(Cluster2Correction) m_applyCorrCluster2 = true; + } + + else if((clE2 == 0.0 || clEta2 > 5.0) && (clE1 > 0.0 && clEta1 < 5.0)) + { + m_doubleCountingE = DCCluster1; + m_keepCluster1 = true; + m_keepCluster2 = false; + if(Cluster1Correction) m_applyCorrCluster1 = true; + } + + else + { + m_doubleCountingE = 0; + m_applyCorrCluster1 = false; + m_applyCorrCluster2 = false; + m_keepCluster1 = false; + m_keepCluster2 = false; + m_noMatch = true; + + } +} + + +//--------------------------------------------------------- +// Contamination Correction +//--------------------------------------------------------- +EMFCluster Pi0Finder::correct(const EMFCluster& cl) +{ + //Start by extracting the EMFCluster since a new one will have to be built + + double E = cl.TLV().E(); + double Eta = cl.TLV().Eta(); + double Phi = cl.TLV().Phi(); + double M = cl.TLV().M(); + double PSSF = cl.PSSF(); + double EM2F = cl.EM2F(); + double EM3F = cl.EM3F(); + double HADE = cl.HADE(); +// double HADF = cl.HADF(); + + if(m_usePseudoHADF) + { + HADE = cl.pseudoHADE(); +// HADF = cl.pseudoHADF(); + } + double PSSE = cl.PSSE(); + double EM2E = cl.EM2E(); + + double ChPiContaminationE = m_trkE; + if(m_trkHADF > 0.0) ChPiContaminationE = HADE/m_trkHADF; + double corrE = (E - ChPiContaminationE); + double corrE2 = 0.0; + if(m_doubleCountingE > 0.0) corrE2 = (m_PSSFactor*PSSE + m_EM2Factor*EM2E)/m_doubleCountingE; + + double corrScale = -exp(m_turnOnRate*(m_turnOnPoint - m_doubleCountingE)) + 1; + + //If there is substantial hadronic energy, use trkHADF + TLorentzVector newCl; + double effE = E; + if(m_caloHADE > 0.0) effE = (1 - corrScale)*E + corrScale*((1-HADE/m_caloHADE)*corrE2 + (HADE/m_caloHADE)*corrE); + + //Correct direction + double corrPt = effE/cosh(Eta); + + newCl.SetPtEtaPhiM(corrPt, Eta, Phi, M); + + EMFCluster newEMFCl(newCl, PSSF, EM2F, EM3F); + + return newEMFCl; +} + + +//--------------------------------------------------------- +// give pi0 Mass +//--------------------------------------------------------- +EMFCluster Pi0Finder::giveMass(const EMFCluster& cl) +{ + double Pt = cl.TLV().Pt(); + double Eta = cl.TLV().Eta(); + double Phi = cl.TLV().Phi(); + double PSSF = cl.PSSF(); + double EM2F = cl.EM2F(); + double EM3F = cl.EM3F(); + double mass = 135; + + TLorentzVector newTLV; + newTLV.SetPtEtaPhiM(Pt, Eta, Phi, mass); + return EMFCluster(newTLV, PSSF, EM2F, EM3F); +} + + +//--------------------------------------------------------- +// Return reconstructed visible tau +//--------------------------------------------------------- +TLorentzVector Pi0Finder::visTauTLV() const +{ + int ntracks = (int)m_tracks.size(); + TLorentzVector trksys; + + for(int i = 0; i < ntracks; ++i) + { + double Pt = m_tracks.at(i).Pt(); + double Eta = m_tracks.at(i).Eta(); + double Phi = m_tracks.at(i).Phi(); + + TLorentzVector trk; + trk.SetPtEtaPhiM(Pt, Eta, Phi, 140); + trksys += trk; + } + + TLorentzVector visTau = trksys; + if(!m_noMatch) + { + TLorentzVector pi0s; + + if(m_twoPi0s) + { + double pi0sPt = m_selEMFCluster1.TLV().Pt() + m_selEMFCluster2.TLV().Pt(); + TLorentzVector pi0sdirection = m_selEMFCluster1.TLV() + m_selEMFCluster2.TLV(); + double pi0sEta = pi0sdirection.Eta(); + double pi0sPhi = pi0sdirection.Phi(); + + + pi0s.SetPtEtaPhiM(pi0sPt, pi0sEta, pi0sPhi, 135); + } + else + pi0s.SetPtEtaPhiM(m_selEMFCluster1.TLV().Pt(), m_selEMFCluster1.TLV().Eta(), m_selEMFCluster1.TLV().Phi(), 135); + + visTau += pi0s; + + } + + return visTau; +} + + +//--------------------------------------------------------- +// Converts the 4 std::vectors to 1 EMFCluster std::vector +//--------------------------------------------------------- + +std::vector<EMFCluster> Pi0Finder::convertToEMFClusters(const std::vector<TLorentzVector>& clusters, + const std::vector<float>& PSSFs, + const std::vector<float>& EM2Fs, + const std::vector<float>& EM3Fs) +{ + int clsize = (int)clusters.size(); + int pssfsize = (int)PSSFs.size(); + int em2fsize = (int)EM2Fs.size(); + int em3fsize = (int)EM3Fs.size(); + + std::vector<EMFCluster> emfclusters; + + if(clsize == pssfsize && pssfsize == em2fsize && em2fsize == em3fsize) + { + for(int i = 0; i < clsize; ++i) + { + EMFCluster emfcl(clusters.at(i), PSSFs.at(i), EM2Fs.at(i), EM3Fs.at(i)); + emfclusters.push_back(emfcl); + } + } + + return emfclusters; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/TauDetailsManagerStandalone.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/TauDetailsManagerStandalone.cxx new file mode 100644 index 00000000000..f1b1c143bfd --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/TauDetailsManagerStandalone.cxx @@ -0,0 +1,356 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + /** + * file: TauDetailsManagerStandalone.cxx + * + * Author: Pawel malecki (Pawel.Malecki@cern.ch) + */ + + +#include "TauDiscriminant/TauDetailsManagerStandalone.h" + +#include <utility> +#include <iostream> +#include <TFile.h> +#include <math.h> + +// redefine the macro to print strings instead of enums as in TauDetails.h +#undef ENUM_OR_STRING +#define ENUM_OR_STRING( x ) #x + +using namespace std; +using namespace TauID; + +// Arrays of the string representations of the detail names + +namespace Details +{ + + string IntTauDetailStringS[] = + { + INT_TAU_DETAILS + }; + + string FloatTauDetailStringS[] = + { + FLOAT_TAU_DETAILS + }; + + string IntEventDetailStringS[] = + { + INT_EVENT_DETAILS + }; + + string FloatEventDetailStringS[] = + { + FLOAT_EVENT_DETAILS + }; +} + +// The default value for all details +const float TauDetailsManagerStandalone::LOW_NUMBER = -1111.; + +TauDetailsManagerStandalone::TauDetailsManagerStandalone(TTree *tree) { + + + //hard-coded for a while + m_clusterCone = 0.2; + if(tree) m_tree = tree; + + // Initialize the vector containing the tau-based variables + this->float_data = vector<float>(Details::__FloatTauDetail__END__+1, LOW_NUMBER); + this->int_data = vector<int>(Details::__IntTauDetail__END__+1, int(LOW_NUMBER)); + + // Initialize the vector containing the event-based variables + this->float_event_data = vector<float>(Details::__FloatEventDetail__END__+1, LOW_NUMBER); + this->int_event_data = vector<int>(Details::__IntEventDetail__END__+1, int(LOW_NUMBER)); + + // Maps of the string representations to the addresses of the values in the above vectors + unsigned int i; + for (i = 0; i < this->float_data.size()-1; ++i) + { + this->float_details.insert(pair<string,float*>(Details::FloatTauDetailStringS[i],&this->float_data[i])); + } + for (i = 0; i < this->float_event_data.size()-1; ++i) + { + this->float_details.insert(pair<string,float*>(Details::FloatEventDetailStringS[i],&this->float_event_data[i])); + } + for (i = 0; i < this->int_data.size()-1; ++i) + { + this->int_details.insert(pair<string,int*>(Details::IntTauDetailStringS[i],&this->int_data[i])); + } + for (i = 0; i < this->int_event_data.size()-1; ++i) + { + this->int_details.insert(pair<string,int*>(Details::IntEventDetailStringS[i],&this->int_event_data[i])); + } + + m_tree = 0; + + + tau_charge = 0; + tau_author = 0; + tau_numTrack = 0; + tau_seedCalo_nWideTrk = 0; + tau_eta = 0; + tau_phi = 0; + tau_pt = 0; + tau_seedCalo_trkAvgDist = 0; + tau_etOverPtLeadTrk = 0; + tau_calcVars_EMFractionAtEMScale = 0; + tau_TRTHTOverLT_LeadTrk = 0; + tau_seedCalo_dRmax = 0; + tau_leadTrack_eta = 0; + tau_calcVars_ChPiEMEOverCaloEME = 0; + tau_seedTrk_secMaxStripEt = 0; + tau_seedTrk_hadLeakEt = 0; + tau_seedTrk_sumEMCellEtOverLeadTrkPt = 0; + tau_calcVars_corrFTrk = 0; + tau_calcVars_corrCentFrac = 0; + tau_seedCalo_isolFrac = 0; + tau_seedCalo_hadRadius = 0; + tau_calcVars_PSSFraction = 0; + tau_seedCalo_nStrip = 0; + tau_massTrkSys = 0; + tau_ipSigLeadTrk = 0; + tau_trFlightPathSig = 0; + tau_calcVars_EMPOverTrkSysP = 0; + evt_calcVars_numGoodVertices = -1111; + tau_pi0_n = 0; + tau_pi0_vistau_m = 0; + tau_pi0_vistau_pt = 0; + tau_leadTrkPt = 0; + tau_seedCalo_etEMAtEMScale = 0; + tau_seedCalo_etHadAtEMScale = 0; + tau_leadTrack_phi = 0; + + b_tau_charge = 0; + b_tau_author = 0; + b_tau_numTrack = 0; + b_tau_seedCalo_nWideTrk = 0; + b_tau_eta = 0; + b_tau_phi = 0; + b_tau_pt = 0; + b_tau_seedCalo_trkAvgDist = 0; + b_tau_etOverPtLeadTrk = 0; + b_tau_calcVars_EMFractionAtEMScale = 0; + b_tau_TRTHTOverLT_LeadTrk = 0; + b_tau_seedCalo_dRmax = 0; + b_tau_leadTrack_eta = 0; + b_tau_calcVars_ChPiEMEOverCaloEME = 0; + b_tau_seedTrk_secMaxStripEt = 0; + b_tau_seedTrk_hadLeakEt = 0; + b_tau_seedTrk_sumEMCellEtOverLeadTrkPt = 0; + b_tau_calcVars_corrFTrk = 0; + b_tau_calcVars_corrCentFrac = 0; + b_tau_seedCalo_isolFrac = 0; + b_tau_seedCalo_hadRadius = 0; + b_tau_calcVars_PSSFraction = 0; + b_tau_seedCalo_nStrip = 0; + b_tau_massTrkSys = 0; + b_tau_ipSigLeadTrk = 0; + b_tau_trFlightPathSig = 0; + b_tau_calcVars_EMPOverTrkSysP = 0; + + b_evt_calcVars_numGoodVertices = 0; + b_tau_pi0_n = 0; + b_tau_pi0_vistau_m = 0; + b_tau_pi0_vistau_pt = 0; + + b_tau_leadTrkPt = 0; + b_tau_seedTrk_sumEMCellEtOverLeadTrkPt = 0; + b_tau_seedCalo_etEMAtEMScale = 0; + b_tau_seedCalo_etHadAtEMScale = 0; + b_tau_leadTrack_eta = 0; + b_tau_leadTrack_phi = 0; + + + doTrigger = false; +} +bool TauDetailsManagerStandalone::initTree(TTree* tree) +{ + if(!tree) return false; + m_tree = (TTree*)tree;//->Clone("newtree"); + m_tree->SetBranchStatus("evt_calcVars_numGoodVertices",1); + m_tree->SetBranchAddress("evt_calcVars_numGoodVertices",&evt_calcVars_numGoodVertices,&b_evt_calcVars_numGoodVertices); + m_tree->SetBranchStatus("tau_*",1); + m_tree->SetBranchAddress("tau_charge",&tau_charge,&b_tau_charge); + m_tree->SetBranchAddress("tau_author",&tau_author,&b_tau_author); + m_tree->SetBranchAddress("tau_numTrack",&tau_numTrack,&b_tau_numTrack); + m_tree->SetBranchAddress("tau_seedCalo_nWideTrk",&tau_seedCalo_nWideTrk,&b_tau_seedCalo_nWideTrk); + m_tree->SetBranchAddress("tau_eta",&tau_eta,&b_tau_eta); + m_tree->SetBranchAddress("tau_phi",&tau_phi,&b_tau_phi); + m_tree->SetBranchAddress("tau_pt",&tau_pt,&b_tau_pt); + m_tree->SetBranchAddress("tau_seedCalo_trkAvgDist",&tau_seedCalo_trkAvgDist,&b_tau_seedCalo_trkAvgDist); + m_tree->SetBranchAddress("tau_etOverPtLeadTrk",&tau_etOverPtLeadTrk,&b_tau_etOverPtLeadTrk); + m_tree->SetBranchAddress("tau_calcVars_EMFractionAtEMScale",&tau_calcVars_EMFractionAtEMScale,&b_tau_calcVars_EMFractionAtEMScale); + m_tree->SetBranchAddress("tau_TRTHTOverLT_LeadTrk",&tau_TRTHTOverLT_LeadTrk,&b_tau_TRTHTOverLT_LeadTrk); + m_tree->SetBranchAddress("tau_seedCalo_dRmax",&tau_seedCalo_dRmax,&b_tau_seedCalo_dRmax); + m_tree->SetBranchAddress("tau_leadTrack_eta",&tau_leadTrack_eta,&b_tau_leadTrack_eta); + m_tree->SetBranchAddress("tau_calcVars_ChPiEMEOverCaloEME",&tau_calcVars_ChPiEMEOverCaloEME,&b_tau_calcVars_ChPiEMEOverCaloEME); + m_tree->SetBranchAddress("tau_seedTrk_secMaxStripEt",&tau_seedTrk_secMaxStripEt,&b_tau_seedTrk_secMaxStripEt); + m_tree->SetBranchAddress("tau_seedTrk_hadLeakEt",&tau_seedTrk_hadLeakEt,&b_tau_seedTrk_hadLeakEt); + m_tree->SetBranchAddress("tau_seedTrk_sumEMCellEtOverLeadTrkPt",&tau_seedTrk_sumEMCellEtOverLeadTrkPt,&b_tau_seedTrk_sumEMCellEtOverLeadTrkPt); + m_tree->SetBranchAddress("tau_calcVars_corrFTrk",&tau_calcVars_corrFTrk,&b_tau_calcVars_corrFTrk); + m_tree->SetBranchAddress("tau_calcVars_corrCentFrac",&tau_calcVars_corrCentFrac,&b_tau_calcVars_corrCentFrac); + m_tree->SetBranchAddress("tau_seedCalo_isolFrac",&tau_seedCalo_isolFrac,&b_tau_seedCalo_isolFrac); + m_tree->SetBranchAddress("tau_seedCalo_hadRadius",&tau_seedCalo_hadRadius,&b_tau_seedCalo_hadRadius); + m_tree->SetBranchAddress("tau_calcVars_PSSFraction",&tau_calcVars_PSSFraction,&b_tau_calcVars_PSSFraction); + m_tree->SetBranchAddress("tau_calcVars_EMPOverTrkSysP",&tau_calcVars_EMPOverTrkSysP,&b_tau_calcVars_EMPOverTrkSysP); + m_tree->SetBranchAddress("tau_seedCalo_nStrip",&tau_seedCalo_nStrip,&b_tau_seedCalo_nStrip); + m_tree->SetBranchAddress("tau_massTrkSys",&tau_massTrkSys,&b_tau_massTrkSys); + m_tree->SetBranchAddress("tau_ipSigLeadTrk",&tau_ipSigLeadTrk,&b_tau_ipSigLeadTrk); + m_tree->SetBranchAddress("tau_trFlightPathSig",&tau_trFlightPathSig,&b_tau_trFlightPathSig); + m_tree->SetBranchAddress("tau_pi0_n",&tau_pi0_n,&b_tau_pi0_n); + m_tree->SetBranchAddress("tau_pi0_vistau_m",&tau_pi0_vistau_m,&b_tau_pi0_vistau_m); + m_tree->SetBranchAddress("tau_pi0_vistau_pt",&tau_pi0_vistau_pt,&b_tau_pi0_vistau_pt); + + m_tree->SetBranchAddress("tau_leadTrkPt",&tau_leadTrkPt,&b_tau_leadTrkPt); + m_tree->SetBranchAddress("tau_seedCalo_etEMAtEMScale",&tau_seedCalo_etEMAtEMScale,&b_tau_seedCalo_etEMAtEMScale); + m_tree->SetBranchAddress("tau_seedCalo_etHadAtEMScale",&tau_seedCalo_etHadAtEMScale,&b_tau_seedCalo_etHadAtEMScale); + + m_tree->SetBranchAddress("tau_leadTrack_phi",&tau_leadTrack_phi,&b_tau_leadTrack_phi); + + + + m_tree->SetMakeClass(1); + return true; + +} + + +bool TauDetailsManagerStandalone::updateEvent(int entry) +{ + // Reset the buffers at the beginning of each event + this->float_event_data.assign(this->float_event_data.size(), LOW_NUMBER); + this->int_event_data.assign(this->int_event_data.size(), int(LOW_NUMBER)); + + if(!m_tree){ + cout<<"ERROR: no TTree assigned!"<<endl; + return false; + + } + m_tree->GetEntry(entry); + + + this->int_event_data[Details::NUM_PILEUP_AND_PRIMARY_VERTICES] = evt_calcVars_numGoodVertices; + + + return true; +} + +bool TauDetailsManagerStandalone::update(unsigned int itau) { + + // Reset the buffers before setting the variables of each tau + this->float_data.assign(this->float_data.size(), LOW_NUMBER); + this->int_data.assign(this->int_data.size(), int(LOW_NUMBER)); + + if(!m_tree){ + cout<<"ERROR: no TTree assigned!"<<endl; + return false; + + } + + + + this->float_data[Details::TRKAVGDIST] = tau_seedCalo_trkAvgDist->at(itau); + this->int_data[Details::AUTHOR] = tau_author->at(itau); + this->float_data[Details::ETOVERPTLEADTRK] = tau_etOverPtLeadTrk->at(itau); + this->float_data[Details::EMFRACTIONATEMSCALE] = tau_calcVars_EMFractionAtEMScale->at(itau); + this->float_data[Details::TRT_NHT_OVER_NLT] = tau_TRTHTOverLT_LeadTrk->at(itau); + this->float_data[Details::DRMAX] = tau_seedCalo_dRmax->at(itau); + this->float_data[Details::ABS_ETA_LEAD_TRACK] = fabs(tau_leadTrack_eta->at(itau)); + this->float_data[Details::CHPIEMEOVERCALOEME] = tau_calcVars_ChPiEMEOverCaloEME->at(itau); + this->float_data[Details::SECMAXSTRIPET] = tau_seedTrk_secMaxStripEt->at(itau); + this->float_data[Details::HADLEAKET] = tau_seedTrk_hadLeakEt->at(itau); + this->float_data[Details::SUMEMCELLETOVERLEADTRKPT] = tau_seedTrk_sumEMCellEtOverLeadTrkPt->at(itau); + this->float_data[Details::CORRFTRK] = tau_calcVars_corrFTrk->at(itau); + this->float_data[Details::CORRCENTFRAC] = tau_calcVars_corrCentFrac->at(itau); + this->float_data[Details::ISOLFRAC] = tau_seedCalo_isolFrac->at(itau); + this->float_data[Details::HADRADIUS] = tau_seedCalo_hadRadius->at(itau); + this->float_data[Details::EMPOVERTRKSYSP] = tau_calcVars_EMPOverTrkSysP->at(itau); + this->float_data[Details::PSSFRACTION] = tau_calcVars_PSSFraction->at(itau); + this->int_data[Details::NSTRIP] = tau_seedCalo_nStrip->at(itau); + this->int_data[Details::NUMTRACK] = tau_numTrack->at(itau); + this->float_data[Details::PT] = tau_pt->at(itau); + this->float_data[Details::ETA] = tau_eta->at(itau); + this->int_data[Details::NUMWIDETRACK] = tau_seedCalo_nWideTrk->at(itau); + this->float_data[Details::MASSTRKSYS] = tau_massTrkSys->at(itau); + this->float_data[Details::IPSIGLEADTRK] = tau_ipSigLeadTrk->at(itau); + this->int_data[Details::TAU_PI0_N] = tau_pi0_n->at(itau); + this->float_data[Details::TAU_PTRATIO] = tau_pi0_vistau_pt->at(itau)/tau_pt->at(itau); + this->float_data[Details::TAU_PI0_VISTAU_M] = tau_pi0_vistau_m->at(itau); + this->float_data[Details::TRFLIGHTPATHSIG] = tau_trFlightPathSig->at(itau); + + // solve for E3 + float tau_sumETCellsLAr = tau_seedTrk_sumEMCellEtOverLeadTrkPt->at(itau) * tau_leadTrkPt->at(itau); + float tau_sumEMCellET = tau_seedCalo_etEMAtEMScale->at(itau); + float tau_E3 = tau_sumETCellsLAr - tau_sumEMCellET; + // remove E3 + float tau_seedCalo_etHadAtEMScale_noE3 = tau_seedCalo_etHadAtEMScale->at(itau) - tau_E3; + float tau_seedCalo_etEMAtEMScale_yesE3 = tau_seedCalo_etEMAtEMScale->at(itau) + tau_E3; + + //calculate new EMFraction + this->float_data[Details::EMFRACTIONATEMSCALE_MOVEE3] = tau_seedCalo_etEMAtEMScale_yesE3/(tau_seedCalo_etEMAtEMScale_yesE3+tau_seedCalo_etHadAtEMScale_noE3); + + + this->float_data[Details::TAU_ABSDELTAETA] = fabs(tau_leadTrack_eta->at(itau)-tau_eta->at(itau)); + this->float_data[Details::TAU_ABSDELTAPHI] = fabs(tau_leadTrack_phi->at(itau)-tau_phi->at(itau)); + this->float_data[Details::TAU_SEEDTRK_SECMAXSTRIPETOVERPT] = (tau_leadTrkPt->at(itau)!=0?tau_seedTrk_secMaxStripEt->at(itau)/tau_leadTrkPt->at(itau):LOW_NUMBER); + + + + + + + + return true; +} + +const float* TauDetailsManagerStandalone::getFloatDetailAddress(Details::FloatTauDetail detail) const { + + return &this->float_data[detail]; +} + +const int* TauDetailsManagerStandalone::getIntDetailAddress(Details::IntTauDetail detail) const { + + return &this->int_data[detail]; +} + +const float* TauDetailsManagerStandalone::getFloatDetailAddress(Details::FloatEventDetail detail) const { + + return &this->float_event_data[detail]; +} + +const int* TauDetailsManagerStandalone::getIntDetailAddress(Details::IntEventDetail detail) const { + + return &this->int_event_data[detail]; +} + +float TauDetailsManagerStandalone::getFloatDetailValue(Details::FloatTauDetail detail) const { + + return this->float_data[detail]; +} + +int TauDetailsManagerStandalone::getIntDetailValue(Details::IntTauDetail detail) const { + + return this->int_data[detail]; +} + +float TauDetailsManagerStandalone::getFloatDetailValue(Details::FloatEventDetail detail) const { + + return this->float_event_data[detail]; +} + +int TauDetailsManagerStandalone::getIntDetailValue(Details::IntEventDetail detail) const { + + return this->int_event_data[detail]; +} + +int TauDetailsManagerStandalone::getNtau() +{ + if(tau_pt) return tau_pt->size(); + else return 0; +} + diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/TauIDReader.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/TauIDReader.cxx new file mode 100644 index 00000000000..bc8dd60b580 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/TauIDReader.cxx @@ -0,0 +1,774 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#include "TauDiscriminant/TauIDReader.h" +#include "TROOT.h" +#include <iomanip> + +using namespace TauID; + +void TauIDReader::print() const +{ + ios_base::fmtflags original_flags = cout.flags(); + vector<string>::const_iterator name_it(this->methodNames.begin()); + vector<float*>::const_iterator it_float(this->methodBuffer.begin()); + cout << "Methods:" << endl; + for(; it_float != this->methodBuffer.end(); ++it_float) + { + cout << left << setw(40) << setfill('.') << *(name_it++) << ' ' << **it_float << endl; + } + cout << "Variables:" << endl; + name_it = this->floatNames.begin(); + it_float = this->floatVariables.begin(); + for(; it_float != this->floatVariables.end(); ++it_float) + { + cout << left << setw(40) << setfill('.') << *(name_it++) << ' ' << **it_float << endl; + } + name_it = this->vectFloatNames.begin(); + it_float = this->vectFloatVariables.begin(); + for(; it_float != this->vectFloatVariables.end(); ++it_float) + { + cout << left << setw(40) << setfill('.') << *(name_it++) << ' ' << **it_float << endl; + } + name_it = this->intNames.begin(); + vector<int*>::const_iterator it_int(this->intVariables.begin()); + for(; it_int != this->intVariables.end(); ++it_int) + { + cout << left << setw(40) << setfill('.') << *(name_it++) << ' ' << **it_int << endl; + } + name_it = this->vectIntNames.begin(); + it_int = this->vectIntVariables.begin(); + for(; it_int != this->vectIntVariables.end(); ++it_int) + { + cout << left << setw(40) << setfill('.') << *(name_it++) << ' ' << **it_int << endl; + } + cout.flags(original_flags); +} + +bool TauIDReader::bookMethod(Types::MethodType type, const string& name, const string& filename, unsigned int numResponses) { + + if (name.size() == 0) + { + cout << "You must supply a non-empty name" << endl; + return false; + } + + if (numResponses == 0) + { + cout << "Number of responses must be non-zero" << endl; + return false; + } + + if (find(methodNames.begin(),methodNames.end(),name) != methodNames.end()) + { + cout << "Method with name " << name << " was already booked." << endl; + return false; + } + + MethodBase* method; + if (type == Types::CUTS) + { + method = new MethodCuts(name); + + } + else if (type == Types::BDT) + { + method = new MethodBDT(name); + } + else if (type == Types::LLH) + { + method = new MethodLLH(name); + } + else if (type == Types::DUMMY) + { + method = new MethodDummy(name); + } + else if (type == Types::TRANSFORM) + { + method = new MethodTransform(name); + } + else + { + return false; + } + + if (verbose) cout << "Booking method " << name << endl; + + // Add variables that reference the outputs of other methods + vector<pair<string,string> >::const_iterator methodvar_it(this->methodVariables.begin()); + vector<string>::const_iterator method_name_it; + for (; methodvar_it != this->methodVariables.end(); ++methodvar_it) + { + method_name_it = find(this->methodNames.begin(),this->methodNames.end(),methodvar_it->second); + method->addVariable(methodvar_it->first,this->methodBuffer[method_name_it - this->methodNames.begin()],'F'); + } + + //vector<int*>::const_iterator it_val_int(intVariables.begin()); + vector<string>::const_iterator it_name(intNames.begin()); + for (; it_name != intNames.end();) + { + //method->addVariable(*(it_name++),*(it_val_int++),'I'); + string valname = *(it_name++); + const map<string,int*> *dets = m_tdms->getIntDetails(); + method->addVariable(valname,dets->at(valname),'I'); + } + + //vector<float*>::const_iterator it_val_float(floatVariables.begin()); + it_name = floatNames.begin(); + for (;/* it_val_float != floatVariables.end() &&*/ it_name != floatNames.end();) + { + string valname = *(it_name++); + const map<string,float*> *dets = m_tdms->getFloatDetails(); + std::cout<<valname<<std::endl; + method->addVariable(valname,dets->at(valname),'F'); + } + + //it_val_int = vectIntVariables.begin(); + it_name = vectIntNames.begin(); + for (; /*it_val_int != vectIntVariables.end() &&*/ it_name != vectIntNames.end();) + { + string valname = *(it_name++); + const map<string,int*> *dets = m_tdms->getIntDetails(); + method->addVariable(valname,dets->at(valname),'I'); + } + + //it_val_float = vectFloatVariables.begin(); + it_name = vectFloatNames.begin(); + for (; /*it_val_float != vectFloatVariables.end() &&*/ it_name != vectFloatNames.end();) + { + string valname = *(it_name++); + const map<string,float*> *dets = m_tdms->getFloatDetails(); + method->addVariable(valname,dets->at(valname),'F'); + } + + if (!method->build(filename,false)) + { + cout << "Initializing the method " << name << " failed." << endl; + delete method; + return false; + } + + this->methodNames.push_back(name); + this->methodBuffer.push_back(new float(0.)); + this->methods.push_back(pair<MethodBase*,vector<vector<float>* > >(method,vector<vector<float>* >(numResponses, 0))); + vector<vector<float>* >::iterator it = methods.back().second.begin(); + for (; it != methods.back().second.end(); ++it) + { + *it = new vector<float>(); + } + return true; +} + +bool TauIDReader::addVariable(const string& name, const string& type, const string& branchName) { + + if (this->verbose) cout << "Adding variable " << name << " --> " << branchName << endl; + if (find(this->allVariableNames.begin(), this->allVariableNames.end(), name) != this->allVariableNames.end()) + { + cout << "Variable " << name << " has already been booked" << endl; + return false; + } +// if (find(this->allBranchNames.begin(), this->allBranchNames.end(), branchName) != this->allBranchNames.end()) +// { +// cout << "A variable referring to branch " << branchName << " has already been booked" << endl; +// return false; +// } + vector<string>::const_iterator it(find(this->methodNames.begin(),this->methodNames.end(),branchName)); + if (it != this->methodNames.end()) + { + if (this->verbose) cout << "Branch matches name of method previously booked" << endl; + if (type != "F") + { + cout << "The type of all method outputs are scalar floats" << endl; + cout << "Variable referring to branch " << branchName << " must be of type \"F\"" << endl; + return false; + } + if (this->verbose) cout << "This variable will refer to the output of that method" << endl; + this->allVariableNames.push_back(name); + this->allBranchNames.push_back(branchName); + this->methodVariables.push_back(pair<string,string>(name,branchName)); + return true; + } + if (type == "F") + { + this->floatNames.push_back(name); + this->allVariableNames.push_back(name); + //this->floatBranches.push_back(branchName); + //this->allBranchNames.push_back(branchName); + this->floatVariables.push_back(new float(0.)); + return true; + } + else if (type == "I") + { + this->intNames.push_back(name); + this->allVariableNames.push_back(name); + //this->intBranches.push_back(branchName); + //this->allBranchNames.push_back(branchName); + this->intVariables.push_back(new int(0)); + return true; + } + else if (type == "VF") + { + this->vectFloatNames.push_back(name); + this->allVariableNames.push_back(name); + //this->vectFloatBranches.push_back(branchName); + //this->allBranchNames.push_back(branchName); + this->vectFloatVariables.push_back(new float(0.)); + this->vectorMode = true; + return true; + } + else if (type == "VI") + { + this->vectIntNames.push_back(name); + this->allVariableNames.push_back(name); + //this->vectIntBranches.push_back(branchName); + //this->allBranchNames.push_back(branchName); + this->vectIntVariables.push_back(new int(0)); + this->vectorMode = true; + return true; + } + cout << "Unknown variable type " << type << " for variable " << name << endl; + return false; +} + +bool TauIDReader::checkBranch(TTree* tree, const char* name, string type, bool checkType) +{ + if (!tree) + { + return false; + } + TBranch* branch = tree->GetBranch(name); + if (!branch) + { + cout << "Branch " << name << " does not exist!" << endl; + return false; + } + if (checkType) + { + if (strcmp(type.c_str(), branch->GetClassName())) + { + cout << "Branch " << name << " does not contain the correct type: " << branch->GetClassName() << " (expected " << type << ")" << endl; + return false; + } + } + return true; +} + +bool TauIDReader::setOutput(const string& outputFileName, const string& _outputDir) +{ + if (this->own_output) + { + delete this->output; + } + this->own_output = true; + this->output = new TFile(outputFileName.c_str(),"NEW"); + gROOT->GetListOfFiles()->Remove(this->output); + if (!this->output->IsOpen() || this->output->IsZombie()) + { + cout << "Could not create " << outputFileName << endl; + return false; + } + if (!this->output->GetDirectory(_outputDir.c_str())) + { + cout << "Could not find directory " << _outputDir << " in " << outputFileName << endl; + return false; + } + this->output->cd(_outputDir.c_str()); + if (this->verbose) + { + cout << "Output is now " << outputFileName; + if (_outputDir != "") + { + cout << "/" << _outputDir; + } + cout << endl; + } + this->outputDir = _outputDir; + return true; +} + +bool TauIDReader::setOutput(TFile& outputFile, const string& _outputDir) +{ + return this->setOutput(&outputFile, _outputDir); +} + +bool TauIDReader::setOutput(TFile* outputFile, const string& _outputDir) +{ + if (!outputFile) + { + cout << "NULL file!" << endl; + return false; + } + if (!outputFile->IsOpen() || outputFile->IsZombie()) + { + cout << "File is not open!" << endl; + return false; + } + if (this->own_output) + { + delete this->output; + } + this->own_output = false; + this->output = outputFile; + if (!this->output->GetDirectory(_outputDir.c_str())) + { + cout << "Could not find directory " << _outputDir << " in " << outputFile->GetName() << endl; + return false; + } + this->output->cd(_outputDir.c_str()); + if (this->verbose) + { + cout << "Output is now " << outputFile->GetName(); + if (outputDir != "") + { + cout << "/" << _outputDir; + } + cout << endl; + } + this->outputDir = _outputDir; + return true; +} + +int TauIDReader::classify(const string& inputTreeName, const string& outputTreeName, + const string& inputFileName, const string& inputDir, + bool makeFriend, + bool copyTree) +{ + unsigned int entries(0); + TFile* input = new TFile(inputFileName.c_str(), "READ"); + if (!input->IsOpen() || input->IsZombie()) + { + cout << "Could not open " << inputFileName << endl; + delete input; + return -1; + } + // Try to cd to desired directory in input ROOT file + if (!input->GetDirectory(inputDir.c_str())) + { + delete input; + cout << "Could not find directory " << inputDir << " in " << inputFileName << endl; + return -1; + } + input->cd(inputDir.c_str()); + TTree* tree = (TTree*)input->Get(inputTreeName.c_str()); + if (!tree) + { + cout << "Could not find tree " << inputTreeName << " in file " << inputFileName; + if (inputDir != "") + { + cout << "/" << inputDir << endl; + } + else + { + cout << endl; + } + delete input; + return -1; + } + entries = tree->GetEntries(); + TTree* outputTree = this->classify(tree, outputTreeName, copyTree); + if (!outputTree) + { + delete tree; + delete input; + return -1; + } + if (makeFriend) + { + if (verbose) + { + cout << "Making input tree a friend of output tree" << endl; + } + if (inputDir == "") + { + outputTree->AddFriend(inputTreeName.c_str(), inputFileName.c_str()); + } + else + { + string fullInputDir(inputFileName + "/" + inputDir); + outputTree->AddFriend(inputTreeName.c_str(), fullInputDir.c_str()); + } + } + this->output->cd(this->outputDir.c_str()); + outputTree->Write("",TObject::kOverwrite); + delete tree; + delete input; + delete outputTree; + return entries; +} + +TTree* TauIDReader::classify(TTree& tree, const string& outputTreeName, bool copyTree) +{ + return this->classify(&tree, outputTreeName, copyTree); +} + +TTree* TauIDReader::classify(TTree* tree, const string& outputTreeName, bool copyTree) +{ + if (!this->output) + { + cout << "No output file has been previously specified" << endl; + return 0; + } + if (!this->output->IsOpen() || this->output->IsZombie()) + { + cout << "Output file is not open" << endl; + return 0; + } + if (!tree) + { + cout << "Input tree is NULL!" << endl; + return 0; + } + int lastStatus(0); + unsigned long entry(0); + unsigned long numEntries(tree->GetEntries()); + if (numEntries == 0) + { + cout << "The input tree has no entries!" << endl; + return 0; + } + if (this->methods.size()==0) + { + cout << "No methods were booked successfully!" << endl; + return 0; + } + if (tree->GetNbranches() == 0) + { + cout << "Input tree contains no branches!" << endl; + return 0; + } + + + + m_tdms->initTree(tree); + + + vector<pair<MethodBase*,vector<vector<float>* > > >::iterator method_it; + vector<int*>::iterator intvalue_it; + vector<float*>::iterator floatvalue_it; + vector<string>::const_iterator intbranch_it; + vector<string>::const_iterator floatbranch_it; + vector<string>::const_iterator intname_it; + vector<string>::const_iterator floatname_it; + + + TTree* outputTree(0); + // this has already been checked in setOutput to succeed + this->output->cd(this->outputDir.c_str()); + + // Create the output tree + if (copyTree) + { + // Make sure that all branches are activated + tree->SetBranchStatus("*",1); + + // Deactivate the branches we will use for the Methods (if they already exist in the input tree) + for (method_it = methods.begin(); method_it != methods.end(); ++method_it) + { + for (unsigned int i(0); i<(method_it->second).size(); ++i) + { + string name = method_it->first->getName(); + if ((method_it->second).size() > 1) + { + name += to_string<unsigned int>(i); + } + if (tree->GetBranch(name.c_str())) + { + tree->SetBranchStatus(name.c_str(),0); + } + } + } + if (verbose) + { + cout << "Cloning input tree... " << flush; + } + outputTree = tree->CloneTree(-1,"fast"); + if (!outputTree) + { + if (verbose) cout << "fail" << endl; + cout << "Could not clone tree" << endl; + return 0; + } + outputTree->Write("",TObject::kOverwrite); + if (verbose) + { + cout << "done" << endl; + } + if (outputTree->GetNbranches() == 0) + { + cout << "The output tree contains no branches" << endl; + cout << "They were probably all deactivated before cloning the input tree" << endl; + delete outputTree; + return 0; + } + // Separate the cloned tree from the original + tree->CopyAddresses(outputTree, true); + //outputTree->ResetBranchAddresses(); + //outputTree->SetBranchStatus("*",0); + } + else + { + outputTree = new TTree(outputTreeName.c_str(),outputTreeName.c_str()); + } + + // Disable all branches of the input tree + tree->SetBranchStatus("*",0); + // Only the required branches are reactivated below + + m_tdms->initTree(tree); + + // Scalar variables: + + // Set the addresses of the int variables +// intvalue_it = intVariables.begin(); +// intbranch_it = intBranches.begin(); + + +// for ( ; intvalue_it != intVariables.end() && intbranch_it != intBranches.end(); ) +// { +// +// if (!checkBranch(tree,intbranch_it->c_str(),string("int"),false)) +// { +// delete outputTree; +// return 0; +// } +// +// tree->SetBranchStatus(intbranch_it->c_str(),1); +// if (tree->SetBranchAddress((intbranch_it++)->c_str(),*(intvalue_it++)) != 0) +// { +// delete outputTree; +// return 0; +// } +// +// } +// +// // Set the addresses of the float variables +// floatvalue_it = floatVariables.begin(); +// floatbranch_it = floatBranches.begin(); +// for (; floatvalue_it != floatVariables.end() && floatbranch_it != floatBranches.end(); ) +// { +// if (!checkBranch(tree,floatbranch_it->c_str(),string("float"),false)) +// { +// delete outputTree; +// return 0; +// } +// tree->SetBranchStatus(floatbranch_it->c_str(),1); +// if (tree->SetBranchAddress((floatbranch_it++)->c_str(),*(floatvalue_it++)) != 0) +// { +// delete outputTree; +// return 0; +// } +// } +// +// // Vector variables: +// +// vector<vector<int>* > intBuffer(vectIntVariables.size(),0); +// vector<vector<float>* > floatBuffer(vectFloatVariables.size(),0); +// +// // Set the addresses of the int vector variables +// vector<vector<int>* >::iterator intbuffer_it(intBuffer.begin()); +// intbranch_it = vectIntBranches.begin(); +// for (; intbuffer_it != intBuffer.end() && intbranch_it != vectIntBranches.end(); ) +// { +// if (!checkBranch(tree,intbranch_it->c_str(),string("vector<int>"))) +// { +// delete outputTree; +// return 0; +// } +// tree->SetBranchStatus(intbranch_it->c_str(),1); +// if (tree->SetBranchAddress((intbranch_it++)->c_str(),&(*(intbuffer_it++))) != 0) +// { +// delete outputTree; +// return 0; +// } +// } +// +// // Set the addresses of the float vector variables +// vector<vector<float>* >::iterator floatbuffer_it(floatBuffer.begin()); +// floatbranch_it = vectFloatBranches.begin(); +// for (; floatbuffer_it != floatBuffer.end() && floatbranch_it != vectFloatBranches.end(); ) +// { +// if (!checkBranch(tree,floatbranch_it->c_str(),string("vector<float>"))) +// { +// delete outputTree; +// return 0; +// } +// tree->SetBranchStatus(floatbranch_it->c_str(),1); +// if (tree->SetBranchAddress((floatbranch_it++)->c_str(),&(*(floatbuffer_it++))) != 0) +// { +// delete outputTree; +// return 0; +// } +// } + + vector<TBranch*> outputBranches; + + + // Initialize new branches in the output tree + for (method_it = methods.begin(); method_it != methods.end(); ++method_it) + { + for (unsigned int i(0); i<(method_it->second).size(); ++i) + { + string name = method_it->first->getName(); + if ((method_it->second).size() > 1) + { + name += to_string<unsigned int>(i); + } + method_it->second[i]->clear(); + if (this->vectorMode) + { + outputBranches.push_back(outputTree->Branch(name.c_str(),"std::vector<float>",&(method_it->second[i]))); + } + else + { + method_it->second[i]->push_back(0.); + outputBranches.push_back(outputTree->Branch(name.c_str(),&(*(method_it->second[i]->begin())),(name+"/F").c_str())); + } + } + } + +// void* sampleVector(0); +// bool sampleIsInt(false); + unsigned int vectorLength; + +// if (this->vectorMode) +// { +// if (vectIntVariables.size() > 0) +// { +// sampleVector = intBuffer[0]; +// sampleIsInt = true; +// } +// else +// { +// sampleVector = floatBuffer[0]; +// } +// } + + vector<TBranch*>::const_iterator outputBranches_it; + vector<TBranch*>::const_iterator outputBranches_end(outputBranches.end()); + + // The main event loop + + for (; entry < numEntries; ++entry) + { + tree->GetEntry(entry); + m_tdms->updateEvent(entry); + + + if (verbose) + { + int newStatus = int(100*(entry+1)/numEntries); + if (newStatus != lastStatus || entry == 0) + { + cout << "\rClassifying " << numEntries << " entries... " << newStatus << '%' << flush; + lastStatus = newStatus; + } + } + if (this->vectorMode) + { + // Assume all vectors have the same length (as they should...) + // TODO: protect against vectors of differing length +// if (sampleIsInt) +// vectorLength = static_cast<vector<int>* >(sampleVector)->size(); +// else +// vectorLength = static_cast<vector<float>* >(sampleVector)->size(); + + vectorLength = m_tdms->getNtau(); + + for (method_it = methods.begin(); method_it != methods.end(); ++method_it) + { + for (unsigned int i(0); i<(method_it->second).size(); ++i) + { + *(method_it->second)[i] = vector<float>(vectorLength,0.); + } + } + + for (unsigned int j(0); j < vectorLength; ++j) + { + + m_tdms->update(j); + + // Copy buffers to stage +/* intbuffer_it = intBuffer.begin(); + intvalue_it = this->vectIntVariables.begin(); + for (; intbuffer_it != intBuffer.end();) + { + **(intvalue_it++) = (**(intbuffer_it++))[j]; + } + floatbuffer_it = floatBuffer.begin(); + floatvalue_it = this->vectFloatVariables.begin(); + for (; floatbuffer_it != floatBuffer.end();) + { + **(floatvalue_it++) = (**(floatbuffer_it++))[j]; + }*/ + method_it = methods.begin(); + unsigned int k(0); + // Fill the output vector containing each Method's response + for (; method_it != methods.end(); ++method_it) + { + for (unsigned int i(0); i<(method_it->second).size(); ++i) + { + float response = method_it->first->response(i); + *(this->methodBuffer[k]) = response; + (*(method_it->second[i]))[j] = response; + } + ++k; + } + } + } + else + { + unsigned int j(0); + // Get the response from each Method + for (method_it = methods.begin(); method_it != methods.end(); ++method_it) + { + for (unsigned int i(0); i<(method_it->second).size(); ++i) + { + float response = method_it->first->response(i); + *(this->methodBuffer[j]) = response; + (*((method_it->second)[i]))[0] = response; + } + ++j; + } + } + if (copyTree) + { + outputBranches_it = outputBranches.begin(); + for(; outputBranches_it != outputBranches_end; ++outputBranches_it) + { + if ((*outputBranches_it)->Fill() < 1) + { + if (verbose) + { + cout << endl; + } + cout << "There was an error when filling the output tree" << endl; + delete outputTree; + return 0; + } + } + } + else + { + if (outputTree->Fill() < 1) + { + if (verbose) + { + cout << endl; + } + cout << "There was an error when filling the output tree" << endl; + delete outputTree; + return 0; + } + } + } + if (verbose) + { + cout << endl; + } + return outputTree; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/Transformation.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/Transformation.cxx new file mode 100644 index 00000000000..881e588aac3 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/Transformation.cxx @@ -0,0 +1,32 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: Transformation.cxx + * + * Author: Noel Dawe (end1@sfu.ca) + */ + +#include "TauDiscriminant/Transformation.h" + +float Transformation::response() const { + + Node* currentNode = 0; + DecisionNode* decision = 0; + LeafNode<float>* leafNode = 0; + vector<pair<Node*,float> >::const_iterator tree = this->trees.begin(); + if (tree == this->trees.end()) return -200.; + currentNode = (*tree).first; + while (!currentNode->isLeaf()) { + decision = static_cast<DecisionNode*>(currentNode); + if (decision->goRight()) { + currentNode = decision->getRightChild(); + } else { + currentNode = decision->getLeftChild(); + } + if (!currentNode) return -200.; + } + leafNode = static_cast<LeafNode<float>*>(currentNode); + return leafNode->getValue(); +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/TreeReader.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/TreeReader.cxx new file mode 100644 index 00000000000..e5aa846935e --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/TreeReader.cxx @@ -0,0 +1,748 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#include "TauDiscriminant/TreeReader.h" +#include "TROOT.h" +#include "TNamed.h" +#include "TFile.h" +#include "TGraph.h" +#include "TGraph2D.h" +#include "TF1.h" + +bool isGoodTree(Node* node) +{ + if (!node) return false; + LeafNode<float> dummyLeafNode; + if (string(typeid(dummyLeafNode).name()).compare(typeid(*node).name())==0) return true; + return isGoodTree(node->getLeftChild()) && isGoodTree(node->getRightChild()); +} + +void findBadNodes(Node* node, vector<Node*>& badNodes) +{ + if (!node) return; + LeafNode<float> dummyLeafNode; + if (string(typeid(dummyLeafNode).name()).compare(typeid(*node).name())==0) return; + UnivariateCut<float>* intNode = static_cast<UnivariateCut<float>*>(node); + if (!intNode->isComplete()) badNodes.push_back(intNode); + findBadNodes(node->getLeftChild(),badNodes); + findBadNodes(node->getRightChild(),badNodes); +} + +string signature(Node* node, vector<Node*>* badNodes, string hash = "") +{ + if(!node) return hash; + if (badNodes) + { + if (find(badNodes->begin(),badNodes->end(),node) != badNodes->end()) hash += "[BAD]"; + } + Node* child = node->getLeftChild(); + if (child) hash = signature(child,badNodes,hash+"1")+"2"; + child = node->getRightChild(); + if (child) hash = signature(child,badNodes,hash+"3")+"2"; + return hash; +} + +void getLeafNodes(Node* node, vector<Node*>& leafNodes) +{ + if (!node) return; + if (node->isLeaf()) + { + leafNodes.push_back(node); + return; + } + getLeafNodes(node->getLeftChild(),leafNodes); + getLeafNodes(node->getRightChild(),leafNodes); +} + +void getIncompleteNodes(Node* node, vector<Node*>& incompleteNodes) +{ + if (!node) return; + if (!node->isComplete()) + { + incompleteNodes.push_back(node); + } + getIncompleteNodes(node->getLeftChild(),incompleteNodes); + getIncompleteNodes(node->getRightChild(),incompleteNodes); +} + +void attachTree(Node* tree, Node* subtree) +{ + if (!tree || !subtree) return; + vector<Node*> incompleteNodes; + getIncompleteNodes(tree, incompleteNodes); + vector<Node*>::iterator it(incompleteNodes.begin()); + for (;it != incompleteNodes.end(); ++it) + { + if(!(*it)) return; + if(!(*it)->getLeftChild()) static_cast<DecisionNode*>(*it)->setLeftChild(subtree->clone()); + if(!(*it)->getRightChild()) static_cast<DecisionNode*>(*it)->setRightChild(subtree->clone()); + } +} + +Node* createBalancedTree(const vector<DecisionNode*>& nodes) +{ + if (nodes.size() == 0) return 0; + DecisionNode* root = nodes.at(nodes.size()/2); + if (!root) return 0; + vector<DecisionNode*>::const_iterator midpoint(nodes.begin()+nodes.size()/2); + vector<DecisionNode*> leftTree(nodes.begin(),midpoint); + vector<DecisionNode*> rightTree(midpoint+1,nodes.end()); + root->setLeftChild(createBalancedTree(leftTree)); + root->setRightChild(createBalancedTree(rightTree)); + return root; +} + +Node* createBinningTree(const void* variable, char type, const vector<float>& binCuts) +{ + vector<float>::const_iterator it(binCuts.begin()); + vector<DecisionNode*> nodes; + for (;it != binCuts.end(); ++it) + { + if (type == 'F') + { + nodes.push_back(new UnivariateCut<float>((float*)variable,*it)); + } + else if (type == 'I') + { + nodes.push_back(new UnivariateCut<int>((int*)variable,(int)*it)); + } + else + { + return 0; + } + } + return createBalancedTree(nodes); +} + +Node* buildCategoryTree(const vector<Node*>& binningTrees) +{ + vector<Node*>::const_iterator it(binningTrees.begin()); + Node* tree = *(it++); + if (!tree) return 0; + tree = tree->clone(); + for (;it != binningTrees.end(); ++it) + { + attachTree(tree,*(it)); + } + vector<Node*> incompleteNodes; + getIncompleteNodes(tree,incompleteNodes); + it = incompleteNodes.begin(); + for (;it != incompleteNodes.end(); ++it) + { + if(!(*it)) return 0; + if(!(*it)->getLeftChild()) static_cast<DecisionNode*>(*it)->setLeftChild(new PointerLeafNode<TreeVector>()); + if(!(*it)->getRightChild()) static_cast<DecisionNode*>(*it)->setRightChild(new PointerLeafNode<TreeVector>()); + } + return tree; +} + +bool hasEnding(const string& fullString, const string& ending) +{ + if (fullString.length() > ending.length()) + { + return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); + } + else + { + return false; + } +} + +template<typename T> +bool read(istream& file, T& data, Format format) +{ + if (format == ASCII || format == ROOTFILE) + { + if ((file >> data).fail()) + { + return false; + } + } + else + { + file.read((char*)&data,sizeof(T)); + } + return true; +} + +bool good_file(TFile* file) +{ + if (!file) + return false; + return file->IsOpen() && !file->IsZombie(); +} + +Node* TreeReader::readTree( + istream& treeFile, + TFile* rootFile, + Format format, + vector<string>& variableList, + vector<char>& variableTypeList, + unsigned int& numNodes) +{ + int variable; + int idata; + float fdata; + string line; + Node* rootNode(0); + Node* node(0); + stack<DecisionNode*> parentNodeStack; + DecisionNode* parent(0); + if (!read<int>(treeFile,variable,format)) + { + print("Failed extracting variable index from the discriminant file"); + return 0; + } + while (variable != ENDOFTREE) + { + if (variable == LEAF) + { // parsing leaf node + if (!read<float>(treeFile,fdata,format)) + { + print("Failed extracting leaf node purity"); + return 0; + } + node = new LeafNode<float>(fdata); + } + else if (variable == POINTERLEAF) + { + node = new PointerLeafNode<TreeVector>(); + } + else if(variable == GRAPH || variable == FUNC || variable == TRANS) // Now reading a UnivariateSlidingCut1D/Tranformation node + { + int numPoints; + string expression; + string graphName; + float lowX, highX; + float lowY, highY; + if (variable == GRAPH) + { + if (!read<int>(treeFile,numPoints,format)) + { + print("Failed extracting number of points for a UnivariateSlidingCut1D node"); + return 0; + } + if (numPoints < 2) + { + print("Invalid number of points in UnivariateSlidingCut1D node"); + return 0; + } + } + else if (variable == FUNC) + { + treeFile >> expression; + getline(treeFile,line); // Discard \n + } + else + { + if (!rootFile) + { + print("Requested a transformation but input file is not a ROOT file"); + return 0; + } + if (!good_file(rootFile)) + { + print("Input ROOT file is not open while trying to get transformation!"); + return 0; + } + treeFile >> graphName; + getline(treeFile,line); // Discard \n + } + int varX, varY; + if (!read<int>(treeFile,varX,format)) + { + print("Failed extracting X for a UnivariateSlidingCut1D node"); + return 0; + } + if (variable == TRANS) + { + if(!read<float>(treeFile,lowX,format) || !read<float>(treeFile,highX,format)) + { + print("Failed extracting bounds on X for transformation"); + return 0; + } + } + if (!read<int>(treeFile,varY,format)) + { + print("Failed extracting Y for a UnivariateSlidingCut1D node"); + return 0; + } + if (variable == TRANS) + { + if(!read<float>(treeFile,lowY,format) || !read<float>(treeFile,highY,format)) + { + print("Failed extracting bounds on Y for transformation"); + return 0; + } + } + if (varX < 0 || varY < 0) + { + print("Invalid X or Y for UnivariateSlidingCut1D node"); + return 0; + } + TObject* graph; + if (variable == GRAPH) + { + graph = new TGraph(numPoints); + } + else if (variable == FUNC) + { + graph = new TF1(expression.c_str(),expression.c_str(),0.,1.); + } + else + { + TGraph2D* tempgraph = dynamic_cast<TGraph2D*>(rootFile->Get(graphName.c_str())); + if (!tempgraph) + { + print("Could not get transformation graph from ROOT file"); + return 0; + } + //tempgraph = dynamic_cast<TGraph2D*>(tempgraph->Clone()); + graph = tempgraph; + } + if (variableTypeList[varX] == 'F' && variableTypeList[varY] == 'I') + { + map<string,const float*>::const_iterator it1(floatVariables->find(variableList[varX])); + if (it1 == floatVariables->end()) + { + print("A Did not find variable "+variableList[varX]+" in booked float variables!"); + return 0; + } + map<string,const int*>::const_iterator it2(intVariables->find(variableList[varY])); + if (it2 == intVariables->end()) + { + print("B Did not find variable "+variableList[varY]+" in booked float variables!"); + return 0; + } + if (variable == GRAPH) + { + node = new UnivariateSlidingCut1D<int,TGraph,float>(it2->second,static_cast<TGraph*>(graph),it1->second); + } + else if (variable == FUNC) + { + node = new UnivariateSlidingCut1D<int,TF1,float>(it2->second,static_cast<TF1*>(graph),it1->second); + } + else + { + node = new TransformationNode<float,int,TGraph2D>(it1->second,lowX,highX,it2->second,lowY,highY,static_cast<TGraph2D*>(graph)); + } + } + else if (variableTypeList[varX] == 'I' && variableTypeList[varY] == 'F') + { + map<string,const int*>::const_iterator it1(intVariables->find(variableList[varX])); + if (it1 == intVariables->end()) + { + print("Did not find variable "+variableList[varX]+" in booked int variables!"); + return 0; + } + map<string,const float*>::const_iterator it2(floatVariables->find(variableList[varY])); + if (it2 == floatVariables->end()) + { + print("Did not find variable "+variableList[varY]+" in booked int variables!"); + return 0; + } + if (variable == GRAPH) + { + node = new UnivariateSlidingCut1D<float,TGraph,int>(it2->second,static_cast<TGraph*>(graph),it1->second); + } + else if (variable == FUNC) + { + node = new UnivariateSlidingCut1D<float,TF1,int>(it2->second,static_cast<TF1*>(graph),it1->second); + } + else + { + node = new TransformationNode<int,float,TGraph2D>(it1->second,lowX,highX,it2->second,lowY,highY,static_cast<TGraph2D*>(graph)); + } + } + else if (variableTypeList[varX] == 'F' && variableTypeList[varY] == 'F') + { + map<string,const float*>::const_iterator it1(floatVariables->find(variableList[varX])); + if (it1 == floatVariables->end()) + { + print("D Did not find variable "+variableList[varX]+" in booked float variables!"); + return 0; + } + map<string,const float*>::const_iterator it2(floatVariables->find(variableList[varY])); + if (it2 == floatVariables->end()) + { + print("E Did not find variable "+variableList[varY]+" in booked float variables!"); + return 0; + } + if (variable == GRAPH) + { + node = new UnivariateSlidingCut1D<float,TGraph,float>(it2->second,static_cast<TGraph*>(graph),it1->second); + } + else if (variable == FUNC) + { + node = new UnivariateSlidingCut1D<float,TF1,float>(it2->second,static_cast<TF1*>(graph),it1->second); + } + else + { + node = new TransformationNode<float,float,TGraph2D>(it1->second,lowX,highX,it2->second,lowY,highY,static_cast<TGraph2D*>(graph)); + } + } + else if (variableTypeList[varX] == 'I' && variableTypeList[varY] == 'I') + { + map<string,const int*>::const_iterator it1(intVariables->find(variableList[varX])); + if (it1 == intVariables->end()) + { + print("Did not find variable "+variableList[varX]+" in booked int variables!"); + return 0; + } + map<string,const int*>::const_iterator it2(intVariables->find(variableList[varY])); + if (it2 == intVariables->end()) + { + print("Did not find variable "+variableList[varY]+" in booked int variables!"); + return 0; + } + if (variable == GRAPH) + { + node = new UnivariateSlidingCut1D<int,TGraph,int>(it2->second,static_cast<TGraph*>(graph),it1->second); + } + else if (variable == FUNC) + { + node = new UnivariateSlidingCut1D<int,TF1,int>(it2->second,static_cast<TF1*>(graph),it1->second); + } + else + { + node = new TransformationNode<int,int,TGraph2D>(it1->second,lowX,highX,it2->second,lowY,highY,static_cast<TGraph2D*>(graph)); + } + } + else + { + print("Unsupported variable type in list found in discriminant file!"); + return 0; + } + if (variable == GRAPH) + { + TGraph* tgraph = static_cast<TGraph*>(graph); + float X,Y; + for (int k(0); k < numPoints; ++k ) + { + if (!read<float>(treeFile,X,format) || !read<float>(treeFile,Y,format)) + { + print("Failed extracting X,Y for a UnivariateSlidingCut1D node"); + delete node; + delete rootNode; + return 0; + } + tgraph->SetPoint(k,X,Y); + } + } + } + else + { // parsing internal node + if (variableTypeList[variable] == 'F')\ + { // internal node cuts on float + map<string,const float*>::const_iterator it(floatVariables->find(variableList[variable])); + if (it == floatVariables->end()) + { + print("F Did not find variable "+variableList[variable]+" in booked float variables!"); + return 0; + } + if (!read<float>(treeFile,fdata,format)) + { + print("Failed extracting internal float node cut"); + return 0; + } + node = new UnivariateCut<float>(it->second,fdata); + } + else if (variableTypeList[variable] == 'I') + { // internal node cuts on int + map<string,const int*>::const_iterator it(intVariables->find(variableList[variable])); + if (it == intVariables->end()) + { + print("Did not find variable "+variableList[variable]+" in booked int variables!"); + return 0; + } + if (!read<int>(treeFile,idata,format)) + { + print("Failed extracting internal int node cut"); + return 0; + } + node = new UnivariateCut<int>(it->second,idata); + } + else + { // unknown node type + print("Unsupported variable type in list found in discriminant file!"); + return 0; + } + } + ++numNodes; + + if (parentNodeStack.empty()) + { + if (variable == LEAF) + { + print("Corrupt tree! Adding leaf node as root node."); + delete node; + return 0; + } + rootNode = node; + } + else + { + parent = parentNodeStack.top(); + while (parent->isComplete()) + { + parentNodeStack.pop(); + if (parentNodeStack.empty()) + { + print("Corrupt tree! Expected a parent node."); + delete node; + delete rootNode; + return 0; + } + parent = parentNodeStack.top(); + } + if (!parent->getLeftChild()) + { + parent->setLeftChild(node); + } + else if (!parent->getRightChild()) + { + parent->setRightChild(node); + } + else + { + print("Corrupt tree! Attempted to add a child to a complete node!"); + delete node; + delete rootNode; + return 0; + } + } + + if (variable != LEAF) + { + parentNodeStack.push(static_cast<DecisionNode*>(node)); + } + + if (!read<int>(treeFile,variable,format)) + { + print("Failed extracting variable index"); + delete rootNode; + return 0; + } + } + while (!parentNodeStack.empty()) parentNodeStack.pop(); + return rootNode; +} + +Node* TreeReader::build( + const string& filename, + bool checkTree) +{ + + Format format; + if (hasEnding(filename, ".bin")) + { + format = BINARY; + if (verbose) print("Reading input as binary"); + } + else if (hasEnding(filename, ".txt")) + { + format = ASCII; + if (verbose) print("Reading input as ASCII text"); + } + else if (hasEnding(filename, ".root")) + { + format = ROOTFILE; + if (verbose) print("Reading input as ROOT file"); + } + else + { + print("Unknown discriminant format"); + return 0; + } + + unsigned int numVariables; + Node* categoryTree; + Node* rootNode; + vector<string> tokens; + string line; + string token; + vector<string> variableList; + vector<char> variableTypeList; + vector<string> binningVariableList; + vector<char> binningVariableTypeList; + char type; + unsigned int numNodes(0); + + istream* treeInfoTemp; + ifstream treeFile; + istringstream treeString; + TFile* file(0); + + if (format == ROOTFILE) + { + // read in tree data from ROOT file and place in stringstream + file = new TFile(filename.c_str(), "READ"); + if (!good_file(file)) + { + print("The discriminant ROOT file "+filename+" will not open!"); + return 0; + } + TNamed* treeInfoText = (TNamed*)file->Get("TreeInfo"); + if (!treeInfoText) + { + print("Could not find TreeInfo in discriminant ROOT file!"); + file->Close(); + return 0; + } + string treeInfoTextString(treeInfoText->GetTitle()); + treeString.str(treeInfoTextString); + delete treeInfoText; + treeInfoTemp = &treeString; + } + else + { + treeFile.open(filename.c_str(),ios::in); + if (!treeFile.is_open()) + { + print("The discriminant file "+filename+" will not open!"); + return 0; + } + treeInfoTemp = &treeFile; + } + istream& treeInfo(*treeInfoTemp); + + unsigned int numBinningVariables = 0; + if ((treeInfo >> numBinningVariables).fail()) + { + print("Failed extracting the number of binning variables in the discriminant file!"); + return 0; + } + + binningVariableList = vector<string>(numBinningVariables,""); + binningVariableTypeList = vector<char>(numBinningVariables,'F'); + + for (unsigned int j(0); j < numBinningVariables; ++j) + { + if ((treeInfo >> binningVariableList[j]).fail()) + { + print("Failed extracting a variable name from the discriminant file"); + return 0; + } + if ((treeInfo >> type).fail()) + { + print("Failed extracting a variable type from the discriminant file"); + return 0; + } + if (type != 'F' && type != 'I') + { + print("Unsupported variable type found in the discriminant file: "+type); + return 0; + } + binningVariableTypeList[j] = type; + } + getline(treeFile,line); // discard \n + + if (numBinningVariables > 0) + { + categoryTree = readTree(treeInfo,file,ASCII,binningVariableList,binningVariableTypeList,numNodes); + } + else + { + categoryTree = new PointerLeafNode<TreeVector>(); + } + + if ((treeInfo >> numVariables).fail()) + { + print("Failed extracting number of variables from the discriminant file!"); + delete categoryTree; + return 0; + } + + variableList = vector<string>(numVariables,""); + variableTypeList = vector<char>(numVariables,'F'); + + for (unsigned int j(0); j < numVariables; ++j) + { + if ((treeInfo >> variableList[j]).fail()) + { + print("Failed extracting a variable name from the discriminant file"); + delete categoryTree; + return 0; + } + if ((treeInfo >> type).fail()) + { + print("Failed extracting a variable type from the discriminant file"); + delete categoryTree; + return 0; + } + if (type != 'F' && type != 'I') + { + print("Unsupported variable type found in the discriminant file: "+type); + delete categoryTree; + return 0; + } + variableTypeList[j] = type; + } + getline(treeInfo,line); // discard \n + + // Get vector of all leaf nodes of the category tree and initialize an iterator + vector<Node*> categories; + vector<Node*>::const_iterator category_it, category_end; + getLeafNodes(categoryTree, categories); + category_it = categories.begin(); + category_end = categories.end(); + + unsigned int numTrees; + float weight; + + // Build the (categorized) TreeVector + TreeVector* treeVector; + for (;category_it != category_end; ++category_it) + { + numNodes = 0; + treeVector = new TreeVector(); + static_cast<PointerLeafNode<TreeVector>* >(*category_it)->setValue(treeVector); + + if (!read<unsigned int>(treeInfo,numTrees,format)) print("Failed extracting number of trees from the discriminant file!"); + + for (unsigned int j(0); j < numTrees; ++j) + { + rootNode = 0; + + if (!read<float>(treeInfo,weight,format)) + { + print("Failed extracting tree weight from the discriminant file"); + delete categoryTree; + return 0; + } + rootNode = readTree(treeInfo,file,format,variableList,variableTypeList,numNodes); + if (!rootNode) + { + print("Null tree!"); + delete categoryTree; + return 0; + } + if (checkTree) + { + vector<Node*> badNodes; + findBadNodes(rootNode,badNodes); + if (badNodes.size()>0) + { + print("Tree is not well-formed!"); + print("Bad tree has signature: "+signature(rootNode,&badNodes)); + delete categoryTree; + return 0; + } + } + treeVector->addTree(rootNode,weight); + } + if (verbose) print("Created a tree vector with "+to_string(numNodes)+" nodes"); + } + treeFile.close(); + if (file) + { + //file->Close(); + } + //delete file; + return categoryTree; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/TreeVector.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/TreeVector.cxx new file mode 100644 index 00000000000..3385305b2cb --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/TreeVector.cxx @@ -0,0 +1,6 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "TauDiscriminant/TreeVector.h" diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/Root/Types.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/Root/Types.cxx new file mode 100644 index 00000000000..42a0d57e4e6 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/Root/Types.cxx @@ -0,0 +1,5 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TauDiscriminant/Types.h" diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/BoostedDecisionTree.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/BoostedDecisionTree.h new file mode 100644 index 00000000000..fa8200b7217 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/BoostedDecisionTree.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#ifndef BOOSTEDDECISIONTREE_H +#define BOOSTEDDECISIONTREE_H + +#include <iostream> +#include <string> +#include <vector> +#include <map> +#include <utility> +#include "TauDiscriminant/Node.h" +#include "TauDiscriminant/TreeVector.h" + +using namespace std; + +class BoostedDecisionTree : public TreeVector { + + public: + + //!< Default Constructor + BoostedDecisionTree() {} + + /** + * @brief Returns the @c float score for the set of variables and values in @c variableMap. + * @param variableMap + */ + float response() const; + +}; + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/CommonLikelihood.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/CommonLikelihood.h new file mode 100644 index 00000000000..c207b745c51 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/CommonLikelihood.h @@ -0,0 +1,158 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: CommonLikelihood.h + * + * Author: Martin Flechl (mflechl@cern.ch) + */ + +#ifndef COMMONLIKELIHOOD_H +#define COMMONLIKELIHOOD_H + +#include <iostream> +#include <string> +#include <vector> +#include <map> +#include <assert.h> +#ifndef __STANDALONE +#include "GaudiKernel/MsgStream.h" +#endif + +#include "TH3.h" +#include "TFile.h" +#include "TString.h" +#include "TMath.h" +#include "TGraph.h" +using namespace std; + +//mw added +////////////////////////////////////////////////////////////////////////////////////////////// +const unsigned int NVAR_SAFE_1P=5; +const unsigned int NVAR_SAFE_3P=6; +const unsigned int NVAR_DEF=16; +////////////////////////////////////////////////////////////////////////////////////////////// + + +class CommonLikelihood{ + + public: + + //Constructor +#ifndef __STANDALONE + CommonLikelihood(bool _verbose=false,MsgStream* _log = 0):log(_log), +#else + CommonLikelihood(bool _verbose=false): +#endif + m_tauFile(NULL), + m_jetFile(NULL), + m_cutFile(NULL), + m_mu_correction_factor_1P(0.317), + m_mu_correction_factor_3P(0.117), + tg_loose_cuts_1P(NULL), + tg_medium_cuts_1P(NULL), + tg_tight_cuts_1P(NULL), + tg_loose_cuts_3P(NULL), + tg_medium_cuts_3P(NULL), + tg_tight_cuts_3P(NULL), + m_doTrigger(false) + { + if (_verbose) cout << "CommonLikelihood: Creating Instance..." << endl; + m_tauFilename="pdfs_tau.root"; + m_jetFilename="pdfs_jets.root"; + m_cutFilename="LMTCutsLLH.root"; + m_llh=-99; + m_et=-9999.; + m_prongindex=-1; + m_ntau[0]=0; m_ntau[1]=0; + NVAR=56; + DEBUG=0; + if (_verbose) DEBUG=1; + this->verbose = _verbose; + // DEBUG=2; + m_smooth = false; + } + ~CommonLikelihood(){ + if(m_tauFile) m_tauFile->Close(); + delete m_tauFile; + if(m_jetFile) m_jetFile->Close(); + delete m_jetFile; + if(m_cutFile) m_cutFile->Close(); + delete m_cutFile; + } + bool build(const string& filename); + int response(int level=-1, int option=-1) const; + bool calcLLHValue(const map<string,const float*>* floatVariables, + const map<string,const int*>* intVariables, int option); + float getLLHValue(){ return m_llh; } + + void setDoTrigger(bool trig) { m_doTrigger = trig; } + + private: + + bool readPDFHistograms(); + bool readLMTCuts(); + bool smoothPDFHistograms(); + void smooth3D(TH3F* hTmp); + TH3F* divideLog(TH3F* hTmpTau, TH3F* hTmpJet); + Double_t Interpolate(TH3F* hist, Double_t x, Double_t y, Double_t z); + int varNameToNumber(std::string varname) const; + float getSingleLLHRatio(const int ivar, const int numtrack, const int author, const float et, const int nvtx, const float value); + float getSimpleSingleLLHRatio(const int ivar, const int numtrack, const int author, const float et, const int nvtx, const float value); + bool skipVar(const TString varname,const int numtrack,const int author,const int option) const; + void splitString(const string& str, vector<string>& substrings, const string& delimiters = " ") const; + + void print(TString message, int level) const { +#ifndef __STANDALONE + if (log) { + if (level<=0) (*log) << "WARNING" << message << endreq; + else (*log) << "DEBUG" << message << endreq; + } + else +#endif + if (level<=DEBUG) cout << message << endl; + } + +#ifndef __STANDALONE + MsgStream* log; +#endif + + std::string m_tauFilename; + std::string m_cutFilename; + std::string m_jetFilename; + TFile *m_tauFile; + TFile *m_jetFile; + TFile *m_cutFile; + float m_llh; + float m_et; + int m_prongindex; + int m_nvtx; + int m_ntau[2]; + bool m_smooth; + + double m_mu_correction_factor_1P; + double m_mu_correction_factor_3P; + + std::vector<TGraph*> m_vLMTCuts1P; + std::vector<TGraph*> m_vLMTCuts3P; + int NVAR; + std::map<std::string,TH3F*> m_pdfHistogramsTau; + std::map<std::string,TH3F*> m_pdfHistogramsJet; + std::map<std::string,TH3F*> m_pdfHistogramsRatio; + TGraph* tg_loose_cuts_1P; + TGraph* tg_medium_cuts_1P; + TGraph* tg_tight_cuts_1P; + TGraph* tg_loose_cuts_3P; + TGraph* tg_medium_cuts_3P; + TGraph* tg_tight_cuts_3P; + + bool m_doTrigger; + + int DEBUG; + bool verbose; + + map<string,float> getVariables(const map<string,const float*>* floatVariables,const map<string,const int*>* intVariables, const int numtrack, const int author, const int option) const; +}; + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/CutsDecisionTree.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/CutsDecisionTree.h new file mode 100644 index 00000000000..bde85473dc6 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/CutsDecisionTree.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#ifndef CUTSDECISIONTREE_H +#define CUTSDECISIONTREE_H + +#include <iostream> +#include <string> +#include <vector> +#include <map> +#include <utility> +#include "TauDiscriminant/Node.h" +#include "TauDiscriminant/TreeVector.h" + +using namespace std; + +class CutsDecisionTree: public TreeVector { + + public: + + //!< Default Constructor + CutsDecisionTree() {} + + float response(unsigned int level) const; +}; + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/EMFCluster.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/EMFCluster.h new file mode 100644 index 00000000000..3092b134f2d --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/EMFCluster.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef EMFCluster_H +#define EMFCluster_H + +//*******************************************************// +// Name: EMFCluster.h // +// Author: Michel Trottier-McDonald <mtm@cern.ch> // +// Description: A simple class to house cluster // +// TLorentzVectors and their associated fractions of // +// energy in different calorimeter layers // +//*******************************************************// + +#include <TLorentzVector.h> + +class EMFCluster +{ +public: + //Constructor, Destructor + EMFCluster(); + EMFCluster(double pt); + EMFCluster(const TLorentzVector& inCluster, + double inPSSF, + double inEM2F, + double inEM3F); + ~EMFCluster(); + + //Getters + TLorentzVector TLV() const {return m_cluster;} + + double PSSF() const {return m_PSSF;} + double EM2F() const {return m_EM2F;} + double EM3F() const {return m_EM3F;} + double HADF() const {return m_HADF;} + double pseudoHADF() const {return m_pseudoHADF;} + + double PSSE() const {return m_PSSE;} + double EM2E() const {return m_EM2E;} + double EM3E() const {return m_EM3E;} + double HADE() const {return m_HADE;} + double pseudoHADE() const {return m_pseudoHADE;} + + //Comparison operator + bool operator< (const EMFCluster& rhs) const + { return (m_cluster.E() < rhs.TLV().E()); } + +private: + //Cluster 4-vector + TLorentzVector m_cluster; + + //Layer related info + double m_PSSF; // Fraction on energy in the PreSampler and Strip layers + double m_EM2F; // Fraction of energy in layer 2 of the EM calorimeter + double m_EM3F; // Fraction of energy in layer 3 of the EM calorimeter + double m_HADF; // Fraction of energy in the hadronic calorimeter + double m_pseudoHADF; // Fraction of energy in layer 3 of the EM calorimeter and hadronic calorimeter + + double m_PSSE; // Energy in the PreSampler and Strip layers + double m_EM2E; // Energy in layer 2 of the EM calorimeter + double m_EM3E; // Energy in layer 3 of the EM calorimeter + double m_HADE; // Energy in the hadronic calorimeter + double m_pseudoHADE; // Energy in layer 3 of the EM calorimeter and hadronic calorimeter + + //Calculate the hadronic fractions and energies + void update(); +}; + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/FakeTauBits.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/FakeTauBits.h new file mode 100644 index 00000000000..0d58ca62688 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/FakeTauBits.h @@ -0,0 +1,90 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AUTHOR: Noel Dawe +#ifndef FAKETAUBITS_H +#define FAKETAUBITS_H + +#include <bitset> +#include <algorithm> +#include "xAODTau/TauJet.h" +#include "DataModel/DataVector.h" +#include "SGTools/CLASS_DEF.h" + +namespace TauBit +{ + enum TauBit + { + BDT_LOOSE_BKG, + BDT_MEDIUM_BKG, + BDT_TIGHT_BKG + }; +} + +class FakeTauBits +{ + typedef TauBit::TauBit TauBit; + friend class FakeTauBitsContainer; + + public: + + FakeTauBits(const xAOD::TauJet* tau): + tau(tau) + {} + + void setBit(TauBit bit, bool value) + { + bits[bit] = value; + } + + bool getBit(TauBit bit) const + { + return bits[bit]; + } + + private: + + std::bitset<32> bits; + const xAOD::TauJet* tau; +}; + +class FakeTauBitsContainer: public DataVector<FakeTauBits> +{ + public: + + FakeTauBitsContainer( SG::OwnershipPolicy own = SG::OWN_ELEMENTS ): + DataVector<FakeTauBits>( own ) {} + + const FakeTauBits* getBitsAssocTo(const xAOD::TauJet* tau) const + { + if (!tau) + return 0; + FakeTauBitsContainer::const_iterator it(this->begin()); + FakeTauBitsContainer::const_iterator it_end(this->end()); + for(; it != it_end; ++it) + { + if (tau == (*it)->tau) + return *it; + } + return 0; + } + + const FakeTauBits* getBitsAssocTo(const xAOD::TauJet& tau) const + { + FakeTauBitsContainer::const_iterator it(this->begin()); + FakeTauBitsContainer::const_iterator it_end(this->end()); + for(; it != it_end; ++it) + { + if (&tau == (*it)->tau) + return *it; + } + return 0; + } +}; + +SG_BASE( FakeTauBitsContainer, DataVector<FakeTauBits> ); + +CLASS_DEF( FakeTauBitsContainer , 1316558256 , 1 ) + +#endif // FAKETAUBITS diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/FakeTauScores.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/FakeTauScores.h new file mode 100644 index 00000000000..c89bf4e1122 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/FakeTauScores.h @@ -0,0 +1,93 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AUTHOR: Noel Dawe +#ifndef FAKETAUSCORES_H +#define FAKETAUSCORES_H + +#include <algorithm> +#include "xAODTau/TauJet.h" +#include "DataModel/DataVector.h" +#include "SGTools/CLASS_DEF.h" + +namespace TauScore +{ + enum TauScore + { + BDT_TRANS_BKG, + BDT_TRANS_SIG, + BDT_PI0_PRIMARY, + BDT_PI0_SECONDARY, + __END__ + }; +} + +class FakeTauScores +{ + // DR: clang32 is confused by this + // typedef TauScore::TauScore TauScore; + friend class FakeTauScoresContainer; + + public: + + FakeTauScores(const xAOD::TauJet* tau): + scores(TauScore::__END__,0.), + tau(tau) + {} + + void setScore(TauScore::TauScore score, float value) + { + scores[score] = value; + } + + float getScore(TauScore::TauScore score) const + { + return scores[score]; + } + + private: + + std::vector<float> scores; + const xAOD::TauJet* tau; +}; + +class FakeTauScoresContainer: public DataVector<FakeTauScores> +{ + public: + + FakeTauScoresContainer( SG::OwnershipPolicy own = SG::OWN_ELEMENTS ): + DataVector<FakeTauScores>( own ) {} + + const FakeTauScores* getScoresAssocTo(const xAOD::TauJet* tau) const + { + if (!tau) + return 0; + FakeTauScoresContainer::const_iterator it(this->begin()); + FakeTauScoresContainer::const_iterator it_end(this->end()); + for(; it != it_end; ++it) + { + if (tau == (*it)->tau) + return *it; + } + return 0; + } + + const FakeTauScores* getScoresAssocTo(const xAOD::TauJet& tau) const + { + FakeTauScoresContainer::const_iterator it(this->begin()); + FakeTauScoresContainer::const_iterator it_end(this->end()); + for(; it != it_end; ++it) + { + if (&tau == (*it)->tau) + return *it; + } + return 0; + } +}; + +SG_BASE( FakeTauScoresContainer, DataVector<FakeTauScores> ); + +CLASS_DEF( FakeTauScoresContainer , 1249450621 , 1 ) + +#endif // FAKETAUSCORES diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodBDT.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodBDT.h new file mode 100644 index 00000000000..6097e77edf3 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodBDT.h @@ -0,0 +1,95 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#ifndef METHODBDT_H +#define METHODBDT_H + +#include <string> +#include <vector> +#include <stack> +#include <map> +#include <utility> +#include <iostream> +#include <fstream> +#include <sstream> +#include <algorithm> +#include <typeinfo> +#include "TauDiscriminant/MethodBase.h" +#include "TauDiscriminant/BoostedDecisionTree.h" +#include "TauDiscriminant/Node.h" +#include "TauDiscriminant/TreeReader.h" + +using namespace std; + +namespace TauID +{ + class MethodBDT : public MethodBase + { + public: + + //!< Default constructor + #ifdef __STANDALONE + MethodBDT(const string& _name = "", bool _verbose = false): + MethodBase(_name,_verbose), + isBuilt(false), + categoryTree(0) + {} + #else + MethodBDT(const string& _name = ""): + MethodBase(_name), + isBuilt(false), + categoryTree(0) + {} + #endif + + //!< Destructor + ~MethodBDT() + { + delete this->categoryTree; + } + + bool build(const string& filename, bool checkTree = false); + + float response() const; + + float response(unsigned int level) const + { + if (level != 0) + { + print("MethodBDT does not output more than one possible response."); + print("Use a MethodCuts on the MethodBDT response to determine loose, medium, and tight boolean values."); + } + return response(); + } + + BoostedDecisionTree* getCurrentCategory() const; + + Types::MethodType getType() const + { + return Types::BDT; + } + + void addVariable(const string& _name, const void* _value, char type = 'F') + { + MethodBase::addVariable(_name,_value,type); + } + + #ifndef __STANDALONE + void setDetails(const TauDetailsManager& manager) + { + MethodBase::setDetails(manager); + } + #endif + + private: + + bool isBuilt; + Node* categoryTree; + }; +} +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodBase.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodBase.h new file mode 100644 index 00000000000..a8227f41068 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodBase.h @@ -0,0 +1,177 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#ifndef METHODBASE_H +#define METHODBASE_H + +#include <string> +#include <iostream> +#include <map> +#include <algorithm> +#include "TauDiscriminant/Types.h" + +#ifndef __STANDALONE + //including the Message Stream Member + #include "AthenaKernel/MsgStreamMember.h" + #include "TauDiscriminant/TauDetailsManager.h" +#endif + +using namespace std; + +namespace TauID +{ + class MethodBase + { + public: + + //////////////////////////////////////////////////////////// + /// The name is an arbitrary name set by the user and should + /// have no influence on the behaviour of the method + //////////////////////////////////////////////////////////// + #ifdef __STANDALONE + MethodBase(const string& _name = "", bool _verbose = false): + name(_name), + verbose(_verbose) + {} + #else + MethodBase(const string& _name = ""): + name(_name) + {} + #endif + + virtual ~MethodBase() {} + + /////////////////////////////////////////////////////////// + /// Return the value of a continuous discriminant + /////////////////////////////////////////////////////////// + virtual float response() const =0; + + /////////////////////////////////////////////////////////// + /// This method should only be used for cut-based + /// methods for responses at different levels of + /// "tightness." For continuous discriminants, this + /// method should print a warning message and + /// return the value of response() above. + /////////////////////////////////////////////////////////// + virtual float response(unsigned int level) const =0; + + string getName() const + { + return name; + } + + /////////////////////////////////////////////////////////// + /// Add a variable. You should not need to + /// override this method. + /////////////////////////////////////////////////////////// + void addVariable(const string& _name, const void* value, char type = 'F') + { + if (!value) + { + print("Variable pointer is NULL!"); + return; + } + string localname = _name; + // Convert to uppercase: + std::transform(localname.begin(), localname.end(), localname.begin(), &upper); + if (type == 'F') + { + this->floatVariables[localname] = (const float*)value; + } + else if (type == 'I') + { + this->intVariables[localname] = (const int*)value; + } + else + { + print("Unsupported variable type!"); + } + } + + #ifndef __STANDALONE + ////////////////////////////////////////////////////////// + /// This method is used in Athena to set the + /// variables instead of the addVariable method + ////////////////////////////////////////////////////////// + void setDetails(const TauDetailsManager& manager) + { + const map<string,float*>* floatDetails = manager.getFloatDetails(); + map<string,float*>::const_iterator it1(floatDetails->begin()); + for (; it1 != floatDetails->end(); ++it1 ) + { + this->addVariable(it1->first,it1->second,'F'); + } + const map<string,int*>* intDetails = manager.getIntDetails(); + map<string,int*>::const_iterator it2(intDetails->begin()); + for (; it2 != intDetails->end(); ++it2 ) + { + this->addVariable(it2->first,it2->second,'I'); + } + } + #endif + + void print(string message) const + { + #ifdef __STANDALONE + if (this->verbose) + { + cout << message << endl; + } + #else + if (msgLvl(MSG::VERBOSE)) + { + msg(MSG::VERBOSE) << message << endreq; + } + #endif + } + + //////////////////////////////////////////////////////////// + /// Build the discriminant from an input file + /// The first parameter is a filename. Your method + /// should be saved in only one file. + /// Specifying a list of files here separated + /// by commas, for example, is not acceptable. + /// The boolean parameter is optional and may be + /// used to optionally validate your method after + /// building from your input file. + //////////////////////////////////////////////////////////// + virtual bool build(const string&, bool = false) =0; + + virtual Types::MethodType getType() const =0; + + #ifndef __STANDALONE + //Declaring the Message method for further use + MsgStream& msg( MSG::Level lvl ) const { return m_msg << lvl ; } + + //Declaring the Method providing Verbosity Level + bool msgLvl( MSG::Level lvl ) const { return m_msg.get().level() <= lvl ; } + #endif + + private: + + static int upper(int c) + { + return std::toupper((unsigned char)c); + } + + string name; + + protected: + + #ifdef __STANDALONE + bool verbose; + #else + //Declaring private message stream member. + mutable Athena::MsgStreamMember m_msg ; + #endif + + map<string,const float*> floatVariables; + map<string,const int*> intVariables; + }; +} +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodCuts.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodCuts.h new file mode 100644 index 00000000000..3f9a72f6bce --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodCuts.h @@ -0,0 +1,98 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#ifndef METHODCUTS_H +#define METHODCUTS_H + +#include <string> +#include <vector> +#include <stack> +#include <map> +#include <utility> +#include <iostream> +#include <fstream> +#include <sstream> +#include <algorithm> +#include <typeinfo> +#include "TauDiscriminant/MethodBase.h" +#include "TauDiscriminant/CutsDecisionTree.h" +#include "TauDiscriminant/Node.h" +#include "TauDiscriminant/TreeReader.h" + +using namespace std; + +namespace TauID +{ + class MethodCuts : public MethodBase + { + public: + + //!< Default constructor + #ifdef __STANDALONE + MethodCuts(const string& _name = "", bool _verbose = false): + MethodBase(_name,_verbose), + isBuilt(false), + nLevels(0), + categoryTree(0) + {} + #else + MethodCuts(const string& _name = ""): + MethodBase(_name), + isBuilt(false), + nLevels(0), + categoryTree(0) + {} + #endif + + //!< Destructor + ~MethodCuts() + { + delete this->categoryTree; + } + + bool build(const string& filename, bool checkTree = false); + + float response() const + { + return response(0); + } + + float response(unsigned int level) const; + + unsigned int numLevels() const + { + return this->nLevels; + } + + CutsDecisionTree* getCurrentCategory() const; + + Types::MethodType getType() const + { + return Types::CUTS; + } + + void addVariable(const string& _name, const void* _value, char type = 'F') + { + MethodBase::addVariable(_name,_value,type); + } + + #ifndef __STANDALONE + void setDetails(const TauDetailsManager& manager) + { + MethodBase::setDetails(manager); + } + #endif + + private: + + bool isBuilt; + unsigned int nLevels; + Node* categoryTree; + }; +} +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodDummy.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodDummy.h new file mode 100644 index 00000000000..23943206f2b --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodDummy.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * MethodDummy is used for speed benchmarking the other Methods. + * A better approximation of a Method's processing time per classification instance + * is after subtraction of the processing time per entry of MethodDummy to remove + * data I/O time and other constant overhead. + * + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#ifndef METHODDUMMY_H +#define METHODDUMMY_H + +#include "TauDiscriminant/MethodBase.h" + +using namespace std; + +namespace TauID +{ + class MethodDummy : public MethodBase + { + public: + + //!< Default constructor + #ifdef __STANDALONE + MethodDummy(const string& _name = "", bool _verbose = false): + MethodBase(_name,_verbose) + {} + #else + MethodDummy(const string& _name = ""): + MethodBase(_name) + {} + #endif + + //!< Destructor + ~MethodDummy() + {} + + bool build(const string& filename, bool checkTree = false); + + float response() const; + + float response(unsigned int level) const + { + if (level != 0) + { + print("MethodDummy does not output more than one possible response."); + } + return response(); + } + + Types::MethodType getType() const + { + return Types::DUMMY; + } + }; +} +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodLLH.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodLLH.h new file mode 100644 index 00000000000..5879fb0290e --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodLLH.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: MethodLLH.h + * + * Author: Martin Flechl (mflechl@cern.ch) + */ + +#ifndef METHODLLH_H +#define METHODLLH_H + +#include <string> +#include <vector> +#include <stack> +#include <map> +#include <utility> +#include <iostream> +#include <fstream> +#include <sstream> +#include <algorithm> +#include <typeinfo> +#include "TauDiscriminant/MethodBase.h" +#include "TauDiscriminant/CommonLikelihood.h" + +using namespace std; + +namespace TauID +{ + class MethodLLH : public MethodBase { + + public: + + #ifdef __STANDALONE + MethodLLH(const string& _name = "", bool _verbose = false): + MethodBase(_name,_verbose), + isBuilt(false), + nLevels(0), + llh(NULL) + {} + #else + MethodLLH(const string& _name = ""): + MethodBase(_name), + isBuilt(false), + nLevels(0), + llh(NULL) + {} + #endif + + ~MethodLLH() { + delete llh; + } + + bool build(const string& filename, bool check=false); + + float response() const { return response(0); } + + float response(unsigned int level) const; + + unsigned int numLevels() const { return this->nLevels; } + + Types::MethodType getType() const{ return Types::LLH; } + + void addVariable(const string& _name, const void* _value, char type = 'F') { MethodBase::addVariable(_name,_value,type); } + + #ifndef __STANDALONE + void setDetails(const TauDetailsManager& manager){ MethodBase::setDetails(manager); } + void setDoTrigger(const TauDetailsManager& manager) { llh->setDoTrigger(manager.getDoTrigger()); } + #endif + + private: + + bool isBuilt; + unsigned int nLevels; + CommonLikelihood* llh; + int m_option; + + }; +} +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodTransform.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodTransform.h new file mode 100644 index 00000000000..0e9a5f48d5d --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/MethodTransform.h @@ -0,0 +1,94 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#ifndef METHODTRANSFORM_H +#define METHODTRANSFORM_H + +#include <string> +#include <vector> +#include <stack> +#include <map> +#include <utility> +#include <iostream> +#include <fstream> +#include <sstream> +#include <algorithm> +#include <typeinfo> +#include "TauDiscriminant/MethodBase.h" +#include "TauDiscriminant/TreeReader.h" +#include "TauDiscriminant/Node.h" +#include "TauDiscriminant/Transformation.h" + +using namespace std; + +namespace TauID +{ + class MethodTransform : public MethodBase + { + public: + + //!< Default constructor + #ifdef __STANDALONE + MethodTransform(const string& _name = "", bool _verbose = false): + MethodBase(_name,_verbose), + isBuilt(false), + categoryTree(0) + {} + #else + MethodTransform(const string& _name = ""): + MethodBase(_name), + isBuilt(false), + categoryTree(0) + {} + #endif + + //!< Destructor + ~MethodTransform() + { + delete this->categoryTree; + } + + bool build(const string& filename, bool check = false); + + float response() const; + + float response(unsigned int level) const + { + if (level != 0) + { + print("MethodTransform does not output more than one possible response."); + } + return response(); + } + + Transformation* getCurrentCategory() const; + + Types::MethodType getType() const + { + return Types::TRANSFORM; + } + + void addVariable(const string& _name, const void* _value, char type = 'F') + { + MethodBase::addVariable(_name,_value,type); + } + + #ifndef __STANDALONE + void setDetails(const TauDetailsManager& manager) + { + MethodBase::setDetails(manager); + } + #endif + + private: + + bool isBuilt; + Node* categoryTree; + }; +} +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Node.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Node.h new file mode 100644 index 00000000000..2cbcffa8ebb --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Node.h @@ -0,0 +1,371 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//! This is a node class. +/** + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#include <iostream> +using namespace std; + +#ifndef NODE_H +#define NODE_H + +//!< Abstract base class +class Node +{ + public: + + virtual ~Node() {} + virtual bool isLeaf(void) const =0; + virtual bool isComplete(void) const =0; + virtual Node* clone(void) const =0; + virtual Node* getLeftChild(void) const =0; + virtual Node* getRightChild(void) const =0; +}; + +class DecisionNode: public Node +{ + public: + + /** + * @brief Set left child of this node. + * @param child a @c Node pointer to the new left child. + */ + void setLeftChild(Node* child) + { + if (leftChild != 0) delete leftChild; + leftChild = child; + } + + /** + * @brief Set right child of this node. + * @param child a @c Node pointer to the new right child. + */ + void setRightChild(Node* child) + { + if (rightChild != 0) delete rightChild; + rightChild = child; + } + + /** + * @brief Returns a pointer to the left child node. + * @return a @c Node pointer to the left child node. + */ + Node* getLeftChild() const { return this->leftChild; } + + /** + * @brief Returns a pointer to the right child node. + * @return a @c Node pointer to the right child node. + */ + Node* getRightChild() const { return this->rightChild; } + + /** + * @brief Returns true if node has no children and false otherwise. + * @return true if node has no children and false otherwise. + */ + bool isLeaf() const { return !this->rightChild && !this->leftChild; } + + /** + * @brief Returns true if both children exist. + * @return true if both children exist. + */ + bool isComplete() const { return this->rightChild && this->leftChild; } + + //virtual void setLeftChild(Node* node) =0; + //virtual void setRightChild(Node* node) =0; + virtual bool goRight(void) const =0; + + protected: + + Node* leftChild; + Node* rightChild; +}; + +template <class T> +class UnivariateCut: public DecisionNode +{ + public: + + //!< Constructor + UnivariateCut(const T* _feature, T _cut): + feature(_feature), + cut(_cut) + { + this->leftChild = 0; + this->rightChild = 0; + } + + //!< Copy Constructor + UnivariateCut(const UnivariateCut<T>& other) + { + this->feature = other.feature; + this->cut = other.cut; + this->leftChild = other.leftChild ? other.leftChild->clone() : 0; + this->rightChild = other.rightChild ? other.rightChild->clone() : 0; + } + + //!< Destructor + ~UnivariateCut() + { + delete this->rightChild; + delete this->leftChild; + } + + Node* clone() const + { + UnivariateCut<T>* node = new UnivariateCut<T>(this->feature,this->cut); + if (this->leftChild) node->setLeftChild(this->leftChild->clone()); + if (this->rightChild) node->setRightChild(this->rightChild->clone()); + return node; + } + + bool goRight() const { return this->feature ? *this->feature > this->cut : false; } + + const T* getFeature() const { return this->feature; } + + T getValue() const { return this->feature ? *this->feature : -9999.; } + + T getCut() const { return this->cut; } + + private: + + const T* feature; //!< Pointer to the variable which is cut on at this node. + T cut; //!< The cut. +}; + +template <class T, class U, class V> +class UnivariateSlidingCut1D: public DecisionNode +{ + public: + + //!< Constructor + UnivariateSlidingCut1D(const T* _feature, U* _function, const V* _variable): + feature(_feature), + function(_function), + variable(_variable) + { + this->leftChild = 0; + this->rightChild = 0; + } + + //!< Copy Constructor + UnivariateSlidingCut1D(const UnivariateSlidingCut1D<T,U,V>& other) + { + this->feature = other.feature; + this->function = other.function->Clone(); + this->variable = other.variable; + this->leftChild = other.leftChild ? other.leftChild->clone() : 0; + this->rightChild = other.rightChild ? other.rightChild->clone() : 0; + } + + //!< Destructor + ~UnivariateSlidingCut1D() + { + delete this->function; + delete this->rightChild; + delete this->leftChild; + } + + Node* clone() const + { + UnivariateSlidingCut1D<T,U,V>* node = new UnivariateSlidingCut1D<T,U,V>(this->feature,(U*)this->function->Clone(),this->variable); + if (this->leftChild) node->setLeftChild(this->leftChild->clone()); + if (this->rightChild) node->setRightChild(this->rightChild->clone()); + return node; + } + + bool goRight() const + { + return this->feature && this->variable ? *this->feature > this->function->Eval(float(*this->variable)) : false; + } + + private: + + const T* feature; + U* function; + const V* variable; +}; + +template <class T, class U, class V, class W> +class MultivariateCut2D: public DecisionNode +{ + public: + + //!< Constructor + MultivariateCut2D(T* _function, const U* _x, const V* _y, W _cut): + function(_function), + x(_x), + y(_y), + cut(_cut) + { + this->leftChild = 0; + this->rightChild = 0; + } + + //!< Copy Constructor + MultivariateCut2D(const MultivariateCut2D<T,U,V,W>& other) + { + this->function = other.function->Clone(); + this->x = other.x; + this->y = other.y; + this->cut = other.cut; + this->leftChild = other.leftChild ? other.leftChild->clone() : 0; + this->rightChild = other.rightChild ? other.rightChild->clone() : 0; + } + + //!< Destructor + ~MultivariateCut2D() + { + delete this->function; + delete this->rightChild; + delete this->leftChild; + } + + Node* clone() const + { + MultivariateCut2D<T,U,V,W>* node = new MultivariateCut2D<T,U,V,W>((T*)this->function->Clone(),this->x,this->y,this->cut); + if (this->leftChild) node->setLeftChild(this->leftChild->clone()); + if (this->rightChild) node->setRightChild(this->rightChild->clone()); + return node; + } + + bool goRight() const + { + return this->function && this->x && this->y ? this->function->Eval(float(*this->x),float(*this->y)) > cut : false; + } + + private: + + T* function; + const U* x; + const V* y; + W cut; +}; + + +template <class T> +class LeafNode: public Node +{ + public: + + LeafNode(T _value = 0):value(_value){} + + LeafNode(const LeafNode<T>& other) { this->value = other.value; } + + ~LeafNode(){} + + Node* clone() const { return new LeafNode<T>(this->value); } + + bool isLeaf() const { return true; } + + Node* getLeftChild() const { return 0; } + + Node* getRightChild() const { return 0; } + + bool isComplete() const { return true; } + + virtual T getValue() const { return this->value; } + + void setValue(T _value) { this->value = _value; } + + private: + + T value; +}; + +template <class X, class Y, class G> +class TransformationNode: public LeafNode<float> +{ + public: + + TransformationNode(const X* _x, float _xlow, float _xhigh, const Y* _y, float _ylow, float _yhigh, G* _transform): + x(_x), + xlow(_xlow), + xhigh(_xhigh), + y(_y), + ylow(_ylow), + yhigh(_yhigh), + transform(_transform) + {} + + TransformationNode(const TransformationNode<X,Y,G>& other) + { + this->x = other.x; + this->xlow = other.xlow; + this->xhigh = other.xhigh; + this->y = other.y; + this->ylow = other.ylow; + this->yhigh = other.yhigh; + this->transform = other.transform->Clone(); + } + + ~TransformationNode() + { + //delete transform; + } + + Node* clone() const + { + return new TransformationNode<X,Y,G>(x,xlow,xhigh,y,ylow,yhigh,(G*)transform->Clone()); + } + + float getValue() const + { + float _x = float(*x); + float _y = float(*y); + if (_x < xlow) + _x = xlow; + else if (_x > xhigh) + _x = xhigh; + if (_y < ylow) + _y = ylow; + else if (_y > yhigh) + _y = yhigh; + return this->transform->Interpolate(_x, _y); + } + + private: + + const X* x; + float xlow; + float xhigh; + const Y* y; + float ylow; + float yhigh; + G* transform; +}; + +template <class T> +class PointerLeafNode: public Node +{ + public: + + PointerLeafNode(T* _value = 0):value(_value){} + + PointerLeafNode(const PointerLeafNode<T>& other) { this->value = other.value; } + + ~PointerLeafNode() { delete this->value; } + + Node* clone() const { return new PointerLeafNode<T>(this->value); } + + bool isLeaf() const { return true; } + + Node* getLeftChild() const { return 0; } + + Node* getRightChild() const { return 0; } + + bool isComplete() const { return true; } + + T* getValue() const { return this->value; } + + void setValue(T* _value) { this->value = _value; } + + private: + + T* value; +}; + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/NoiseCorrIsol.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/NoiseCorrIsol.h new file mode 100644 index 00000000000..627d84e280d --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/NoiseCorrIsol.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef NOISECORRISOL_H +#define NOISECORRISOL_H + +//*******************************************************// +// Name: NoiseCorrIsol.h // +// Author: Michel Trottier-McDonald <mtm@cern.ch> // +// Description: A class to provide isolation based // +// pileup/underlying event correction to the clusters // +// of tau decays // +//*******************************************************// + +#include <TLorentzVector.h> +#include "TauDiscriminant/EMFCluster.h" +#include <vector> + +class NoiseCorrIsol +{ +public: + // Constructors, Destructors + NoiseCorrIsol(); + + NoiseCorrIsol(const TLorentzVector& tau, + const std::vector<TLorentzVector>& clusters, + double innerDR=0.3, + double outerDR=0.4, + bool eff=false); + + NoiseCorrIsol(const TLorentzVector& tau, + const std::vector<EMFCluster>& clusters, + double innerDR=0.3, + double outerDR=0.4, + bool eff=false); + + ~NoiseCorrIsol(); + + //Getters + std::vector<TLorentzVector> correctedClustersTLV(); + std::vector<EMFCluster> correctedClusters(); + +private: + + std::vector<TLorentzVector> m_clusters; + std::vector<EMFCluster> m_EMFClusters; + + TLorentzVector m_tau; + + double m_innerDR; + double m_outerDR; + double m_areaRatio; + + double areaRatio(); + std::vector<EMFCluster> effClusters(const std::vector<EMFCluster>& inputClusters); + + bool m_eff; + +}; + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Pi0Finder.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Pi0Finder.h new file mode 100644 index 00000000000..75150d10036 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Pi0Finder.h @@ -0,0 +1,123 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef PI0FINDER_H +#define PI0FINDER_H + +//*******************************************************// +// Name: Pi0Finder.h // +// Author: Michel Trottier-McDonald <mtm@cern.ch> // +// Description: Main class to find which clusters are // +// the pi0s in tau decays involving neutral pions // +//*******************************************************// + +#include <TLorentzVector.h> +#include "TauDiscriminant/EMFCluster.h" +#include <vector> + +class Pi0Finder +{ +public: + // Constructors, Destructors + Pi0Finder(); + + Pi0Finder(const std::vector<TLorentzVector>& tracks, + const std::vector<EMFCluster>& clusters, + bool twoPi0s = true, + double resImportance = 1.0, + double turnOnPoint = 1.05, + double turnOnRate = 9, + double PSSFactor = 1.4, + double EM2Factor = 0.4, + double twoPi0Strength = 0.4, + bool usePseudoHADF = true, + bool effClusters = false); + + Pi0Finder(const std::vector<TLorentzVector>& tracks, + const std::vector<TLorentzVector>& clusters, + const std::vector<float>& PSSFs, + const std::vector<float>& EM2Fs, + const std::vector<float>& EM3Fs, + bool twoPi0s = true, + double resImportance = 1.0, + double turnOnPoint = 1.05, + double turnOnRate = 9, + double PSSFactor = 1.4, + double EM2Factor = 0.4, + double twoPi0Strength = 0.4, + bool usePseudoHADF = true, + bool effClusters = false); + + ~Pi0Finder(); + + //Getters + TLorentzVector visTauTLV() const; //Returns the visible tau + TLorentzVector pi0TLV1() const {return m_selEMFCluster1.TLV();} + TLorentzVector pi0TLV2() const {return m_selEMFCluster2.TLV();} + TLorentzVector pi0NotCorrTLV1() const {return m_selEMFClusterNotCorr1.TLV();} + TLorentzVector pi0NotCorrTLV2() const {return m_selEMFClusterNotCorr2.TLV();} + EMFCluster pi0EMFCluster1() const {return m_selEMFCluster1;} + EMFCluster pi0EMFCluster2() const {return m_selEMFCluster2;} + double doubleCounting() const {return m_doubleCountingE;} + bool corrected1() const {return m_applyCorrCluster1;} + bool corrected2() const {return m_applyCorrCluster2;} + bool noMatch() const {return m_noMatch;} + +private: + + //The candidate clusters (after noise correction) + std::vector<EMFCluster> m_EMFClusters; + + //the tracks + std::vector<TLorentzVector> m_tracks; + + //General parameters + bool m_usePseudoHADF; + bool m_twoPi0s; + + //Selection parameters + double m_resImportance; // Importance of the resolution of the cluster energy compared to calo energy - track energy + + //Contamination correction parameters + double m_turnOnPoint; // Value of energy double counting at which the correction turns on. + double m_turnOnRate; // How quickly the correction turns on after the turn on point + double m_PSSFactor; // How many times the PreSampler-Strip Energy when finding the corrected energy + double m_EM2Factor; // How many times the EMLayer 2 Energy when finding the corrected energy + double m_twoPi0Strength; //Biases the preference for finding 1 or 2 clusters + + //Internal transient parameters + double m_caloE; // total calorimeter energy + double m_caloHADE; // total hadronic (pseudo-hadronic) calorimeter energy + double m_trkE; // total track system energy + double m_trkHADF; // energy in the hadronic (pseudo-hadronic) calorimeter divided by the track energy + double m_doubleCountingE; // Values above 1 roughly indicates energy double counting, used to decide to correct cluster energy or not + bool m_applyCorrCluster1; // Apply correction to cluster 1 + bool m_applyCorrCluster2; // Apply correction to cluster 2 + bool m_keepCluster1; // Keep Cluster1 + bool m_keepCluster2; // Keep Cluster2 + bool m_noMatch; // True if no pi0 has been selected + + TLorentzVector m_trkSys; + + //Results + EMFCluster m_selEMFCluster1; + EMFCluster m_selEMFCluster2; + EMFCluster m_selEMFClusterNotCorr1; + EMFCluster m_selEMFClusterNotCorr2; + + //Internal methods + void preSelParameters(); // Calculate pre-selection internal transient parameters + void postSelParameters(); // Calculate post-selection internal transient parameters + void select(); // Select one pi0 cluster + void select2(); // Select two pi0 clusters + EMFCluster correct(const EMFCluster& cl); // Correct the energy of one contaminated cluster + EMFCluster giveMass(const EMFCluster& cl); // Give the pi0 mass to uncorrected clusters + void execute(); // Execute the pi0 finding + std::vector<EMFCluster> convertToEMFClusters(const std::vector<TLorentzVector>& clusters, + const std::vector<float>& PSSFs, + const std::vector<float>& EM2Fs, + const std::vector<float>& EM3Fs); +}; + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauCuts.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauCuts.h new file mode 100644 index 00000000000..2fc682b0856 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauCuts.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUCUTS_H +#define TAUCUTS_H + +#include "TauDiscriminant/TauDiscriToolBase.h" +#include "TauDiscriminant/MethodCuts.h" +#include "TauDiscriminant/TauDetailsManager.h" +#include <string> + +using namespace TauID; + +class TauCuts: public TauDiscriToolBase +{ + public: + + //----------------------------------------------------------------- + // Contructor and destructor + //----------------------------------------------------------------- + TauCuts(const string& type, + const string& name, + const IInterface* parent): + TauDiscriToolBase(type, name, parent) + { + declareInterface<TauDiscriToolBase>(this); + declareProperty( "cuts", m_fileName); + } + + virtual ~TauCuts() {} + + //----------------------------------------------------------------- + // Gaudi algorithm hooks + //----------------------------------------------------------------- + virtual StatusCode prepare(const TauDetailsManager&); + + virtual StatusCode execute(xAOD::TauJet*, FakeTauBits*, FakeTauScores*); + + virtual StatusCode finalize(); + + private: + + std::string m_fileName; + MethodCuts* m_cutsManager; +}; + +#endif // TAUCUTS_H diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauCutsEleVeto.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauCutsEleVeto.h new file mode 100644 index 00000000000..e3bfabb8644 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauCutsEleVeto.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUCUTSELEVETO_H +#define TAUCUTSELEVETO_H + +#include "TauDiscriminant/TauDiscriToolBase.h" +#include "TauDiscriminant/TauDetailsManager.h" +#include <string> + +class TauCutsEleVeto: public TauDiscriToolBase +{ + public: + + //----------------------------------------------------------------- + // Contructor and destructor + //----------------------------------------------------------------- + TauCutsEleVeto(const string& type, + const string& name, + const IInterface* parent): + TauDiscriToolBase(type, name, parent), + detailsManager(0), + useLCscale(false) + { + declareInterface<TauDiscriToolBase>(this); + + declareProperty("useLCscale", this->useLCscale); + } + + virtual ~TauCutsEleVeto() {} + + //----------------------------------------------------------------- + // Gaudi algorithm hooks + //----------------------------------------------------------------- + virtual StatusCode prepare(const TauDetailsManager&); + + virtual StatusCode execute(xAOD::TauJet*, FakeTauBits*, FakeTauScores*); + + virtual StatusCode finalize(); + + private: + + const TauDetailsManager* detailsManager; + bool useLCscale; +}; + +#endif // TAUCUTSELEVETO_H diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDetails.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDetails.h new file mode 100644 index 00000000000..052fccef399 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDetails.h @@ -0,0 +1,146 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/* + * Author: Noel Dawe <Noel-dot-Dawe-AT-cern-dot-ch> + */ + +#ifndef TAUDETAILS_H +#define TAUDETAILS_H + +#include <string> + +// Add new details to the proper block below (4 blocks: int/float tau details and int/float event details) +// Use all caps, but note that in the end, detail names are case insensitive +// since they are always compared in the uppercase state when building the discriminants at init +// Using this "ENUM_OR_STRING" macro allows as to use the same list to init enums (below) +// as well as arrays of strings (in the same order) (see TauDetailsManager.cxx) + +#define INT_TAU_DETAILS \ + ENUM_OR_STRING( AUTHOR ), \ + ENUM_OR_STRING( TAU_PI0_N ), \ + ENUM_OR_STRING( CHARGE ), \ + ENUM_OR_STRING( NUMTRACK ), \ + ENUM_OR_STRING( NUMWIDETRACK ), \ + ENUM_OR_STRING( NSTRIP ), \ + ENUM_OR_STRING( NISOLLOOSETRK ), \ + ENUM_OR_STRING( NPI0 ), \ + ENUM_OR_STRING( NPI0CL), \ + ENUM_OR_STRING( NISOLTRK ), \ + ENUM_OR_STRING( NUMTOPOCLUSTERS ), \ + ENUM_OR_STRING( __IntTauDetail__END__ ) + +#define FLOAT_TAU_DETAILS \ + ENUM_OR_STRING( ETA ), \ + ENUM_OR_STRING( ABS_ETA ), \ + ENUM_OR_STRING( ABS_ETA_LEAD_TRACK ), \ + ENUM_OR_STRING( TAU_ABSDELTAETA ), \ + ENUM_OR_STRING( TAU_ABSDELTAPHI ), \ + ENUM_OR_STRING( PHI ), \ + ENUM_OR_STRING( E ), \ + ENUM_OR_STRING( ET ), \ + ENUM_OR_STRING( PT ), \ + ENUM_OR_STRING( EMFRACTIONATEMSCALE ), \ + ENUM_OR_STRING( EMRADIUS ), \ + ENUM_OR_STRING( HADRADIUS ), \ + ENUM_OR_STRING( CALRADIUS ), \ + ENUM_OR_STRING( ISOLFRAC ), \ + ENUM_OR_STRING( CENTFRAC ), \ + ENUM_OR_STRING( STRIPWIDTH2 ), \ + ENUM_OR_STRING( TRFLIGHTPATHSIG ), \ + ENUM_OR_STRING( IPSIGLEADTRK ), \ + ENUM_OR_STRING( IPSIGLEADLOOSETRK ), \ + ENUM_OR_STRING( ETOVERPTLEADTRK ), \ + ENUM_OR_STRING( PTLEADTRKOVERET ), \ + ENUM_OR_STRING( IPZ0SINTHETASIGLEADTRK ), \ + ENUM_OR_STRING( MASSTRKSYS ), \ + ENUM_OR_STRING( TRKWIDTH2 ), \ + ENUM_OR_STRING( TRKAVGDIST ), \ + ENUM_OR_STRING( ETEFLOWOVERET ), \ + ENUM_OR_STRING( MEFLOW ), \ + ENUM_OR_STRING( SUMPT3TRK ), \ + ENUM_OR_STRING( SUMPT ), \ + ENUM_OR_STRING( DRMIN ), \ + ENUM_OR_STRING( DRMAX ), \ + ENUM_OR_STRING( SUMPT_OVER_ET ), \ + ENUM_OR_STRING( SUMPT3TRK_OVER_ET ), \ + ENUM_OR_STRING( ETHAD_EM_OVER_SUMPT3TRK ), \ + ENUM_OR_STRING( ETEM_EM_OVER_SUMPT3TRK ), \ + ENUM_OR_STRING( ETHAD_EM_OVER_SUMPT ), \ + ENUM_OR_STRING( ETEM_EM_OVER_SUMPT ), \ + ENUM_OR_STRING( TRT_NHT_OVER_NLT ), \ + ENUM_OR_STRING( M ), \ + ENUM_OR_STRING( TOPOINVMASS ), \ + ENUM_OR_STRING( EFFTOPOINVMASS ), \ + ENUM_OR_STRING( JVF ), \ + ENUM_OR_STRING( PT_PILEUP ), \ + ENUM_OR_STRING( TRACK_ISO ), \ + ENUM_OR_STRING( CALO_ISO ), \ + ENUM_OR_STRING( CALO_ISO_CORRECTED ), \ + ENUM_OR_STRING( LEAD2CLUSTEREOVERALLCLUSTERE ), \ + ENUM_OR_STRING( LEAD3CLUSTEREOVERALLCLUSTERE ), \ + ENUM_OR_STRING( HADLEAKET ),\ + ENUM_OR_STRING( SUMEMCELLETOVERLEADTRKPT ),\ + ENUM_OR_STRING( SECMAXSTRIPET ),\ + ENUM_OR_STRING( BDTJETSCORE ),\ + ENUM_OR_STRING( CHPIEMEOVERCALOEME ),\ + ENUM_OR_STRING( PSSFRACTION ),\ + ENUM_OR_STRING( EMPOVERTRKSYSP ),\ + ENUM_OR_STRING( EMEOVERTRKSYSE ), \ + ENUM_OR_STRING( CORRCENTFRAC ), \ + ENUM_OR_STRING( CORRFTRK ), \ + ENUM_OR_STRING( TAU_PI0_VISTAU_M ), \ + ENUM_OR_STRING( TAU_PTRATIO ), \ + ENUM_OR_STRING( INTERAXIS_ETA ), \ + ENUM_OR_STRING( INTERAXIS_PHI ), \ + ENUM_OR_STRING( PI0CL1_PT ), \ + ENUM_OR_STRING( PI0CL1_ETA ), \ + ENUM_OR_STRING( PI0CL1_PHI ), \ + ENUM_OR_STRING( PI0CL2_PT ), \ + ENUM_OR_STRING( PI0CL2_ETA ), \ + ENUM_OR_STRING( PI0CL2_PHI ), \ + ENUM_OR_STRING( VISTAU_PI0CL_PT ), \ + ENUM_OR_STRING( VISTAU_PI0CL_ETA ), \ + ENUM_OR_STRING( VISTAU_PI0CL_PHI ), \ + ENUM_OR_STRING( VISTAU_PI0CL_M ), \ + ENUM_OR_STRING( EMFRACTIONATEMSCALE_MOVEE3 ), \ + ENUM_OR_STRING( TAU_SEEDTRK_SECMAXSTRIPETOVERPT ), \ + ENUM_OR_STRING( __FloatTauDetail__END__ ) + +#define INT_EVENT_DETAILS \ + ENUM_OR_STRING( NUMVERTICES ), \ + ENUM_OR_STRING( NUMGOODVERTICES ),\ + ENUM_OR_STRING( NUM_PILEUP_AND_PRIMARY_VERTICES ),\ + ENUM_OR_STRING( __IntEventDetail__END__ ) + +#define FLOAT_EVENT_DETAILS \ + ENUM_OR_STRING( __FloatEventDetail__END__ ) + +#undef ENUM_OR_STRING +#define ENUM_OR_STRING( x ) x + +namespace Details +{ + enum IntTauDetail + { + INT_TAU_DETAILS + }; + + enum FloatTauDetail + { + FLOAT_TAU_DETAILS + }; + + enum IntEventDetail + { + INT_EVENT_DETAILS + }; + + enum FloatEventDetail + { + FLOAT_EVENT_DETAILS + }; +} + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDetailsManager.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDetailsManager.h new file mode 100644 index 00000000000..6845c6dda39 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDetailsManager.h @@ -0,0 +1,151 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*! + * file: TauDetailsManager.h + * + * This class provides a handle on the features used for tau/jet separation. + * + * To add new details: first add the enum entry in TauDetails.h and then + * implement the code in TauDetailsManager.cxx which sets the value for each tau/event + * + * Author: Noel Dawe (Noel-dot-Dawe-AT-cern-dot-ch) + */ + +#ifndef TAUDETAILSMANAGER_H +#define TAUDETAILSMANAGER_H + +#include <string> +#include <vector> +#include <map> +#include <algorithm> +#include <iostream> +#include <iomanip> + +#include "TauDiscriminant/TauDetails.h" +#include "xAODTau/TauJet.h" +// #include "tauEvent/TauCommonDetails.h" +#include "xAODTau/TauDefs.h" +#include "StoreGate/StoreGateSvc.h" +#include "AthenaKernel/MsgStreamMember.h" + +using namespace std; + +class TauDetailsManager +{ + public: + + static const float LOW_NUMBER; + + //!< Default constructor + TauDetailsManager(StoreGateSvc* =0, bool isTrigger=false); + + //!< Destructor + ~TauDetailsManager() {} + + const map<string,float*>* getFloatDetails() const { return &this->float_details; } + + const map<string,int*>* getIntDetails() const { return &this->int_details; } + + const float* getFloatDetailAddress(Details::FloatTauDetail) const; + + const int* getIntDetailAddress(Details::IntTauDetail) const; + + float getFloatDetailValue(Details::FloatTauDetail) const; + + int getIntDetailValue(Details::IntTauDetail) const; + + const float* getFloatDetailAddress(Details::FloatEventDetail) const; + + const int* getIntDetailAddress(Details::IntEventDetail) const; + + float getFloatDetailValue(Details::FloatEventDetail) const; + + int getIntDetailValue(Details::IntEventDetail) const; + + bool getDoTrigger() const { return doTrigger; } + + bool updateEvent(); + + bool update(const xAOD::TauJet& tauJet); //keep for backward compatibility + bool update_with_edm(xAOD::TauJet& tauJet); + + bool setNpi0(xAOD::TauJet& tauJet, int nPi0); + + friend MsgStream& operator<<(MsgStream&, const TauDetailsManager&); + + friend ostream& operator<<(ostream&, const TauDetailsManager&); + + //Declaring the Message method for further use + MsgStream& msg( MSG::Level lvl ) const { return m_msg << lvl; } + + //Declaring the Method providing Verbosity Level + bool msgLvl( MSG::Level lvl ) const { return m_msg.get().level() <= lvl; } + + protected: + + template <class stream> + void printOn(stream& o) const; + + private: + + map<string,float*> float_details; + map<string,int*> int_details; + vector<float> float_data; + vector<int> int_data; + vector<float> float_event_data; + vector<int> int_event_data; + StoreGateSvc* storeGate; + bool doTrigger; + mutable Athena::MsgStreamMember m_msg; + + float m_clusterCone; +}; + +template <class stream> +void TauDetailsManager::printOn(stream& o) const +{ + ios_base::fmtflags original_flags = (ios_base::fmtflags)o.flags(); + o << "\n\n"; + map<string,float*>::const_iterator it_float(this->float_details.begin()); + map<string,float*>::const_iterator it_float_end(this->float_details.end()); + const float* float_value(0); + for(; it_float != it_float_end; ++it_float) + { + o << left << setw(40) << setfill('.') << (it_float->first); + float_value = it_float->second; + if (float_value) + o << " " << *float_value << "\n"; + else + o << " NULL\n"; + } + + map<string,int*>::const_iterator it_int(this->int_details.begin()); + map<string,int*>::const_iterator it_int_end(this->int_details.end()); + const int* int_value(0); + for(; it_int != it_int_end; ++it_int) + { + o << left << setw(40) << setfill('.') << (it_int->first); + int_value = it_int->second; + if (int_value) + o << " " << *int_value << "\n"; + else + o << " NULL\n"; + } + o.flags(original_flags); +} + +inline MsgStream& operator<<(MsgStream& o, const TauDetailsManager& manager) +{ + manager.printOn<MsgStream>(o); + return o; +} + +inline ostream& operator<<(ostream& o, const TauDetailsManager& manager) +{ + manager.printOn<ostream>(o); + return o; +} + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDetailsManagerStandalone.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDetailsManagerStandalone.h new file mode 100644 index 00000000000..634a9577d8a --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDetailsManagerStandalone.h @@ -0,0 +1,176 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*! + * file: TauDetailsManagerStandalone.h + * + * This class provides a handle on the features used for tau/jet separation in standalone mode. + * + * To add new details: first add the enum entry in TauDetails.h and then + * implement the code in TauDetailsManagerStandalone.cxx which sets the value for each tau/event + * + * Author: Pawel Malecki(Pawel dot Malecki at cern dot ch) + */ + + +#ifndef TAUDETAILSMANAGERSTANDALONE_H +#define TAUDETAILSMANAGERSTANDALONE_H + + + +#include <string> +#include <vector> +#include <map> + + +#include "TauDiscriminant/TauDetails.h" + +#include <TTree.h> + +using namespace std; + +namespace TauID{ + class TauDetailsManagerStandalone + { + public: + + static const float LOW_NUMBER; + + //!< Default constructor + TauDetailsManagerStandalone(TTree* tree = 0); + + //!< Destructor + ~TauDetailsManagerStandalone() {} + + const map<string,float*>* getFloatDetails() const { return &this->float_details; } + + const map<string,int*>* getIntDetails() const { return &this->int_details; } + + const float* getFloatDetailAddress(Details::FloatTauDetail) const; + + const int* getIntDetailAddress(Details::IntTauDetail) const; + + float getFloatDetailValue(Details::FloatTauDetail) const; + + int getIntDetailValue(Details::IntTauDetail) const; + + const float* getFloatDetailAddress(Details::FloatEventDetail) const; + + const int* getIntDetailAddress(Details::IntEventDetail) const; + + float getFloatDetailValue(Details::FloatEventDetail) const; + + int getIntDetailValue(Details::IntEventDetail) const; + + bool getDoTrigger() const { return doTrigger; } + + bool updateEvent(int entry); + + bool update(unsigned int itau); + + bool initTree(TTree* tree); + + int getNtau(); + + + //Declaring the Message method for further use + + //Declaring the Method providing Verbosity Level + + + private: + + map<string,float*> float_details; + map<string,int*> int_details; + vector<float> float_data; + vector<int> int_data; + vector<float> float_event_data; + vector<int> int_event_data; + bool doTrigger; + + float m_clusterCone; + + TTree *m_tree; + + + + /// non-vector variables + int evt_calcVars_numGoodVertices; + + ///vector variables + vector<float> *tau_charge; + vector<int> *tau_author; + vector<int> *tau_numTrack; + vector<int> *tau_seedCalo_nWideTrk; + vector<float> *tau_eta; + vector<float> *tau_phi; + vector<float> *tau_pt; + vector<float> *tau_seedCalo_trkAvgDist; + vector<float> *tau_etOverPtLeadTrk; + vector<float> *tau_calcVars_EMFractionAtEMScale; + vector<float> *tau_TRTHTOverLT_LeadTrk; + vector<float> *tau_seedCalo_dRmax; + vector<float> *tau_leadTrack_eta; + vector<float> *tau_calcVars_ChPiEMEOverCaloEME; + vector<float> *tau_seedTrk_secMaxStripEt; + vector<float> *tau_seedTrk_hadLeakEt; + vector<float> *tau_seedTrk_sumEMCellEtOverLeadTrkPt; + vector<float> *tau_calcVars_corrFTrk; + vector<float> *tau_calcVars_corrCentFrac; + vector<float> *tau_seedCalo_isolFrac; + vector<float> *tau_seedCalo_hadRadius; + vector<float> *tau_calcVars_PSSFraction; + vector<float> *tau_calcVars_EMPOverTrkSysP; + vector<int> *tau_seedCalo_nStrip; + vector<float> *tau_massTrkSys; + vector<float> *tau_ipSigLeadTrk; + vector<float> *tau_trFlightPathSig; + vector<float> *tau_pi0_vistau_m; + vector<float> *tau_pi0_vistau_pt; + vector<int> *tau_pi0_n; + vector<float> *tau_seedCalo_etEMAtEMScale; + vector<float> *tau_seedCalo_etHadAtEMScale; + vector<float> *tau_leadTrkPt; + vector<float> *tau_leadTrack_phi; + + TBranch *b_evt_calcVars_numGoodVertices; + TBranch *b_tau_charge; + TBranch *b_tau_author; + TBranch *b_tau_numTrack; + TBranch *b_tau_seedCalo_nWideTrk; + TBranch *b_tau_eta; + TBranch *b_tau_phi; + TBranch *b_tau_pt; + TBranch *b_tau_seedCalo_trkAvgDist; + TBranch *b_tau_etOverPtLeadTrk; + TBranch *b_tau_calcVars_EMFractionAtEMScale; + TBranch *b_tau_TRTHTOverLT_LeadTrk; + TBranch *b_tau_seedCalo_dRmax; + TBranch *b_tau_leadTrack_eta; + TBranch *b_tau_calcVars_ChPiEMEOverCaloEME; + TBranch *b_tau_seedTrk_secMaxStripEt; + TBranch *b_tau_seedTrk_hadLeakEt; + TBranch *b_tau_seedTrk_sumEMCellEtOverLeadTrkPt; + TBranch *b_tau_calcVars_corrFTrk; + TBranch *b_tau_calcVars_corrCentFrac; + TBranch *b_tau_seedCalo_isolFrac; + TBranch *b_tau_seedCalo_hadRadius; + TBranch *b_tau_calcVars_PSSFraction; + TBranch *b_tau_seedCalo_nStrip; + TBranch *b_tau_massTrkSys; + TBranch *b_tau_ipSigLeadTrk; + TBranch *b_tau_trFlightPathSig; + TBranch *b_tau_calcVars_EMPOverTrkSysP; + TBranch *b_tau_pi0_n; + TBranch *b_tau_pi0_vistau_m; + TBranch *b_tau_pi0_vistau_pt; + TBranch *b_tau_seedCalo_etEMAtEMScale; + TBranch *b_tau_seedCalo_etHadAtEMScale; + TBranch *b_tau_leadTrkPt; + TBranch *b_tau_leadTrack_phi; + + }; +} +#endif + diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDiscriBuilder.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDiscriBuilder.h new file mode 100644 index 00000000000..a9078a95b21 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDiscriBuilder.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauDiscriBuilder.h +// package: PhysicsAnalysis/TauID/TauDiscriminant +// authors: M. Wolter, A. Kaczmarska +// date: 13 March 2008 +//----------------------------------------------------------------------------- + +#ifndef DISCRIBUILDER_TAU_H +#define DISCRIBUILDER_TAU_H + +#include "GaudiKernel/ToolHandle.h" +#include "AthenaBaseComps/AthAlgorithm.h" +#include "TauDiscriminant/TauDetailsManager.h" + +#include <string> + +class TauDiscriToolBase; +class StoreGateSvc; + +class TauDiscriBuilder: public AthAlgorithm +{ + public: + //----------------------------------------------------------------- + // Contructor and destructor + //----------------------------------------------------------------- + TauDiscriBuilder( const std::string &name, ISvcLocator *pSvcLocator ); + ~TauDiscriBuilder(); + + //----------------------------------------------------------------- + // Gaudi algorithm hooks + //----------------------------------------------------------------- + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + std::string tauInputContainerName; + ToolHandleArray<TauDiscriToolBase> tools; + TauDetailsManager* manager; +}; +#endif // DISCRIBUILDER_TAU_H diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDiscriToolBase.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDiscriToolBase.h new file mode 100644 index 00000000000..6495243d2ca --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDiscriToolBase.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauDiscriToolBase.h +// package: PhysicsAnalysis/TauID/TauDiscriminant +// authors: M. Wolter, A. Kaczmarska +// date: 13 March 2008 +//----------------------------------------------------------------------------- + +#ifndef DISCRITOOLBASE_TAU_H +#define DISCRITOOLBASE_TAU_H + +#include "AthenaBaseComps/AthAlgTool.h" +#include "AthenaBaseComps/AthMessaging.h" +#include "TauDiscriminant/TauDetailsManager.h" +#include "TauDiscriminant/FakeTauBits.h" +#include "TauDiscriminant/FakeTauScores.h" + +class TauDiscriToolBase: public AthAlgTool +{ + public: + + TauDiscriToolBase( const std::string& type, + const std::string& name, + const IInterface * parent): + AthAlgTool(type, name, parent) + {} + + virtual ~TauDiscriToolBase(){} + + //----------------------------------------------------------------- + //! InterfaceID implementation needed for ToolHandle + //----------------------------------------------------------------- + static const InterfaceID& interfaceID() + { + static const InterfaceID TauDiscriToolBaseID( "TauDiscriToolBase", 1, 0 ); + return TauDiscriToolBaseID; + } + + //----------------------------------------------------------------- + //! Tool initializer + //----------------------------------------------------------------- + virtual StatusCode prepare(const TauDetailsManager&) = 0; + + //----------------------------------------------------------------- + //! Execute - called for each tau candidate + //----------------------------------------------------------------- + virtual StatusCode execute(xAOD::TauJet*, FakeTauBits*, FakeTauScores*) = 0; + + //----------------------------------------------------------------- + //! Finalizer + //----------------------------------------------------------------- + virtual StatusCode finalize() = 0; +}; + +#endif // DISCRITOOLBASE_TAU_H diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDiscriminantDict.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDiscriminantDict.h new file mode 100644 index 00000000000..e6940e3f8d8 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauDiscriminantDict.h @@ -0,0 +1,15 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/// This file is needed to create the Reflex dictionaries. +#ifndef TAUD_DICT_H +#define TAUD_DICT_H +#include "TauDiscriminant/Types.h" +#include "TauDiscriminant/TauIDReader.h" +#include "TauDiscriminant/MethodCuts.h" +#include "TauDiscriminant/MethodBDT.h" +#include "TauDiscriminant/MethodLLH.h" +#include "TauDiscriminant/MethodDummy.h" +#include "TauDiscriminant/MethodTransform.h" +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauEleBDT.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauEleBDT.h new file mode 100644 index 00000000000..b913b8929ce --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauEleBDT.h @@ -0,0 +1,88 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//! This class implements an Athena algorithm for evaluating the BDT score for tau jets. +/*! + * Tool for BDT analysis. + * + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#ifndef TAUELEBDT_H +#define TAUELEBDT_H + +#include "TauDiscriminant/TauDiscriToolBase.h" +#include "TauDiscriminant/MethodBDT.h" +#include "TauDiscriminant/MethodCuts.h" +#include "TauDiscriminant/MethodTransform.h" +#include "TauDiscriminant/TauDetailsManager.h" +#include <string> +#include <PathResolver/PathResolver.h> +#include "xAODTau/TauJet.h" +#include "TFile.h" +#include "TH2F.h" + +using namespace std; +using namespace TauID; + +class TauEleBDT: public TauDiscriToolBase +{ + public: + + //!< Constructor + TauEleBDT(const string& type, + const string& name, + const IInterface* parent): + TauDiscriToolBase(type, name, parent), + eleBDTFile(""), + eleBitsFile(""), + eleBitsRootFile(""), + cutsFile(NULL), + hloose(NULL), hmedium(NULL), htight(NULL), + eleBDT(NULL), + eleBits(NULL) + { + declareInterface<TauDiscriToolBase>(this); + + declareProperty("eleBDT", this->eleBDTFile); + declareProperty("eleBits", this->eleBitsFile); + declareProperty("eleBitsRoot", this->eleBitsRootFile); + } + + //!< Destructor + virtual ~TauEleBDT() {} + + /** + * @brief The boosted decision trees are built. + * @return @c StatusCode StatusCode::FAILURE if there were problems and StatusCode::SUCCESS otherwise. + */ + virtual StatusCode prepare(const TauDetailsManager&); + + /** + * @brief Values of the tau parameters are extracted and a boosted decision tree score is retrieved. + * @param tauJet a @c xAOD::TauJet pointer to a tau jet candidate. + * @return @c StatusCode StatusCode::FAILURE if there were problems and StatusCode::SUCCESS otherwise. + */ + virtual StatusCode execute(xAOD::TauJet*, FakeTauBits*, FakeTauScores*); + + /** + * @brief Allocated memory is freed. + * @return @c StatusCode StatusCode::FAILURE if there were problems and StatusCode::SUCCESS otherwise. + */ + virtual StatusCode finalize(); + + private: + + float eleScore; //!< Holds the current electron score which is used by a MethodCuts instance to determine if it passes loose, medium, or tight. + + string eleBDTFile; //!< The @c string name of the bdt file for electron rejection. + string eleBitsFile; //!< The @c string name of the file used to define the loose, medium, and tight cuts for electron rejection. + string eleBitsRootFile; //!< The @c string name of the ROOT file used to define the loose, medium, and tight cuts for electron rejection. + TFile *cutsFile; + TH2F *hloose, *hmedium, *htight; //!< Histograms storing eta/pt for loose/medium/tight cuts + MethodBDT* eleBDT; //!< A pointer to the @c MethodBDT used to construct and evaluate BDTs used for electron discrimination. + MethodCuts* eleBits; //!< A pointer to the @c MethodCuts used to determine whether the current electron BDT score passes loose, medium, or tight cut. +}; + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauIDReader.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauIDReader.h new file mode 100644 index 00000000000..ba41cb71dd1 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauIDReader.h @@ -0,0 +1,149 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#ifndef TAUIDREADER_H +#define TAUIDREADER_H + +#include <string> +#include <vector> +#include <map> +#include <utility> +#include <algorithm> + +#include "TTree.h" +#include "TFile.h" +#include "TauDiscriminant/MethodBase.h" +#include "TauDiscriminant/MethodBDT.h" +#include "TauDiscriminant/MethodCuts.h" +#include "TauDiscriminant/MethodLLH.h" +#include "TauDiscriminant/MethodDummy.h" +#include "TauDiscriminant/MethodTransform.h" +#include "TauDiscriminant/TauDetailsManagerStandalone.h" + + +using namespace std; + +namespace TauID +{ + class TauIDReader + { + public: + + TauIDReader(bool _verbose = false): + verbose(_verbose), + vectorMode(false), + output(0), + own_output(true) + { + m_tdms = new TauDetailsManagerStandalone(); + + + } + + ~TauIDReader() + { + vector<pair<MethodBase*, vector<vector<float>* > > >::iterator it(this->methods.begin()); + for (;it != this->methods.end(); ++it) + { + vector<vector<float>* >::iterator it2(it->second.begin()); + for (; it2 != it->second.end(); ++it2) + { + delete *it2; + } + delete it->first; + } + vector<float*>::iterator it_float(this->methodBuffer.begin()); + for(; it_float != this->methodBuffer.end(); ++it_float) + { + delete *it_float; + } + it_float = this->floatVariables.begin(); + for(; it_float != this->floatVariables.end(); ++it_float) + { + delete *it_float; + } + it_float = this->vectFloatVariables.begin(); + for(; it_float != this->vectFloatVariables.end(); ++it_float) + { + delete *it_float; + } + vector<int*>::iterator it_int(this->intVariables.begin()); + for(; it_int != this->intVariables.end(); ++it_int) + { + delete *it_int; + } + it_int = this->vectIntVariables.begin(); + for(; it_int != this->vectIntVariables.end(); ++it_int) + { + delete *it_int; + } + if (this->own_output) + { + delete this->output; + } + delete m_tdms; + } + + bool bookMethod(Types::MethodType type, const string& name, const string& filename, unsigned int numResponses = 1); + + bool addVariable(const string& name, const string& type = "F", const string& branchName=""); + + bool setOutput(const string& outputFileName, const string& outputDir = ""); + + bool setOutput(TFile* outputFile, const string& outputDir = ""); + + bool setOutput(TFile& outputFile, const string& outputDir = ""); + + TTree* classify(TTree& tree, const string& outputTreeName, bool copyTree = false); + + TTree* classify(TTree* tree, const string& outputTreeName, bool copyTree = false); + + // return the number of entries in the tree or -1 if there was a problem + int classify(const string& inputTreeName, const string& outputTreeName, + const string& inputFileName, const string& inputDir = "", + bool makeFriend = true, + bool copyTree = false); + + private: + + bool checkBranch(TTree* tree, const char* name, string type, bool checkType = true); + void print() const; + + bool verbose; + bool vectorMode; + + TFile* output; + string outputDir; + bool own_output; + + vector<string> methodNames; + vector<pair<MethodBase*, vector<vector<float>* > > > methods; + vector<float*> methodBuffer; + vector<pair<string,string> > methodVariables; + + vector<int*> intVariables; + vector<string> intNames; + vector<string> intBranches; + vector<float*> floatVariables; + vector<string> floatNames; + vector<string> floatBranches; + + vector<int*> vectIntVariables; + vector<string> vectIntNames; + vector<string> vectIntBranches; + vector<float*> vectFloatVariables; + vector<string> vectFloatNames; + vector<string> vectFloatBranches; + + vector<string> allVariableNames; + vector<string> allBranchNames; + + TauDetailsManagerStandalone *m_tdms; + }; +} +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauJetBDT.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauJetBDT.h new file mode 100644 index 00000000000..fe787ae5406 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauJetBDT.h @@ -0,0 +1,95 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//! This class implements an Athena algorithm for evaluating the BDT score for tau jets. +/*! + * Tool for BDT analysis. + * + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#ifndef TAUJETBDT_H +#define TAUJETBDT_H + +#include "TauDiscriminant/TauDiscriToolBase.h" +#include "TauDiscriminant/MethodBDT.h" +#include "TauDiscriminant/MethodCuts.h" +#include "TauDiscriminant/MethodTransform.h" +#include "TauDiscriminant/TauDetailsManager.h" +#include <string> +#include <PathResolver/PathResolver.h> +#include "xAODTau/TauJet.h" + +using namespace std; +using namespace TauID; + +class TauJetBDT: public TauDiscriToolBase +{ + public: + + //!< Constructor + TauJetBDT(const string& type, + const string& name, + const IInterface* parent): + TauDiscriToolBase(type, name, parent), + jetBDTFile(""), + jetSigBitsFile(""), + jetBkgBitsFile(""), + jetSigTransFile(""), + jetBkgTransFile(""), + jetBDT(NULL), + jetSigBits(NULL), + jetBkgBits(NULL), + jetSigTrans(NULL), + jetBkgTrans(NULL) + { + declareInterface<TauDiscriToolBase>(this); + + declareProperty("jetBDT", this->jetBDTFile); + declareProperty("jetSigBits",this->jetSigBitsFile); + declareProperty("jetBkgBits",this->jetBkgBitsFile); + declareProperty("jetSigTrans",this->jetSigTransFile); + declareProperty("jetBkgTrans",this->jetBkgTransFile); + } + + //!< Destructor + virtual ~TauJetBDT() {} + + /** + * @brief The boosted decision trees are built. + * @return @c StatusCode StatusCode::FAILURE if there were problems and StatusCode::SUCCESS otherwise. + */ + virtual StatusCode prepare(const TauDetailsManager&); + + /** + * @brief Values of the tau parameters are extracted and a boosted decision tree score is retrieved. + * @param tauJet a @c xAOD::TauJet pointer to a tau jet candidate. + * @return @c StatusCode StatusCode::FAILURE if there were problems and StatusCode::SUCCESS otherwise. + */ + virtual StatusCode execute(xAOD::TauJet*, FakeTauBits*, FakeTauScores*); + + /** + * @brief Allocated memory is freed. + * @return @c StatusCode StatusCode::FAILURE if there were problems and StatusCode::SUCCESS otherwise. + */ + virtual StatusCode finalize(); + + private: + + float jetScore; //!< Holds the current jet score which is used by a MethodCuts instance to determine if it passes loose, medium, or tight. + + string jetBDTFile; //!< The @c string name of the bdt file for jet rejection. + string jetSigBitsFile; //!< The @c string name of the file used to define the loose, medium, and tight cuts on the signal taus for jet rejection. + string jetBkgBitsFile; //!< The @c string name of the file used to define the loose, medium, and tight cuts on the background jets for jet rejection. + string jetSigTransFile; + string jetBkgTransFile; + + MethodBDT* jetBDT; //!< A pointer to the @c MethodBDT used to construct and evaluate BDTs used for jet discrimination. + MethodCuts* jetSigBits; //!< A pointer to the @c MethodCuts used to determine whether the current jet BDT score passes loose, medium, or tight signal cut. + MethodCuts* jetBkgBits; //!< A pointer to the @c MethodCuts used to determine whether the current jet BDT score passes loose, medium, or tight background cut. + MethodTransform* jetSigTrans; + MethodTransform* jetBkgTrans; +}; + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauLLH.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauLLH.h new file mode 100644 index 00000000000..9d7438ff6aa --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauLLH.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: TauLLH.h + * + * Author: Martin Flechl (mflechl@cern.ch) + */ + +#ifndef TAULLHRERUN_H +#define TAULLHRERUN_H + +#include "TauDiscriminant/TauDiscriToolBase.h" +#include "TauDiscriminant/MethodLLH.h" +#include "TauDiscriminant/TauDetailsManager.h" +#include <string> + +using namespace TauID; + +class TauLLH: public TauDiscriToolBase +{ + public: + + //----------------------------------------------------------------- + // Contructor and destructor + //----------------------------------------------------------------- + TauLLH(const string& type, + const string& name, + const IInterface* parent): + TauDiscriToolBase(type, name, parent) + { + declareInterface<TauDiscriToolBase>(this); + declareProperty( "FileNameTauPDF", m_fileNameTauPDF = "pdfs_tau.root" ); + declareProperty( "FileNameJetPDF", m_fileNameJetPDF = "pdfs_jet.root"); + declareProperty( "FileNameLMTCuts", m_fileNameLMTCuts = "LMTCutsLLH.root"); + } + + virtual ~TauLLH() {} + + //----------------------------------------------------------------- + // Gaudi algorithm hooks + //----------------------------------------------------------------- + virtual StatusCode prepare(const TauDetailsManager&); + + virtual StatusCode execute(xAOD::TauJet*, FakeTauBits*, FakeTauScores*); + + virtual StatusCode finalize(); + + private: + + std::string m_fileNameTauPDF; + std::string m_fileNameJetPDF; + std::string m_fileNameLMTCuts; + + MethodLLH* m_defllh; + MethodLLH* m_safellh; +}; + +#endif // TAULLHRERUN_H diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauMuonVeto.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauMuonVeto.h new file mode 100644 index 00000000000..26a15749170 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauMuonVeto.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUMUONVETO_H +#define TAUMUONVETO_H + +#include "TauDiscriminant/TauDiscriToolBase.h" +#include "TauDiscriminant/TauDetailsManager.h" +#include <string> + +class TauMuonVeto: public TauDiscriToolBase +{ + public: + + //----------------------------------------------------------------- + // Contructor and destructor + //----------------------------------------------------------------- + TauMuonVeto(const string& type, + const string& name, + const IInterface* parent): + TauDiscriToolBase(type, name, parent), + detailsManager(0) + { + declareInterface<TauDiscriToolBase>(this); + } + + virtual ~TauMuonVeto() {} + + //----------------------------------------------------------------- + // Gaudi algorithm hooks + //----------------------------------------------------------------- + virtual StatusCode prepare(const TauDetailsManager&); + + virtual StatusCode execute(xAOD::TauJet*, FakeTauBits*, FakeTauScores*); + + virtual StatusCode finalize(); + + private: + + const TauDetailsManager* detailsManager; +}; + +#endif // TAUMUONVETO_H diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauPi0BDT.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauPi0BDT.h new file mode 100644 index 00000000000..95f6b90b65c --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauPi0BDT.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//! This class implements an Athena algorithm for evaluating the BDT score for pi0s. +/*! + * Tool for BDT analysis. + * + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#ifndef TAUPI0BDT_H +#define TAUPI0BDT_H + +#include "TauDiscriminant/TauDiscriToolBase.h" +#include "TauDiscriminant/MethodBDT.h" +#include "TauDiscriminant/TauDetailsManager.h" +#include <string> +#include <PathResolver/PathResolver.h> +#include "xAODTau/TauJet.h" + +using namespace std; +using namespace TauID; + +class TauPi0BDT: public TauDiscriToolBase +{ + public: + + //!< Constructor + TauPi0BDT(const string& type, + const string& name, + const IInterface* parent): + TauDiscriToolBase(type, name, parent), + pi0BDTPrimaryFile(""), + pi0BDTSecondaryFile(""), + pi0BDTPrimary(NULL), + pi0BDTSecondary(NULL) + { + declareInterface<TauDiscriToolBase>(this); + + declareProperty("pi0BDTPrimary", this->pi0BDTPrimaryFile); + declareProperty("pi0BDTSecondary", this->pi0BDTSecondaryFile); + } + + //!< Destructor + virtual ~TauPi0BDT() {} + + /** + * @brief The boosted decision trees are built. + * @return @c StatusCode StatusCode::FAILURE if there were problems and StatusCode::SUCCESS otherwise. + */ + virtual StatusCode prepare(const TauDetailsManager&); + + /** + * @brief Values of the tau parameters are extracted and a boosted decision tree score is retrieved. + * @param tauJet a @c xAOD::TauJet pointer to a tau jet candidate. + * @return @c StatusCode StatusCode::FAILURE if there were problems and StatusCode::SUCCESS otherwise. + */ + virtual StatusCode execute(xAOD::TauJet*, FakeTauBits*, FakeTauScores*); + + /** + * @brief Allocated memory is freed. + * @return @c StatusCode StatusCode::FAILURE if there were problems and StatusCode::SUCCESS otherwise. + */ + virtual StatusCode finalize(); + + private: + + string pi0BDTPrimaryFile; //!< The @c string name of the bdt file for establishing the presence of pi0s + string pi0BDTSecondaryFile; //!< The @c string name of the bdt file for differentiating 2 from 1 pi0s + + MethodBDT* pi0BDTPrimary; //!< A pointer to the @c MethodBDT used to construct and evaluate BDTs used for establishing the presence of pi0s + MethodBDT* pi0BDTSecondary; //!< A pointer to the @c MethodBDT used to construct and evaluate BDTs used for differentiating 2 from 1 pi0s +}; + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauPi0Clusters.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauPi0Clusters.h new file mode 100644 index 00000000000..3922283ac60 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TauPi0Clusters.h @@ -0,0 +1,72 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*! + * file: TauPi0Clusters.h + * + * This class provides a handle on the Pi0Finder algorithm, and pass the resultin data to storegate + * + * Author: Michel Trottier-McDonald (mtm-AT-cern-dot-ch) + */ + +#ifndef TAUPI0CLUSTERS_H +#define TAUPI0CLUSTERS_H + +#include "TauDiscriminant/TauDetails.h" +#include "xAODTau/TauJet.h" +#include "TauDiscriminant/Pi0Finder.h" + +class TauPi0Clusters +{ +public: + + static const float LOW_NUMBER; + + //!< Constructor + TauPi0Clusters(const xAOD::TauJet& tauJet); + + //!< Destructor + ~TauPi0Clusters() {} + + //Getters + float get_cl1_Pt() const {return m_cl1_Pt;} + float get_cl1_Eta() const {return m_cl1_Eta;} + float get_cl1_Phi() const {return m_cl1_Phi;} + + float get_cl2_Pt() const {return m_cl2_Pt;} + float get_cl2_Eta() const {return m_cl2_Eta;} + float get_cl2_Phi() const {return m_cl2_Phi;} + + float get_tau_vis_Pt() const {return m_tau_vis_Pt;} + float get_tau_vis_Eta() const {return m_tau_vis_Eta;} + float get_tau_vis_Phi() const {return m_tau_vis_Phi;} + float get_tau_vis_M() const {return m_tau_vis_M;} + + +private: + + // Data members to return + + // Cluster 1 4-vector + float m_cl1_Pt; + float m_cl1_Eta; + float m_cl1_Phi; + + // Cluster 2 4-vector + float m_cl2_Pt; + float m_cl2_Eta; + float m_cl2_Phi; + + // Tau 4-vector from pi0s and tracks + float m_tau_vis_Pt; + float m_tau_vis_Eta; + float m_tau_vis_Phi; + float m_tau_vis_M; + + // Run Pi0Finder + void runPi0Finder(const xAOD::TauJet& tauJet); + +}; + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Transformation.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Transformation.h new file mode 100644 index 00000000000..375c5acf40c --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Transformation.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#ifndef TRANSFORMATION_H +#define TRANSFORMATION_H + +#include <iostream> +#include <string> +#include <vector> +#include <map> +#include <utility> +#include "TauDiscriminant/Node.h" +#include "TauDiscriminant/TreeVector.h" + +using namespace std; + +class Transformation : public TreeVector { + + public: + + //!< Default Constructor + Transformation() {} + + /** + * @brief Returns the @c float score for the set of variables and values in @c variableMap. + * @param variableMap + */ + float response() const; + +}; + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TreeReader.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TreeReader.h new file mode 100644 index 00000000000..16b2e4ea41d --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TreeReader.h @@ -0,0 +1,118 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#ifndef TREEREADER_H +#define TREEREADER_H + +#include <map> +#include <stack> +#include <vector> +#include <string> +#include <utility> +#include <iostream> +#include <fstream> +#include <sstream> +#include <algorithm> +#include <typeinfo> +#include "TreeVector.h" +#include "Node.h" +#include "TFile.h" +#ifndef __STANDALONE + #include "GaudiKernel/MsgStream.h" +#endif + +using namespace std; + +enum Format { + ASCII, + BINARY, + ROOTFILE +}; + +enum { + ENDOFTREE = -1, + LEAF = -2, + POINTERLEAF = -3, + GRAPH = -4, + FUNC = -5, + TRANS = -6 +}; + +class TreeReader { + + public: + + #ifdef __STANDALONE + TreeReader(bool _verbose = false): + verbose(_verbose), + floatVariables(0), + intVariables(0) + {} + #else + TreeReader(bool _verbose = false, MsgStream* _log = 0): + verbose(_verbose), + floatVariables(0), + intVariables(0), + log(_log) + {} + #endif + + ~TreeReader(){} + + void setVariables(const map<string,const float*>* _floatVariables, + const map<string,const int*>* _intVariables) + { + this->floatVariables = _floatVariables; + this->intVariables = _intVariables; + } + + Node* build(const string& filename, bool checkTree = false); + + void print(string message) const + { + #ifndef __STANDALONE + if (log) + { + (*log) << "DEBUG" << message << endreq; + } + else + #endif + cout << message << endl; + } + + private: + + Node* readTree(istream& treeFile, + TFile* rootFile, + Format format, + vector<string>& variableList, + vector<char>& variableTypeList, + unsigned int& numNodes); + bool verbose; + const map<string,const float*>* floatVariables; + const map<string,const int*>* intVariables; + #ifndef __STANDALONE + MsgStream* log; + #endif +}; + +/** This templated class is used to convert a string to various data types. +This is used when tokenizing the BDT input file to build the boosted decision trees.*/ +template <class T> +inline bool from_string(T& t, const string& s) { + istringstream ss(s); + return !(ss >> t).fail(); +} + +template <class T> +inline string to_string (const T& t) { + stringstream ss; + ss << t; + return ss.str(); +} +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TreeVector.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TreeVector.h new file mode 100644 index 00000000000..96c3141da0d --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/TreeVector.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#ifndef TREEVECTOR_H +#define TREEVECTOR_H + +#include <vector> +#include <utility> +#include "TauDiscriminant/Node.h" + +using namespace std; + +class TreeVector { + + public: + + //!< Destructor + ~TreeVector() { + vector<pair<Node*,float> >::iterator it(this->trees.begin()); + while (it != this->trees.end()) delete (*it++).first; + } + + /** + * @brief Adds a decision tree rooted at the node @c root with a weight of @c weight. + * @param root a @c Node* pointer to the root node. + * @param weight the @c float weight of the decision tree. + */ + void addTree(Node* root, float weight) { + this->trees.push_back(pair<Node*,float>(root,weight)); + } + + protected: + + vector<pair<Node*,float> > trees; +}; + +#endif diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Types.h b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Types.h new file mode 100644 index 00000000000..65f7b80751e --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/Types.h @@ -0,0 +1,24 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AUTHOR: Noel Dawe +#ifndef TYPES_H +#define TYPES_H + +namespace TauID +{ + namespace Types + { + enum MethodType + { + DUMMY, + CUTS, + BDT, + LLH, + TRANSFORM + }; + } +} + +#endif // TYPES_H diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/selection.xml b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/selection.xml new file mode 100644 index 00000000000..adc974cf6e6 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/TauDiscriminant/selection.xml @@ -0,0 +1,10 @@ +<lcgdict> + <enum pattern="TauID::Types::*"/> + <variable pattern="TauID::Types::*"/> + <class name="TauID::TauIDReader"/> + <class name="TauID::MethodCuts"/> + <class name="TauID::MethodBDT"/> + <class name="TauID::MethodLLH"/> + <class name="TauID::MethodDummy"/> + <class name="TauID::MethodTransform"/> +</lcgdict> diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/cmt/Makefile.RootCore b/PhysicsAnalysis/TauID/TauDiscriminant/cmt/Makefile.RootCore new file mode 100644 index 00000000000..90fc95518ed --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/cmt/Makefile.RootCore @@ -0,0 +1,5 @@ +PACKAGE = TauDiscriminant +PACKAGE_PRELOAD = Tree Hist Matrix +PACKAGE_CXXFLAGS = -D__STANDALONE + +include $(ROOTCOREDIR)/Makefile-common diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/cmt/Makefile.Standalone b/PhysicsAnalysis/TauID/TauDiscriminant/cmt/Makefile.Standalone new file mode 100644 index 00000000000..07edc9e2b58 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/cmt/Makefile.Standalone @@ -0,0 +1,108 @@ +# Author: Noel Dawe (Noel.Dawe@cern.ch) +# TauDiscriminant standalone makefile + +# --- External configuration ---------------------------------- +ifeq ($(wildcard $(ROOTSYS)/test/Makefile.arch),) + include $(ROOTSYS)/etc/Makefile.arch +else + include $(ROOTSYS)/test/Makefile.arch +endif + +# ------------------------------------------------------------- +# General flags +# ------------------------------------------------------------- +PACKAGE = TauDiscriminant +OUTPUTDIR = ../StandAlone +SRCDIR = ../Root +HDIR = ../$(PACKAGE) + +# Get these from Makefile.arch above +#CC = g++ +#CCFLAGS = -g -m32 -fPIC -Wall -W -Woverloaded-virtual -Wno-parentheses -Wno-unused-parameter -Wno-unused-variable +#LDFLAGS = -g -m32 -fPIC + +MFLAGS = -MM -Wall -W -Woverloaded-virtual +INCLUDES += -I${ROOTSYS}/include -I.. -I$(HDIR) -I$(SRCDIR) +CPPFLAGS += -D__STANDALONE + +# Need these to avoid loading dependent libraries when ROOT starts +LINKLIBS = -L${ROOTSYS}/lib -lHist -lMatrix + +# ------------------------------------------------------------- +# ROOT Cint +# ------------------------------------------------------------- +CINT = taudiscriminantcint +LDEFFILE = $(SRCDIR)/LinkDef.h +CINTFILE = $(HDIR)/TauDiscriminantCint.cxx +CINTFILEH = $(HDIR)/TauDiscriminantCint.h +CINTOBJ = $(HDIR)/TauDiscriminantCint.o + +SRC = Types.cxx TauIDReader.cxx TauDetailsManagerStandalone.cxx MethodBase.cxx MethodDummy.cxx MethodTransform.cxx MethodBDT.cxx MethodCuts.cxx MethodLLH.cxx TreeVector.cxx Node.cxx TreeReader.cxx BoostedDecisionTree.cxx CommonLikelihood.cxx CutsDecisionTree.cxx Transformation.cxx +SOURCES = $(addprefix $(SRCDIR)/,$(SRC)) $(CINTFILE) +HDR = $(patsubst %.cxx,%.h,$(SRC)) +HEADERS = $(addprefix $(HDIR)/,$(HDR)) +OBJECTS = $(patsubst %.cxx,%.o,$(SOURCES)) +DEPS = $(patsubst %.h,%.d,$(HEADERS)) + +DICTS = $(HDIR)/$(PACKAGE)Dict.h +SELECTION = $(HDIR)/selection.xml + +# ------------------------------------------------------------- +# Libraries +# ------------------------------------------------------------- +SHLIBFILE = $(OUTPUTDIR)/lib$(PACKAGE).so + +ifeq ($(PLATFORM),macosx) +EXTRALDFLAGS = -install_name @rpath/$(SHLIBFILE) +endif + +# get libraries of ROOT +define ldlinksuffixROOT + $(addsuffix $(LDLINKSUFFIX),$(Lib)) $(shell if [ "$(findstring -Ldlink2,$(OPTIONS))" ]; then echo $(addsuffix _pkgid_$(ROOTVER),$(Lib)); fi) +endef + +# ------------------------------------------------------------- +# Compilation +# ------------------------------------------------------------- + +default: shlib + +# Implicit rule making all dependency Makefiles included at the end of this makefile +%.d: %.cxx $(HEADERS) + @echo "Making $@" + @set -e; $(CC) $(MFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) $< \ + | awk '{ sub("^$(notdir $*).o:","$*.o $@:") ; print }' > $@ ;\ + [ -s $@ ] || rm -f $@ + +# Implicit rule to compile all classes +%.o : %.cxx + @echo "Compiling $<" + @$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $< -o $*.o + +# Rule to make ROOTCINT output file +$(CINTOBJ) : $(HEADERS) $(LDEFFILE) + @echo "Running rootcint" + @$(ROOTSYS)/bin/rootcint -f $(CINTFILE) -c -p $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) $(HEADERS) $(LDEFFILE) + @echo "Compiling $(CINTFILE)" + @$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(CINTFILE) -o $@ + +rootcint : $(HEADERS) $(LDEFFILE) + @echo "Running rootcint" + $(ROOTSYS)/bin/rootcint -f $(CINTFILE) -c -p $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) $(HEADERS) $(LDEFFILE) + +# Rule to combine objects into a shared library +$(SHLIBFILE): $(OBJECTS) + @echo "Linking $(SHLIBFILE)" + @mkdir -p $(OUTPUTDIR) + @rm -f $(SHLIBFILE) + @$(LD) $(CXXFLAGS) $(SOFLAGS) $(LINKLIBS) $(EXTRALDFLAGS) $(OBJECTS) -o $(SHLIBFILE) + @rm -f $(OUTPUTDIR)/$(PACKAGE)Lib.so + @ln -s $(SHLIBFILE) $(OUTPUTDIR)/$(PACKAGE)Lib.so + +-include $(DEPS) + +taudiscriminantcint: $(CINTOBJ) +shlib: $(SHLIBFILE) + +clean: + @rm -f ../*/*.o ../*/*.d diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/cmt/requirements b/PhysicsAnalysis/TauID/TauDiscriminant/cmt/requirements new file mode 100644 index 00000000000..fd32c2464cc --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/cmt/requirements @@ -0,0 +1,54 @@ +package TauDiscriminant +author Marcin Wolter, Noel Dawe + +use AtlasPolicy AtlasPolicy-* +use GaudiInterface GaudiInterface-* External +use xAODTau xAODTau-* Event/xAOD +use SGTools SGTools-* Control +use DataModel DataModel-* Control +use AthenaKernel AthenaKernel-* Control +use PathResolver PathResolver-* Tools +use StoreGate StoreGate-* Control +use AtlasROOT AtlasROOT-* External +use AthenaBaseComps AthenaBaseComps-* Control +apply_tag ROOTBasicLibs +apply_tag ROOTMathLibs + +macro_append TauDiscriminant_shlibflags "-L$(ROOTSYS)/lib -lCore -lCint -lHist -lGraf -lGraf3d -lGpad -lTree -lRint -lPostscript -lMatrix -lPhysics -lm -ldl -lpthread -rdynamic" + +# suggested by RootCore +#library TauDiscriminantLib "../Root/*.cxx" +#apply_pattern named_installed_library library=TauDiscriminantLib + +apply_pattern dual_use_library files="../Root/*.cxx ../src/*.cxx" + +apply_pattern declare_joboptions files="../share/*.py" + +apply_pattern declare_runtime files="../share/*.root ../share/*.dat ../share/*.txt ../share/*.bin" + +apply_pattern declare_python_modules files="../python/*.py" + +# debug +# private +# macro cppdebugflags '$(cppdebugflags_s)' +# macro_remove componentshr_linkopts "-Wl,-s" + +private +use AtlasCLHEP AtlasCLHEP-* External +use AnalysisUtils AnalysisUtils-* PhysicsAnalysis/AnalysisCommon +#use CaloEvent CaloEvent-* Calorimeter +use FourMomUtils FourMomUtils-* Event +#use Particle Particle-* Reconstruction +use TrkEventPrimitives TrkEventPrimitives-* Tracking/TrkEvent +#use TrkTrackSummary TrkTrackSummary-* Tracking/TrkEvent +use xAODTracking xAODTracking-* Event/xAOD +#use VxVertex VxVertex-* Tracking/TrkEvent +use AtlasReflex AtlasReflex-* External -no_auto_imports +use CaloUtils CaloUtils-* Calorimeter +use xAODCaloEvent xAODCaloEvent-* Event/xAOD +use CaloGeoHelpers CaloGeoHelpers-* Calorimeter + +apply_pattern lcgdict dict=TauDiscriminant selectionfile=selection.xml headerfiles="../TauDiscriminant/TauDiscriminantDict.h" + +macro_append ROOT_linkopts " -lPyROOT" +end_private diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/python/TauDiscriGetter.py b/PhysicsAnalysis/TauID/TauDiscriminant/python/TauDiscriGetter.py new file mode 100644 index 00000000000..0af84056499 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/python/TauDiscriGetter.py @@ -0,0 +1,168 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +# AUTHOR: Marcin.Wolter@cern.ch +# CREATED: 20 March 2008 +# +# 23 Nov 2010: cleaning up (Noel Dawe) + +from AthenaCommon.Logging import logging +from AthenaCommon.AlgSequence import AlgSequence +#from AthenaCommon.AppMgr import ToolSvc + +from RecExConfig.Configured import Configured +import traceback + +def singleton(cls): + + log = logging.getLogger('%s::__init__'% cls.__name__) + instances = {} + def getinstance(*args, **kwargs): + if cls in instances: + log.warning("Attempting to construct more than one %s. Returning the singleton."% cls.__name__) + return instances[cls] + obj = cls(*args, **kwargs) + instances[cls] = obj + return obj + return getinstance + +# to disable singleton behaviour comment out the following line: +@singleton +class TauDiscriGetter(Configured): + + def __init__(self, name = "TauDiscriminant", + container = "TauRecContainer", + sequence = None, + do_upstream_algs = False, + do_only_fakebits = False, + do_Pi0 = True, # Temporary, turns on the dumping of pi0 scores + msglevel = 3): + + self.sequence = sequence + if sequence is None: + self.sequence = AlgSequence() + self.name = name + self.container = container + self.upstream_algs = do_upstream_algs + self.only_fakebits = do_only_fakebits # temporary hack + self.do_Pi0 = do_Pi0 # Temporary, turns on the dumping of pi0 scores + self.msglevel = msglevel + Configured.__init__(self) + + def configure(self): + + from AthenaCommon.AppMgr import ToolSvc + + mlog = logging.getLogger('TauDiscriGetter::configure:') + + try: + from TauDiscriminant.TauDiscriminantConf import TauDiscriBuilder + TauDiscriBuilder.OutputLevel = self.msglevel + tauDiscriBuilder = TauDiscriBuilder( + self.name, + container = self.container) + except Exception: + mlog.error("could not find TauDiscriBuilder") + print traceback.format_exc() + return False + + tools = [] + + if not self.only_fakebits: + """ + Cut-based tau-jet identification + """ +# try: +# from TauDiscriminant.TauDiscriminantConf import TauCuts +# TauCuts.OutputLevel = self.msglevel +# tauCuts = TauCuts(cuts = "cuts.txt") +# tools.append(tauCuts) +# except Exception: +# mlog.error("could not find TauCuts in TauDiscriminant") +# print traceback.format_exc() +# return False + """ + Cut-based electron veto + """ + try: + from TauDiscriminant.TauDiscriminantConf import TauCutsEleVeto + TauCutsEleVeto.OutputLevel = self.msglevel + tauCutsEleVeto = TauCutsEleVeto() + tools.append(tauCutsEleVeto) + except Exception: + mlog.error("could not find TauCutsEleVeto in TauDiscriminant") + print traceback.format_exc() + return False + """ + Muon veto + """ + try: + from TauDiscriminant.TauDiscriminantConf import TauMuonVeto + TauMuonVeto.OutputLevel = self.msglevel + tauMuonVeto = TauMuonVeto() + tools.append(tauMuonVeto) + except Exception: + mlog.error("could not find TauMuonVeto in TauDiscriminant") + print traceback.format_exc() + return False + + + try: + from TauDiscriminant.TauDiscriminantConf import TauPi0BDT + TauPi0BDT.OutputLevel = self.msglevel + taupi0BDT = TauPi0BDT(pi0BDTPrimary="pi0Primary.BDT.bin", + pi0BDTSecondary="pi0Secondary.BDT.bin") + tools.append(taupi0BDT) + except Exception: + mlog.error("could not find TauPi0BDT in TauDiscriminant") + print traceback.format_exc() + return False + + + + """ + Likelihood tau-jet identification + """ + try: + from TauDiscriminant.TauDiscriminantConf import TauLLH + TauLLH.OutputLevel = self.msglevel + tauLLH = TauLLH() + tools.append(tauLLH) + except Exception: + mlog.error("could not find TauLLH in TauDiscriminant") + print traceback.format_exc() + return False + """ + BDT tau-jet identification + """ + try: + from TauDiscriminant.TauDiscriminantConf import TauJetBDT + TauJetBDT.OutputLevel = self.msglevel + taujetBDT = TauJetBDT(jetBDT="jet.BDT.bin", + jetSigTrans="sig.trans.jet.BDT.root", + jetBkgTrans="", + jetSigBits="sig.bits.jet.BDT.txt", + jetBkgBits="bkg.bits.jet.BDT.txt") + tools.append(taujetBDT) + except Exception: + mlog.error("could not find TauJetBDT in TauDiscriminant") + print traceback.format_exc() + return False + """ + BDT electron veto + """ + try: + from TauDiscriminant.TauDiscriminantConf import TauEleBDT + TauEleBDT.OutputLevel = self.msglevel + taueleBDT = TauEleBDT(eleBDT="ele.BDT.bin", + eleBits="", eleBitsRoot="cuts.eBDT.root") + tools.append(taueleBDT) + except Exception: + mlog.error("could not find TauEleBDT in TauDiscriminant") + print traceback.format_exc() + return False + + + tauDiscriBuilder.tools = tools + + self.sequence += tauDiscriBuilder + return True diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/run/TauEnergyCalibration_jobOption.py b/PhysicsAnalysis/TauID/TauDiscriminant/run/TauEnergyCalibration_jobOption.py new file mode 100644 index 00000000000..ed4a1ba652e --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/run/TauEnergyCalibration_jobOption.py @@ -0,0 +1,39 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +f = open('input.txt', 'r') +inputFiles = f.readlines() +f.close() +inputFiles = [item.strip() for item in inputFiles] + +from AthenaCommon.AthenaCommonFlags import jobproperties as jp +jp.AthenaCommonFlags.FilesInput = inputFiles + +include('AthenaPython/read_file.py') + +from AthenaCommon.AppMgr import theApp, ServiceMgr +from AthenaCommon.AlgSequence import AlgSequence +job = AlgSequence() + +import AthenaPoolCnvSvc.ReadAthenaPool +theApp.EvtMax = -1 + +if True: # run only TauEnergyCalibration + from TauDiscriminant.TauDiscriminantConf import TauEnergyCalibration + TauEnergyCalibration.OutputLevel = DEBUG + tauEnergyCalibration = TauEnergyCalibration('TauEnergyCalibration') + tauEnergyCalibration.tauContainerKey = 'TauRecContainer' + tauEnergyCalibration.calibrationFile = 'EnergyCalibration.root' + tauEnergyCalibration.vertexContainerKey = 'VxPrimaryCandidate' + job += tauEnergyCalibration +else: + from TauDiscriminant.TauDiscriGetter import TauDiscriGetter + TauDiscriGetter(do_upstream_algs = True, msglevel = DEBUG) + + + + + + + + + diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/run/TauIDAnalysisExample.C b/PhysicsAnalysis/TauID/TauDiscriminant/run/TauIDAnalysisExample.C new file mode 100644 index 00000000000..a9bdb038148 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/run/TauIDAnalysisExample.C @@ -0,0 +1,68 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <string> +#include "TFile.h" +#include "TTree.h" + +using namespace std; + +void TauIDAnalysisExample(string filename) +{ + if (gSystem->Load("libTauDiscriminant.so") != 0) + { + cout << "Could not load libTauDiscriminant.so" << endl; + } + using namespace TauID; + + TFile* file = TFile::Open(filename.c_str()); + if (!file) + { + cout << "Could not open " << filename << endl; + return; + } + TTree* tree = (TTree*)file->Get("tauPerf"); + if (!tree) + { + cout << "Could not find tree named tauPerf" << endl; + return; + } + MethodBDT* bdt = new MethodBDT("MyBDT"); + float et; + int numTrack; + float emRadius; + float centFrac; + float trkAvgDist; + float etOverPtLeadTrk; + float emFractionAtEMScale; + float massTrkSys; + float topoInvMass; + float trFlightPathSig; + int numVertices; + + bdt->addVariable("numTrack",&numTrack,"I"); + bdt->addVariable("emRadius",&emRadius,"F"); + bdt->addVariable("centFrac",¢Frac,"F"); + bdt->addVariable("trkAvgDist",&trkAvgDist,"F"); + bdt->addVariable("etOverPtLeadTrk",&etOverPtLeadTrk,"F"); + bdt->addVariable("emFractionAtEMScale",&emFractionAtEMScale,"F"); + bdt->addVariable("massTrkSys",&massTrkSys,"F"); + bdt->addVariable("topoInvMass",&topoInvMass,"F"); + bdt->addVariable("trFlightPathSig",&trFlightPathSig,"F"); + bdt->addVariable("numVertices",&numVertices,"I"); + if (!bdt->build("../share/jet.BDT.bin")) + { + cout "Could not build BDT" << endl; + return; + } + + for(unsigned int ievent(0); ievent < tree->GetEntries(); ++ievent) + { + tree->GetEntry(ievent); + for (unsigned int itau(0); itau < (*tree)["tau_n"]; ++itau) + { + et = (*tree)["tau_Et"][itau]; + } + } +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/run/TauIDAnalysisExample.py b/PhysicsAnalysis/TauID/TauDiscriminant/run/TauIDAnalysisExample.py new file mode 100644 index 00000000000..975bedcd814 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/run/TauIDAnalysisExample.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +################################################################################ +# +# A simple script demonstrating how to use MethodBDT, MethodCuts, etc. in python +# +################################################################################ + +import sys +import ROOT +ROOT.gSystem.Load("libTauDiscriminant.so") +from ROOT import TauID +from array import array +from itertools import izip +import math + +ROOT.gInterpreter.GenerateDictionary("vector<vector<float> >", "vector") +ROOT.gInterpreter.GenerateDictionary("vector<vector<int> >", "vector") + +dphi = lambda phi1, phi2 : abs(math.fmod((math.fmod(phi1, 2*math.pi) - math.fmod(phi2, 2*math.pi)) + 3*math.pi, 2*math.pi) - math.pi) + +dR = lambda eta1, phi1, eta2, phi2: math.sqrt((eta1 - eta2)**2 + dphi(phi1, phi2)**2) + +filename = sys.argv[1] + +file = ROOT.TFile.Open(filename) +tree = file.Get("tauPerf") + +bdt = TauID.MethodBDT() +bdtbits = TauID.MethodCuts() +cuts = TauID.MethodCuts() + +variables = { + "numTrack" : array('i',[0]), + "num_pileup_and_primary_vertices" : array('i',[0]), + "centFrac" : array('f',[0]), + "etOverpTLeadTrk" : array('f',[0]), + "trkAvgDist" : array('f',[0]), + "effTopoInvMass" : array('f',[0]), + "ipSigLeadTrk" : array('f',[0]), + "lead3ClusterEOverAllClusterE" : array('f',[0]), + "numWideTrack" : array('i',[0]), + "calRadius" : array('f',[0]), + "drMax" : array('f',[0]), + "massTrkSys" : array('f',[0]), + "trFlightPathSig" : array('f',[0]), + "pt" : array('f',[0]), + "BDT" : array('f',[0]), + "CALO_ISO_CORRECTED" : array('f',[0]) +} + +for var, value in variables.items(): + bdt.addVariable(var.upper(), value, value.typecode.upper()) + bdtbits.addVariable(var.upper(), value, value.typecode.upper()) + cuts.addVariable(var.upper(), value, value.typecode.upper()) + +if not bdt.build("../share/jet.BDT.bin"): + sys.exit(1) + +if not bdtbits.build("../share/sig.bits.jet.BDT.txt"): + sys.exit(1) + +if not cuts.build("../share/cuts.txt"): + sys.exit(1) + +for entry in xrange(tree.GetEntries()): + tree.GetEntry(entry) + # update event variables + nvtx = len(filter(lambda v: (tree.vxp_type[v]==1 and tree.vxp_nTracks[v]>=4) or \ + (tree.vxp_type[v]==3 and tree.vxp_nTracks[v]>=2), range(tree.vxp_n))) + variables["num_pileup_and_primary_vertices"][0] = nvtx + + for itau in xrange(tree.tau_n): + # update tau variables + variables["numTrack"][0] = tree.tau_seedCalo_numTrack[itau] + variables["centFrac"][0] = tree.tau_seedCalo_centFrac[itau] + variables["etOverpTLeadTrk"][0] = tree.tau_etOverPtLeadTrk[itau] + variables["trkAvgDist"][0] = tree.tau_seedCalo_trkAvgDist[itau] + variables["effTopoInvMass"][0] = tree.tau_effTopoInvMass[itau] + variables["ipSigLeadTrk"][0] = tree.tau_ipSigLeadTrk[itau] + variables["numWideTrack"][0] = tree.tau_seedCalo_wideTrk_n[itau] + variables["calRadius"][0] = tree.tau_calcVars_calRadius[itau] + variables["drMax"][0] = tree.tau_calcVars_drMax[itau] + variables["massTrkSys"][0] = tree.tau_massTrkSys[itau] + variables["trFlightPathSig"][0] = tree.tau_trFlightPathSig[itau] + variables["pt"][0] = tree.tau_pt[itau] + + # calculate lead3ClusterEOverAllClusterE + clusterE = sorted(tree.tau_cluster_E[itau], reverse=True) + totE = sum(clusterE) + variables["lead3ClusterEOverAllClusterE"][0] = sum(clusterE[:3]) / totE if totE > 0 else -1111. + + # calculate CALO_ISO_CORRECTED + jvf = tree.tau_jet_jvtxf[itau] + sumPtTrk = tree.tau_jet_sumPtTrk[itau] + pt_pileup = (1. - jvf) * sumPtTrk + calo_iso = 0. + for E, eta, phi in izip(tree.tau_cluster_E[itau], tree.tau_cluster_eta[itau], tree.tau_cluster_phi[itau]): + if .2 <= dR(tree.tau_seedCalo_eta[itau], tree.tau_seedCalo_phi[itau], eta, phi) < .4: + calo_iso += E / math.cosh(eta) + max_pileup_correction = 4000. + alpha = 1. + pileup_correction = alpha * pt_pileup + if pileup_correction > max_pileup_correction: + pileup_correction = max_pileup_correction + calo_iso_corrected = calo_iso - pileup_correction + variables["CALO_ISO_CORRECTED"][0] = calo_iso_corrected + + bdtScore = bdt.response() + variables["BDT"][0] = bdtScore + + print "BDT Score: %.3f"% bdtScore + print "BDT Loose: %i"% bdtbits.response(0) + print "BDT Medium: %i"% bdtbits.response(1) + print "BDT Tight: %i"% bdtbits.response(2) + print "Cuts Loose: %i"% cuts.response(0) + print "Cuts Medium: %i"% cuts.response(1) + print "Cuts Tight: %i"% cuts.response(2) + print "-"*30 diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/run/jobOptions.py b/PhysicsAnalysis/TauID/TauDiscriminant/run/jobOptions.py new file mode 100644 index 00000000000..ffcac520e00 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/run/jobOptions.py @@ -0,0 +1,33 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +""" +These minimal job options are for testing only!!! +""" + +import AthenaPoolCnvSvc.ReadAthenaPool +#ServiceMgr.EventSelector.InputCollections = ['/tmp/simonyan/mc11_7TeV.106052.PythiaZtautau.merge.AOD.e825_s1324_s1300_r2731_r2700_tid518036_00/AOD.518036._000301.pool.root.1'] +ServiceMgr.EventSelector.InputCollections = ['inputAODFile=/afs/cern.ch/work/p/pmalecki/mc12_8TeV.147818.Pythia8_AU2CTEQ6L1_Ztautau.merge.AOD.e1176_s1479_s1470_r3553_r3549_tid779134_00/AOD.779134._000258.pool.root.1'] + + + +from RecExConfig.RecFlags import rec + +rec.readRDO=False +rec.readESD=False # set true for ESD reading +rec.readAOD=True # set false for ESD reading +rec.doWriteAOD=False +rec.doWriteESD=False +rec.doWriteTAG=False +rec.doCBNT=False +rec.doHist=False +rec.doTruth=False +rec.AutoConfiguration=['everything'] +#rec.doFloatingPointException=True + +include ("RecExCommon/RecExCommon_topOptions.py") + +from AthenaCommon.AppMgr import theApp +from TauDiscriminant.TauDiscriGetter import TauDiscriGetter +TauDiscriGetter(msglevel = VERBOSE) + +theApp.EvtMax = 500 diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/run/minJobOptions.py b/PhysicsAnalysis/TauID/TauDiscriminant/run/minJobOptions.py new file mode 100644 index 00000000000..703ed0be5a8 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/run/minJobOptions.py @@ -0,0 +1,24 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +""" +These minimal job options are for testing only!!! +""" +import AthenaPoolCnvSvc.ReadAthenaPool + +# lxplus +ServiceMgr.EventSelector.InputCollections = \ + ['/scratchdisk2/end/data/valid1.105200.T1_McAtNlo_Jimmy.recon.AOD.e603_s932_r1588_tid172295_00/AOD.172295._000154.pool.root.1'] + +# SFU T3 +#ServiceMgr.EventSelector.InputCollections = \ +# ['/cluster/data03/endw/ntuples/AOD/valid1.105200.T1_McAtNlo_Jimmy.recon.AOD.e603_s932_r1588_tid172295_00/AOD.172295._000001.pool.root.1'] + +from AthenaCommon.AppMgr import theApp +from TauDiscriminant.TauDiscriGetter import TauDiscriGetter + +#TauDiscriGetter(do_upstream_algs = True, msglevel = VERBOSE) +#TauDiscriGetter(do_upstream_algs = False, do_only_fakebits = True, msglevel = VERBOSE) + +TauDiscriGetter(msglevel=VERBOSE, do_Pi0=True) + +theApp.EvtMax = 10 diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/run/tauIDReader_LLH.py b/PhysicsAnalysis/TauID/TauDiscriminant/run/tauIDReader_LLH.py new file mode 100755 index 00000000000..f66260ee9c7 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/run/tauIDReader_LLH.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +#File tauLikelihood_rerunOnDPD.py +#by Martin.Flechl@cern.ch, Marcin.Wolter@cern.ch +#based on Noel's example +# +#usage: tauIDReader_LLH.py D3PD_file_name.root +import PyCintex +import ROOT +import os +import sys + +#ifile="DPD.root" +ifile=sys.argv[1]; +ofile="FOR_DPD.root" + +inputType=0 #0 TauDPD, 1 small TauDPD, 2 Dugan's tiny D4PD + + +if (inputType==0): + m_treename="tauPerf" + m_vartypeF="VF" + m_vartypeI="VI" + m_authortype="VI" +if (inputType==1): + m_treename="tauPerfSmall" + m_vartypeF="VF" + m_vartypeI="VI" + m_authortype="VI" +if (inputType==2): + m_treename="D4PD" + m_vartypeF="F" + m_vartypeI="I" + m_authortype="F" + +print "Setting up..." +output = ROOT.TFile.Open(ofile,"recreate") +### mw app = ROOT.TauID.TauIDReader(output,True) +app = ROOT.TauID.TauIDReader(True) +app.setOutput(output,"") + +#Commented out variables are not needed when running the safeLLH +#Comment in to rerun the full LLH +variables = [ + ("author","tau_author",m_authortype), + ("eta","tau_eta",m_vartypeF), + ("numTrack","tau_numTrack",m_vartypeI), + ("et","tau_Et",m_vartypeF), + ("nPi0","tau_nPi0",m_vartypeI), + ("NUM_PILEUP_AND_PRIMARY_VERTICES","evt_calcVars_numGoodVertices","I"), # number of good vertices + ("vxp_n","vxp_n","I"), # not quite correct, these are all vertices + ("vxp_nTracks","vxp_nTracks","VI"), +# ("emRadius","tau_seedCalo_EMRadius",m_vartypeF), #0 +# ("isolFrac","tau_seedCalo_isolFrac",m_vartypeF), #1 +# ("stripWidth2","tau_seedCalo_stripWidth2",m_vartypeF), #2 +# ("nStrip","tau_seedCalo_nStrip",m_vartypeI), #3 +# ("etHad2etTracks","tau_calcVars_etHadSumPtTracks",m_vartypeF), #4 +# ("etEM2etTracks","tau_calcVars_etEMSumPtTracks",m_vartypeF), #5 +# ("etTracks2et","tau_calcVars_sumTrkPt",m_vartypeF), #6, code divides the quantity by et!! +# ("emFractionCalib","tau_calcVars_emFracCalib",m_vartypeF), #7 +# ("emFractionAtEMScale","tau_calcVars_emFracCalib",m_vartypeF), #7 not quite correct, but not in current D3PD +# ("etOverPtLeadTrk","tau_etOverPtLeadTrk",m_vartypeF), #8 +# ("dRmin","tau_calcVars_drMin",m_vartypeF), #9 + ("dRmax","tau_calcVars_drMax",m_vartypeF), #10 +# ("trkWidth2","tau_trkWidth2",m_vartypeF), #11 + ("massTrkSys","tau_massTrkSys",m_vartypeF), #12 +# ("nIsolTrk","tau_seedTrk_nIsolTrk",m_vartypeI), #13 +# ("MVisEflow","tau_m",m_vartypeF), #14 +# ("ipZ0sinThetaSigLeadTrk","tau_ipZ0SinThetaSigLeadTrk",m_vartypeF), #15 +# ("ipSigLeadLooseTrk","tau_ipSigLeadLooseTrk",m_vartypeF), #16 + ("trFlightPathSig","tau_trFlightPathSig",m_vartypeF), #17 + ("centFrac","tau_seedCalo_centFrac",m_vartypeF), #18 +# ("numEffClus","tau_calcVars_numEffTopoClusters",m_vartypeF), #19 + ("trkAvgDist","tau_seedCalo_trkAvgDist",m_vartypeF), #20 +# ("topoInvMass","tau_topoInvMass",m_vartypeF), #21 + ("calRadius","tau_calcVars_calRadius",m_vartypeF), #22 + + ("lead2ClusterEOverAllClusterE","tau_calcVars_lead2ClusterEOverAllClusterE",m_vartypeF), #27 + ("numWideTrack","tau_seedCalo_wideTrk_n",m_vartypeI), #50 missing + + + ] + +for varName,branchName,type in variables: + app.addVariable(varName,branchName,type) + +# "CUTS" or "BDT", name of cuts/BDT file, number of responses +# (i.e. 3 for cuts (loose, medium, tight), 1 for BDT) +print "Finding PDF files" +filePDFtau = "pdfs_tau.root" +filePDFjet = "pdfs_jet.root" +fileLMTCuts = "LMTCutsLLH.root" +dataPathList = os.environ['DATAPATH'].split(os.pathsep) +dataPathList.insert(0, os.curdir) +from AthenaCommon.Utils.unixtools import FindFile +fileNameTau = FindFile(filePDFtau, dataPathList, os.R_OK ) +fileNameJet = FindFile(filePDFjet, dataPathList, os.R_OK ) +fileNameLMTCuts = FindFile(fileLMTCuts, dataPathList, os.R_OK ) +if (not fileNameTau): + print "Input PDF not found" +print "Tau PDF file name: ", fileNameTau +print "Jet PDF file name: ", fileNameJet +fileNames=fileNameTau+","+fileNameJet+","+fileNameLMTCuts +#print "String: ", fileNames + +print "Booking Method: LLH" +### mw app.bookMethod("LLH","llhsafe",fileNames,4) +app.bookMethod(ROOT.TauID.Types.LLH,"llhsafe",fileNames,4) +#app.bookMethod("LLH","llhdef",fileNames,4) +#app.bookMethod("LLH","llhall",fileNames,4) + +print "Opening input file" +input = ROOT.TFile.Open(ifile) +tree = input.Get(m_treename) + +print "Obtaining Discriminant ",tree,m_treename," ",ifile +# mw llhTree = app.classify(tree,"taullh","") +llhTree = app.classify(tree,"taullh",True) + +llhTree.AddFriend(m_treename,ifile) +output.cd() + +print "Writing output",output.GetName() +llhTree.Write() + +output.Close() diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/run/tauid-redo b/PhysicsAnalysis/TauID/TauDiscriminant/run/tauid-redo new file mode 100755 index 00000000000..f48f88d86ae --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/run/tauid-redo @@ -0,0 +1,236 @@ +#!/usr/bin/env python + +from optparse import OptionParser + +parser = OptionParser(usage="%prog [options] file1.root file2.root ...") +parser.add_option("-t","--tree", action="store", type="str", dest="treename", + default="tau", help="name of tree in D3PD") +parser.add_option("-m","--methods", action="store", type="str", dest="methods", + default="BDT,BDTE,PI0P,PI0S,LLH", help="list of methods to run separated by commas") +parser.add_option("-d","--derived-methods", action="store", type="str", dest="extramethods", + default="BBDTCUTS,SBDTCUTS", help="list of derived methods to run separated by commas, set to NONE if you wish to skip these") +parser.add_option("--clone", action="store_true", dest="clonetree", + default=False, help="copy all branches from each input tree into each output tree") +parser.add_option("--friend", action="store_true", dest="friendtree", + default=False, help="make each input tree a friend of each output tree") +parser.add_option("--idir", action="store", type="str", dest="inputdir", + default="", help="the directory in which the input tree is located in each ROOT file") +parser.add_option("--odir", action="store", type="str", dest="outputdir", + default="", help="the directory in which to write the output tree in each output ROOT file") +parser.add_option("--flat", action="store_true", dest="flat", + default=False, help="the ntuples are flat (D4PD)") +parser.add_option("-v","--verbose", action="store_true", dest="verbose", + default=False, help="show verbose output") +options, args = parser.parse_args() + +import sys + +if not args: + print "specify at least one input ROOT file" + sys.exit(1) + +try: + import ROOT +except: + sys.exit("Could not import ROOT module. Is PyROOT installed?") + +try: + import PyCintex + from ROOT import TauID +except: + try: + ROOT.gSystem.Load("libTauDiscriminant.so") + from ROOT import TauID + except: + print "Could not import TauID module" + print "Be sure to do one of the following:" + print ' 1) Setup Athena, compile TauDiscriminant with "make", and source setup.sh' + print ' 2) Compile standalone TauDiscriminant with "make -f Makefile.Standalone", and source setup.sh' + sys.exit(1) + +import os +import time + +def find_file(filename, search_path_var='PATH', include_working=True): + """ + find filename in PATH with the option of including + the current working directory in the search + """ + if not os.environ.has_key(search_path_var): + sys.exit("Environment variable $%s is not defined"% search_path_var) + search_path = os.environ[search_path_var] + paths = search_path.split(os.pathsep) + if include_working: + paths = ['.'] + paths + for path in paths: + fullpath = os.path.join(path, filename) + if os.path.exists(fullpath): + return os.path.abspath(fullpath) + sys.exit("Could not find %s in %s"%(filename, search_path_var)) + +if options.flat: + variables = [ + ("AUTHOR","I"), + ("ETA","F"), + ("TRKAVGDIST","F"), + ("ETOVERPTLEADTRK","F"), + ("EMFRACTIONATEMSCALE","F"), + ("TRT_NHT_OVER_NLT","F"), + ("NUM_PILEUP_AND_PRIMARY_VERTICES","I"), + ("DRMAX","F"), + ("ABS_ETA_LEAD_TRACK","F"), + ("CHPIEMEOVERCALOEME","F"), + ("SECMAXSTRIPET","F"), + ("HADLEAKET","F"), + ("SUMEMCELLETOVERLEADTRKPT","F"), + ("CORRFTRK","F"), + ("CORRCENTFRAC","F"), + ("ISOLFRAC","F"), + ("HADRADIUS","F"), + ("EMPOVERTRKSYSP","F"), + ("PSSFRACTION","F"), + ("NSTRIP","I"), + ("NUMTRACK","I"), + ("PT","F"), + ("NUMWIDETRACK","I"), + ("MASSTRKSYS","F"), + ("IPSIGLEADTRK","F"), + ("TRFLIGHTPATHSIG","F"), + ("TAU_PTRATIO","F"), + ("TAU_PI0_N","I"), + ("TAU_PI0_VISTAU_M","F"), + ("EMFRACTIONATEMSCALE_MOVEE3","F"), + ("TAU_ABSDELTAETA","F"), + ("TAU_SEEDTRK_SECMAXSTRIPETOVERPT","F"), + ("TAU_ABSDELTAPHI","F"), + + ] +else: + variables = [ ("AUTHOR","VI"), + ("ETA","VF"), + ("TRKAVGDIST","VF"), + ("ETOVERPTLEADTRK","VF"), + ("EMFRACTIONATEMSCALE","VF"), + ("TRT_NHT_OVER_NLT","VF"), + ("NUM_PILEUP_AND_PRIMARY_VERTICES","I"), + ("DRMAX","VF"), + ("ABS_ETA_LEAD_TRACK","VF"), + ("CHPIEMEOVERCALOEME","VF"), + ("SECMAXSTRIPET","VF"), + ("HADLEAKET","VF"), + ("SUMEMCELLETOVERLEADTRKPT","VF"), + ("CORRFTRK","VF"), + ("CORRCENTFRAC","VF"), + ("ISOLFRAC","VF"), + ("HADRADIUS","VF"), + ("EMPOVERTRKSYSP","VF"), + ("PSSFRACTION","VF"), + ("NSTRIP","VI"), + ("NUMTRACK","VI"), + ("PT","VF"), + ("NUMWIDETRACK","VI"), + ("MASSTRKSYS","VF"), + ("IPSIGLEADTRK","VF"), + ("TRFLIGHTPATHSIG","VF"), + ("TAU_PTRATIO","VF"), + ("TAU_PI0_N","VI"), + ("TAU_PI0_VISTAU_M","VF"), + ("EMFRACTIONATEMSCALE_MOVEE3","VF"), + ("TAU_ABSDELTAETA","VF"), + ("TAU_SEEDTRK_SECMAXSTRIPETOVERPT","VF"), + ("TAU_ABSDELTAPHI","VF"), + ] + +#cutsfile = find_file("cuts.txt","DATAPATH",True) +jetBDTfile = find_file("jet.BDT.bin","DATAPATH",True) +eleBDTfile = find_file("ele.BDT.bin","DATAPATH",True) +pi0pBDTfile = find_file("pi0Primary.BDT.bin","DATAPATH",True) +pi0sBDTfile = find_file("pi0Secondary.BDT.bin","DATAPATH",True) +llh_files = find_file("pdfs_tau.root","DATAPATH",True)+","+find_file("pdfs_jet.root","DATAPATH",True)+","+find_file("LMTCutsLLH.root","DATAPATH",True) + +sBDTCutsfile = find_file("sig.bits.jet.BDT.txt","DATAPATH",True) +bBDTCutsfile = find_file("bkg.bits.jet.BDT.txt","DATAPATH",True) + +options.methods = list(set(options.methods.split(','))) +options.extramethods = list(set(options.extramethods.split(','))) + +methods = { +# "CUTS": (TauID.Types.CUTS, "CUTS", cutsfile, 3), + "BDT": (TauID.Types.BDT, "BDTJetScore", jetBDTfile, 1), + "BDTE": (TauID.Types.BDT, "BDTEleScore", eleBDTfile, 1), + "PI0P": (TauID.Types.BDT, "Pi0PrimaryScore",pi0pBDTfile,1), + "PI0S": (TauID.Types.BDT, "Pi0SecondaryScore",pi0sBDTfile,1), + "LLH": (TauID.Types.LLH, "llhsafe",llh_files,4), +} + +extraMethods = { + "SBDTCUTS": (TauID.Types.CUTS, "SBDTJetScore", sBDTCutsfile, 3), + "BBDTCUTS": (TauID.Types.CUTS, "BBDTJetScore", bBDTCutsfile, 3), +} + +methodVariables = [ + ("BDT","F","BDTJetScore"), + ("BDTE","F","BDTEleScore"), + ("PI0P","F","Pi0PrimaryScore"), + ("PI0S","F","Pi0SecondaryScore"), + ("LLH","F","llhsafe"), + + +] + +reader = TauID.TauIDReader(options.verbose) + +for variable,typename in variables: + if not reader.addVariable(variable,typename): + sys.exit("Abort") + +for method in options.methods: + if methods.has_key(method): + if not reader.bookMethod(*methods[method]): + sys.exit("Aborted") + else: + sys.exit("Method %s is not defined"% method) + +for variable,typename,branch in methodVariables: + if not reader.addVariable(variable, typename, branch): + sys.exit("Abort") + +if extraMethods: + for method in options.extramethods: + if not method == "NONE": + if extraMethods.has_key(method): + if not reader.bookMethod(*extraMethods[method]): + sys.exit("Aborted") + else: + sys.exit("Method %s is not defined"% method) + +# Suppress warnings +ROOT.gErrorIgnoreLevel = ROOT.kError + +if options.verbose: + print "=============================================" +totalTime = 0. +totalEntries = 0 +for filename in args: + print "Processing %s..."% filename + outputfilename = filename+".tauid-redo.root" + if not reader.setOutput(outputfilename, options.outputdir): + sys.exit("Aborted") + t1 = time.time() + entries = reader.classify(options.treename, options.treename, filename, options.inputdir, options.friendtree, options.clonetree) + if entries <= 0: + + sys.exit("Aborted") + dt = time.time() - t1 + totalTime += dt + totalEntries += entries + if options.verbose: + print "Total time: %.3f [sec]"%dt + print "<Time per entry>: %i [microsec]"%int(1000000*dt/entries) + print "Finished processing %s"% filename + print "=============================================" +if options.verbose: + print "Total time for all files: %.3f [min]"% (totalTime/60) + if totalEntries > 0: + print "<Time per entry> over all files: %i [microsec]"%int(1000000*totalTime/totalEntries) +print "Done" diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/setup.sh b/PhysicsAnalysis/TauID/TauDiscriminant/setup.sh new file mode 100644 index 00000000000..304d2656725 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/setup.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +######################################################## +# +# Update env variables for running in standalone mode +# on D3PDs (ROOT ntuples) with tauid-redo +# or scripts in taumva (see README) +# +# - Noel Dawe +# +######################################################## + +# deterine path to this script +# http://stackoverflow.com/questions/59895/can-a-bash-script-tell-what-directory-its-stored-in +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done +TD_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +export LD_LIBRARY_PATH=${TD_DIR}/StandAlone${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} +export PATH=${TD_DIR}/run${PATH:+:$PATH} +export DATAPATH=${TD_DIR}/share${DATAPATH:+:$DATAPATH} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/share/EnergyCalibration.root b/PhysicsAnalysis/TauID/TauDiscriminant/share/EnergyCalibration.root new file mode 100644 index 0000000000000000000000000000000000000000..ce496c79bb2c8bbbd94c9ebe8a41b0e1747341c1 GIT binary patch literal 57427 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 K)n5xV4E`@RC;eIg literal 0 HcmV?d00001 diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/share/LMTCutsLLH.root b/PhysicsAnalysis/TauID/TauDiscriminant/share/LMTCutsLLH.root new file mode 100644 index 0000000000000000000000000000000000000000..24f4f48502f5d7b79299227c5e97c58c21de8716 GIT binary patch literal 13034 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 If6X}m3xULAdjJ3c literal 0 HcmV?d00001 diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/share/TauDiscri_jobOptions.py b/PhysicsAnalysis/TauID/TauDiscriminant/share/TauDiscri_jobOptions.py new file mode 100755 index 00000000000..a18556d6509 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/share/TauDiscri_jobOptions.py @@ -0,0 +1,2 @@ +from TauDiscriminant.TauDiscriGetter import TauDiscriGetter +TauDiscriGetter() diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/share/bkg.bits.jet.BDT.txt b/PhysicsAnalysis/TauID/TauDiscriminant/share/bkg.bits.jet.BDT.txt new file mode 100644 index 00000000000..df7f16c5859 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/share/bkg.bits.jet.BDT.txt @@ -0,0 +1,179 @@ +1 +NUMTRACK I +0 1 +-3 +-3 +-1 +2 +BDT F +PT F +3 +1.000000E+00 +-4 22 +1 0 +0.000000 0.518400 +15257.155700 0.518400 +15801.688600 0.517600 +16393.516200 0.519800 +17031.783300 0.516600 +17730.442600 0.521400 +18495.901500 0.523600 +19333.822700 0.523300 +20280.374400 0.522300 +21333.054500 0.529000 +22488.162300 0.528600 +23777.609800 0.535000 +25239.947200 0.539800 +26919.403000 0.543800 +28851.328600 0.546700 +31087.770400 0.556400 +33769.034400 0.559300 +37162.997000 0.581400 +41954.037500 0.596400 +50340.639900 0.612200 +72907.442500 0.668200 +100000.000000 0.668200 +-2 0.000000E+00 +-2 1.000000E+00 +-1 +1.000000E+00 +-4 22 +1 0 +0.000000 0.618000 +15257.155700 0.618000 +15801.688600 0.609600 +16393.516200 0.618500 +17031.783300 0.615000 +17730.442600 0.620100 +18495.901500 0.634100 +19333.822700 0.618700 +20280.374400 0.628900 +21333.054500 0.633100 +22488.162300 0.640300 +23777.609800 0.643800 +25239.947200 0.647400 +26919.403000 0.654200 +28851.328600 0.661400 +31087.770400 0.672800 +33769.034400 0.681100 +37162.997000 0.717500 +41954.037500 0.731800 +50340.639900 0.743800 +72907.442500 0.793800 +100000.000000 0.793800 +-2 0.000000E+00 +-2 1.000000E+00 +-1 +1.000000E+00 +-4 22 +1 0 +0.000000 0.773400 +15257.155700 0.773400 +15801.688600 0.777100 +16393.516200 0.781100 +17031.783300 0.776700 +17730.442600 0.788800 +18495.901500 0.790200 +19333.822700 0.787200 +20280.374400 0.798300 +21333.054500 0.816600 +22488.162300 0.779800 +23777.609800 0.803400 +25239.947200 0.835900 +26919.403000 0.818100 +28851.328600 0.854600 +31087.770400 0.834200 +33769.034400 0.846100 +37162.997000 0.872900 +41954.037500 0.876200 +50340.639900 0.876100 +72907.442500 0.902900 +100000.000000 0.902900 +-2 0.000000E+00 +-2 1.000000E+00 +-1 +3 +1.000000E+00 +-4 22 +1 0 +0.000000 0.436700 +16000.007700 0.436700 +17911.972000 0.432700 +19717.259300 0.433700 +21470.598800 0.425500 +23177.059000 0.421200 +24925.380500 0.398400 +26680.763400 0.426800 +28449.353600 0.393500 +30257.536300 0.420400 +32147.890800 0.402200 +34196.679100 0.407800 +36422.228100 0.403200 +38834.308800 0.415600 +41599.517400 0.407200 +44913.180800 0.422300 +49074.177400 0.406700 +54502.529500 0.360100 +62009.981200 0.421800 +72562.859400 0.398200 +88765.527900 0.405200 +100000.000000 0.405200 +-2 0.000000E+00 +-2 1.000000E+00 +-1 +1.000000E+00 +-4 22 +1 0 +0.000000 0.530700 +16000.007700 0.530700 +17911.972000 0.537900 +19717.259300 0.528000 +21470.598800 0.529600 +23177.059000 0.527900 +24925.380500 0.536600 +26680.763400 0.537500 +28449.353600 0.533700 +30257.536300 0.541100 +32147.890800 0.531500 +34196.679100 0.534900 +36422.228100 0.538100 +38834.308800 0.539900 +41599.517400 0.546400 +44913.180800 0.547100 +49074.177400 0.551700 +54502.529500 0.550100 +62009.981200 0.552800 +72562.859400 0.554200 +88765.527900 0.568800 +100000.000000 0.568800 +-2 0.000000E+00 +-2 1.000000E+00 +-1 +1.000000E+00 +-4 22 +1 0 +0.000000 0.660700 +16000.007700 0.660700 +17911.972000 0.687400 +19717.259300 0.676800 +21470.598800 0.679300 +23177.059000 0.675100 +24925.380500 0.677000 +26680.763400 0.696700 +28449.353600 0.695900 +30257.536300 0.692100 +32147.890800 0.686300 +34196.679100 0.685800 +36422.228100 0.700000 +38834.308800 0.728600 +41599.517400 0.705300 +44913.180800 0.712500 +49074.177400 0.706500 +54502.529500 0.716500 +62009.981200 0.704800 +72562.859400 0.708300 +88765.527900 0.712800 +100000.000000 0.712800 +-2 0.000000E+00 +-2 1.000000E+00 +-1 diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/share/cuts.eBDT.root b/PhysicsAnalysis/TauID/TauDiscriminant/share/cuts.eBDT.root new file mode 100644 index 0000000000000000000000000000000000000000..34fc6599a980992dc6347bd03ac7c17d616d1edc GIT binary patch literal 7067 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 Iz+}LG0L)+t?f?J) literal 0 HcmV?d00001 diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/share/cuts.txt b/PhysicsAnalysis/TauID/TauDiscriminant/share/cuts.txt new file mode 100644 index 00000000000..ba98b560c74 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/share/cuts.txt @@ -0,0 +1,93 @@ +1 +NUMTRACK I +0 1 +-3 +-3 +-1 +6 +TRKAVGDIST F +ETOVERPTLEADTRK F +CALO_ISO_CORRECTED F +NUMWIDETRACK I +PT F +TRFLIGHTPATHSIG F +3 +1.000000E+00 +-5 0.0667*(80000.<=x)+(417./x+0.0824-2.61e-7*x)*(x<80000.) +4 0 +1 4.000000E+00 +2 6.000000E+03 +3 9999 +-2 1.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-1 +1.000000E+00 +-5 0.0667*(80000.<=x)+(417./x+0.0824-2.61e-7*x)*(x<80000.) +4 0 +1 3.330000E+00 +2 4.000000E+03 +3 0 +-2 1.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-1 +1.000000E+00 +-5 0.0567*(80000.<=x)+(417./x+0.0724-2.61e-7*x)*(x<80000.) +4 0 +1 2.500000E+00 +2 3.000000E+03 +3 0 +-2 1.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-1 +3 +1.000000E+00 +-5 0.048*(80000.<=x)+(375./x+0.0696-3.28e-7*x)*(x<80000.) +4 0 +1 3.330000E+00 +2 7.000000E+03 +3 9999 +5 -9.999000E+03 +-2 0.000000E+00 +-2 1.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-1 +1.000000E+00 +-5 0.048*(80000.<=x)+(375./x+0.0696-3.28e-7*x)*(x<80000.) +4 0 +1 3.330000E+00 +2 7.000000E+03 +3 0 +5 0.000000E+00 +-2 0.000000E+00 +-2 1.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-1 +1.000000E+00 +-5 0.038*(80000.<=x)+(375./x+0.0596-3.28e-7*x)*(x<80000.) +4 0 +1 2.500000E+00 +2 4.000000E+03 +3 0 +5 5.000000E-01 +-2 0.000000E+00 +-2 1.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-2 0.000000E+00 +-1 diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/share/pdfs_jet.root b/PhysicsAnalysis/TauID/TauDiscriminant/share/pdfs_jet.root new file mode 100644 index 0000000000000000000000000000000000000000..0bda98ce1378f6dd7497992283ddf2190d29ac7d GIT binary patch literal 30945 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 literal 0 HcmV?d00001 diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/share/pdfs_tau.root b/PhysicsAnalysis/TauID/TauDiscriminant/share/pdfs_tau.root new file mode 100644 index 0000000000000000000000000000000000000000..9fc7a07067d8903a1d4d96ba7b8de855dd877206 GIT binary patch literal 29529 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 literal 0 HcmV?d00001 diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/share/pi0Primary.BDT.bin b/PhysicsAnalysis/TauID/TauDiscriminant/share/pi0Primary.BDT.bin new file mode 100644 index 0000000000000000000000000000000000000000..711ea8de8963f0acf38f3e9da51f80c8eec2d6a1 GIT binary patch literal 87847 zcmb5X2~^I{`!{}5(IPD*q9mV$qEeO=l?sVc5wh>J5)!heNU4OBy_9T)WLMFm?6PHF zDqA5tmF2nT^>X|DKHu|v&-4Fxjx%QFnroYDX0Ewr=6#zfcUN{AGStn>$zzy@i{~iM zq5A!m9R?0{b{gU&3LWeRyGj2mEgb6U+26z7VVJX<t2E~{Ow<k?HrUDDQQA;i;_5lf z!+EH_v$CE<B5?>g)mL7cHvIFi>-u$l#Q%#@b^AyYNym!)wjyuQ_pFV8ll^_MU2Xg8 z_wV0Vf<loVYcs}H)V=LL1L?_KW_?6`vEpLe2Ga5mZm;@^`rCtVA${ro7WL&xLAG+z z@^2%L11{z6l3YP=V9ppD(cWnPRN(hh>PtErzDOq>oC|pQUYdCVZotR@l*j+$jC9ZM zV5E6FO>Jd-3qD$f-tQ~mV*?3)%QhHzl2_<}?}a^dk(%^7(pT`+vgcvsiw=~4-#K?C z0N$!`D(K$aVF5ZRErug~Q|*iT3Ejtnj=7=<%H_YgBQ2<E0emyB4ujklv;0u*bewW# zjUzu@c8o)L<N7X0(=(_3l|#ywM7@WCosc8S!W;EV2bhBHm*&mEr=q0-${(lqLjQ_3 zLjJ@qA)p_my9D%CXzW1$=C&A*c9Uu+1CP<FHhBWSbzeuo9X!VVK0k3J@OG1@oRT&A zkW;I83d&dN%|+VJ)(-7H1WrP}d590vTNw+0-@wijd~}O-2b}Bb4Dj*u+~7Wf&tZ%1 z!cH`PFGreMb_@L7D5V}B&#?r)Zs%K~{ax?Xz?ZN&5d8RjAC3Amr>&8`HJl6m3Ebje z^R6+#tD4fkugLeD;Fc%kP3_PU@be4%0AFNw5%9Gu&_ub}>szpkKAobFAAQ*z={ToJ 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 literal 0 HcmV?d00001 diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/share/pi0Secondary.BDT.bin b/PhysicsAnalysis/TauID/TauDiscriminant/share/pi0Secondary.BDT.bin new file mode 100644 index 0000000000000000000000000000000000000000..0f76f5fb2c1d61778c365482118a7b6e50b67e28 GIT binary patch literal 7351 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 V9sD!?hSAgyvGtVSxip%;{{vJaqRs#S literal 0 HcmV?d00001 diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/share/sig.bits.jet.BDT.txt b/PhysicsAnalysis/TauID/TauDiscriminant/share/sig.bits.jet.BDT.txt new file mode 100644 index 00000000000..432acacd12a --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/share/sig.bits.jet.BDT.txt @@ -0,0 +1,359 @@ +1 +NUMTRACK I +0 1 +-3 +-3 +-1 +2 +BDT F +PT F +3 +1.000000E+00 +-4 50 +1 0 +0.000000 0.500800 +16140.164100 0.500800 +16910.560500 0.504500 +17686.359400 0.511500 +18468.919900 0.515400 +19258.222700 0.522000 +20052.459000 0.526400 +20862.914100 0.525800 +21685.084000 0.532500 +22524.728500 0.535200 +23396.103500 0.536700 +24297.113300 0.540300 +25222.515600 0.540100 +26180.726600 0.543500 +27173.009800 0.547500 +28203.728500 0.548300 +29291.011700 0.546200 +30445.728500 0.554500 +31678.771500 0.552800 +33008.894500 0.558600 +34464.570300 0.561900 +36079.656200 0.561800 +37919.226600 0.566600 +40129.968800 0.572100 +43075.921900 0.573000 +48713.335900 0.578400 +57510.192600 0.586100 +67274.898000 0.581600 +77039.603500 0.584600 +86804.309000 0.577000 +96569.014500 0.588300 +106101.859400 0.587400 +115657.031200 0.590000 +126005.000000 0.583300 +137251.093800 0.589500 +149065.281200 0.590200 +161429.625000 0.591900 +174342.312500 0.591000 +187864.937500 0.590100 +202402.296900 0.588900 +218018.359400 0.590200 +235117.968800 0.590600 +254758.593800 0.591700 +277347.875000 0.593200 +303140.625000 0.588500 +333448.437500 0.591600 +372086.750000 0.591000 +426726.468800 0.596100 +544437.242200 0.595300 +800000.000000 0.595300 +-2 0.000000E+00 +-2 1.000000E+00 +-1 +1.000000E+00 +-4 50 +1 0 +0.000000 0.545100 +16140.164100 0.545100 +16910.560500 0.550200 +17686.359400 0.556700 +18468.919900 0.560100 +19258.222700 0.567200 +20052.459000 0.572700 +20862.914100 0.572400 +21685.084000 0.582100 +22524.728500 0.583500 +23396.103500 0.585600 +24297.113300 0.591400 +25222.515600 0.595100 +26180.726600 0.597200 +27173.009800 0.600500 +28203.728500 0.603800 +29291.011700 0.602900 +30445.728500 0.609300 +31678.771500 0.610800 +33008.894500 0.616200 +34464.570300 0.619500 +36079.656200 0.621200 +37919.226600 0.628800 +40129.968800 0.632500 +43075.921900 0.636000 +48713.335900 0.642500 +57510.192600 0.650800 +67274.898000 0.646300 +77039.603500 0.649900 +86804.309000 0.637700 +96569.014500 0.655800 +106101.859400 0.657000 +115657.031200 0.658600 +126005.000000 0.656200 +137251.093800 0.660200 +149065.281200 0.661200 +161429.625000 0.664500 +174342.312500 0.662400 +187864.937500 0.660800 +202402.296900 0.660100 +218018.359400 0.662200 +235117.968800 0.663600 +254758.593800 0.663100 +277347.875000 0.665700 +303140.625000 0.660200 +333448.437500 0.664600 +372086.750000 0.664200 +426726.468800 0.664400 +544437.242200 0.666500 +800000.000000 0.666500 +-2 0.000000E+00 +-2 1.000000E+00 +-1 +1.000000E+00 +-4 50 +1 0 +0.000000 0.629700 +16140.164100 0.629700 +16910.560500 0.636700 +17686.359400 0.641400 +18468.919900 0.645800 +19258.222700 0.653400 +20052.459000 0.658000 +20862.914100 0.658900 +21685.084000 0.664400 +22524.728500 0.668400 +23396.103500 0.669200 +24297.113300 0.676000 +25222.515600 0.678000 +26180.726600 0.681500 +27173.009800 0.683900 +28203.728500 0.687700 +29291.011700 0.688800 +30445.728500 0.694100 +31678.771500 0.693300 +33008.894500 0.699900 +34464.570300 0.702900 +36079.656200 0.703900 +37919.226600 0.710000 +40129.968800 0.713300 +43075.921900 0.713200 +48713.335900 0.719600 +57510.192600 0.731600 +67274.898000 0.730600 +77039.603500 0.733900 +86804.309000 0.712300 +96569.014500 0.728900 +106101.859400 0.730700 +115657.031200 0.732700 +126005.000000 0.731900 +137251.093800 0.733300 +149065.281200 0.733200 +161429.625000 0.734900 +174342.312500 0.733400 +187864.937500 0.731600 +202402.296900 0.731400 +218018.359400 0.731000 +235117.968800 0.731600 +254758.593800 0.729700 +277347.875000 0.729600 +303140.625000 0.727500 +333448.437500 0.726900 +372086.750000 0.725900 +426726.468800 0.723500 +544437.242200 0.721900 +800000.000000 0.721900 +-2 0.000000E+00 +-2 1.000000E+00 +-1 +3 +1.000000E+00 +-4 54 +1 0 +0.000000 0.475900 +16737.960900 0.475900 +17778.316400 0.486800 +18761.082000 0.493800 +19706.365200 0.499200 +20633.343800 0.508300 +21536.095700 0.507600 +22419.902300 0.514500 +23295.601600 0.518000 +24168.896500 0.518200 +25048.230500 0.521700 +25926.437500 0.521800 +26810.982400 0.523700 +27718.646500 0.527400 +28641.666000 0.530700 +29588.650400 0.531400 +30562.250000 0.533300 +31560.375000 0.536000 +32591.238300 0.535000 +33675.078100 0.534600 +34845.664100 0.537900 +36110.484400 0.537600 +37502.226600 0.537400 +39085.468800 0.541400 +40938.511700 0.542400 +43325.445300 0.544200 +47172.777300 0.546200 +51147.618800 0.553600 +54163.379700 0.555200 +57179.140600 0.559500 +60194.901600 0.553300 +63210.662500 0.556300 +69002.991800 0.557000 +77571.889500 0.554300 +86140.787100 0.549600 +94709.684800 0.556900 +103278.582400 0.559200 +113960.257800 0.566600 +127432.898400 0.573900 +142193.531200 0.572500 +157442.937500 0.567700 +172714.281200 0.569600 +188320.218800 0.569400 +204392.218800 0.568100 +221300.218800 0.569500 +239779.281200 0.563800 +260790.500000 0.560600 +284605.312500 0.552500 +310978.187500 0.553500 +341455.000000 0.549900 +380790.156200 0.533900 +435189.375000 0.529400 +550179.007800 0.506700 +800000.000000 0.506700 +-2 0.000000E+00 +-2 1.000000E+00 +-1 +1.000000E+00 +-4 54 +1 0 +0.000000 0.506300 +16737.960900 0.506300 +17778.316400 0.515900 +18761.082000 0.518400 +19706.365200 0.524600 +20633.343800 0.534000 +21536.095700 0.533500 +22419.902300 0.540100 +23295.601600 0.543000 +24168.896500 0.541400 +25048.230500 0.546000 +25926.437500 0.546800 +26810.982400 0.547600 +27718.646500 0.552600 +28641.666000 0.553300 +29588.650400 0.554800 +30562.250000 0.555200 +31560.375000 0.558800 +32591.238300 0.559000 +33675.078100 0.558100 +34845.664100 0.562000 +36110.484400 0.561300 +37502.226600 0.562300 +39085.468800 0.566600 +40938.511700 0.567200 +43325.445300 0.569100 +47172.777300 0.571100 +51147.618800 0.581800 +54163.379700 0.586600 +57179.140600 0.589000 +60194.901600 0.585000 +63210.662500 0.586900 +69002.991800 0.589400 +77571.889500 0.588300 +86140.787100 0.582900 +94709.684800 0.577500 +103278.582400 0.597000 +113960.257800 0.602500 +127432.898400 0.610700 +142193.531200 0.610700 +157442.937500 0.607800 +172714.281200 0.606200 +188320.218800 0.608500 +204392.218800 0.603200 +221300.218800 0.606800 +239779.281200 0.603400 +260790.500000 0.600900 +284605.312500 0.593700 +310978.187500 0.593500 +341455.000000 0.589100 +380790.156200 0.580900 +435189.375000 0.577000 +550179.007800 0.560000 +800000.000000 0.560000 +-2 0.000000E+00 +-2 1.000000E+00 +-1 +1.000000E+00 +-4 54 +1 0 +0.000000 0.557000 +16737.960900 0.557000 +17778.316400 0.564000 +18761.082000 0.565500 +19706.365200 0.574000 +20633.343800 0.582200 +21536.095700 0.585500 +22419.902300 0.592200 +23295.601600 0.596300 +24168.896500 0.598100 +25048.230500 0.597700 +25926.437500 0.599700 +26810.982400 0.602500 +27718.646500 0.607900 +28641.666000 0.609400 +29588.650400 0.607700 +30562.250000 0.610200 +31560.375000 0.614200 +32591.238300 0.616500 +33675.078100 0.615000 +34845.664100 0.616800 +36110.484400 0.616800 +37502.226600 0.621000 +39085.468800 0.625400 +40938.511700 0.627700 +43325.445300 0.629700 +47172.777300 0.630300 +51147.618800 0.643900 +54163.379700 0.647900 +57179.140600 0.645000 +60194.901600 0.642200 +63210.662500 0.648400 +69002.991800 0.655800 +77571.889500 0.659200 +86140.787100 0.649900 +94709.684800 0.640300 +103278.582400 0.675100 +113960.257800 0.682000 +127432.898400 0.691200 +142193.531200 0.691900 +157442.937500 0.686900 +172714.281200 0.687000 +188320.218800 0.689900 +204392.218800 0.681800 +221300.218800 0.684600 +239779.281200 0.684200 +260790.500000 0.680400 +284605.312500 0.673400 +310978.187500 0.674600 +341455.000000 0.662800 +380790.156200 0.658300 +435189.375000 0.652200 +550179.007800 0.641500 +800000.000000 0.641500 +-2 0.000000E+00 +-2 1.000000E+00 +-1 diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/share/sig.trans.jet.BDT.root b/PhysicsAnalysis/TauID/TauDiscriminant/share/sig.trans.jet.BDT.root new file mode 100644 index 0000000000000000000000000000000000000000..ba5ba57ee1a7f5b1c813237fd7d1f4b5b229d167 GIT binary patch literal 11887 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 literal 0 HcmV?d00001 diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/FakeTauBits.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/FakeTauBits.cxx new file mode 100644 index 00000000000..3f2bc8cf305 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/FakeTauBits.cxx @@ -0,0 +1,5 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TauDiscriminant/FakeTauBits.h" diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/FakeTauScores.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/FakeTauScores.cxx new file mode 100644 index 00000000000..51c598358cd --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/FakeTauScores.cxx @@ -0,0 +1,5 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TauDiscriminant/FakeTauScores.h" diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/TauCuts.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauCuts.cxx new file mode 100644 index 00000000000..f0aa40e04f8 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauCuts.cxx @@ -0,0 +1,75 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TauDiscriminant/TauCuts.h" +#include "xAODTau/TauJetContainer.h" +#include "xAODTau/TauJet.h" +// #include "tauEvent/TauCommonDetails.h" +// #include "tauEvent/TauPID.h" +// #include "tauEvent/TauJetParameters.h" +#include "xAODTau/TauDefs.h" +#include <PathResolver/PathResolver.h> + +using namespace xAOD; +//----------------------------------------------------------------------------- +// Initializer +//----------------------------------------------------------------------------- +StatusCode TauCuts::prepare(const TauDetailsManager& manager) +{ + m_cutsManager = new MethodCuts("TauCuts"); + m_cutsManager->setDetails(manager); + + string cutsPath = PathResolver::find_file(m_fileName, "DATAPATH"); + + if ( !m_cutsManager->build(cutsPath) ) { + ATH_MSG_FATAL("unable to build cuts manager"); + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Finalizer +//----------------------------------------------------------------------------- +StatusCode TauCuts::finalize() +{ + delete m_cutsManager; + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Execution +//----------------------------------------------------------------------------- +StatusCode TauCuts::execute(xAOD::TauJet* tau, FakeTauBits* /*bits*/, FakeTauScores* /*scores*/) +{ + bool loose(false), medium(false), tight(false); + + if (tau->nTracks() > 0) + { + loose = m_cutsManager->response(0); + medium = m_cutsManager->response(1); + tight = m_cutsManager->response(2); + } + +// Analysis::TauPID *p_tauid = tau->tauID(); + + tau->setIsTau(TauJetParameters::TauCutLoose, loose); + tau->setIsTau(TauJetParameters::TauCutMedium, medium); + tau->setIsTau(TauJetParameters::TauCutTight, tight); + + // Verbose messaging for extra info + if (msgLvl(MSG::VERBOSE)) + { + if (!((!loose && !medium && !tight) || (loose && !medium && !tight) || (loose && medium && !tight) || (loose && medium && tight))) + { + msg(MSG::VERBOSE) << "Bad cuts!" << endreq; + } + msg(MSG::VERBOSE) << "TauCutLoose: " << tau->isTau(TauJetParameters::TauCutLoose) << endreq; + msg(MSG::VERBOSE) << "TauCutMedium: " << tau->isTau(TauJetParameters::TauCutMedium) << endreq; + msg(MSG::VERBOSE) << "TauCutTight: " << tau->isTau(TauJetParameters::TauCutTight) << endreq; + } + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/TauCutsEleVeto.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauCutsEleVeto.cxx new file mode 100644 index 00000000000..6eff019da59 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauCutsEleVeto.cxx @@ -0,0 +1,206 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TauDiscriminant/TauCutsEleVeto.h" +#include "xAODTau/TauJetContainer.h" +#include "xAODTau/TauJet.h" +// #include "tauEvent/TauCommonDetails.h" +// #include "tauEvent/TauPID.h" +// #include "tauEvent/TauJetParameters.h" +#include "xAODTau/TauDefs.h" +#include "TauDiscriminant/TauDetails.h" +#include <PathResolver/PathResolver.h> + +using namespace xAOD; + +//----------------------------------------------------------------------------- +// Initializer +//----------------------------------------------------------------------------- +StatusCode TauCutsEleVeto::prepare(const TauDetailsManager& manager) +{ + this->detailsManager = &manager; + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Finalizer +//----------------------------------------------------------------------------- +StatusCode TauCutsEleVeto::finalize() +{ + return StatusCode::SUCCESS; +} +/* Cut-based electron veto implementation + * + * + * returns false if it a tau + * true if it is an electron candidate + * This function can also work on D3PD-level: + * input D3PD variables: ****************************************************** + * eta : tau_seedCalo_track_eta (track with highest tau_seedCalo_track_pt) + * TrkAvgDist: tau_seedCalo_trkAvgDist + * HoP : tau_seedCalo_etHadAtEMScale/tau_leadTrkPt + * EoP : tau_seedCalo_etEMAtEMScale/tau_leadTrkPt + * TrtRatio : tau_calcVars_TRTHTOverLT_LeadTrk + * **************************************************************************** + * Usage: + * tauElectronVeto(float eta, float TrkAvgDist, float HoP, + * float EoP, float TrtRatio, int qual) + * qual: loose, medium, tight or tighter + * returns true if the object is identified as an electron by the algorithm + * ATLAS tauWG supported points: loose, medium and tight, tighter is for test + * purposes + * + * Changes since the last release (12 May 2011) + * + * eta range changed: central taus were defined 0.0-1.7 now 0.0-2.0 + * variables replaced: + * OLD VARIABLE (ATHENA REL16) -> NEW VARIABLE (ATHENA REL17) + * tau_seedTrk_secMaxStripEt -> tau_seedCalo_trkAvgDist + * tau_seedTrk_hadLeakEt -> tau_seedCalo_etHadAtEMScale/tau_leadTrkPt + * tau_seedTrk_sumEMCellEtOverLeadTrkPt -> tau_seedCalo_etEMAtEMScale/tau_leadTrkPt + * **************************************************************************** + * nikolaos.rompotis at cern.ch - 6 Oct 2011 + * + */ +bool tauElectronVeto(float eta, float TrkAvgDist, float HoP, + float EoP, float TrtRatio, int qual) { + float TrkAvgDist_C0, HoP_C0, EoP_C0, TrtRatio_C0a, TrtRatio_C0b, TrtRatio_C0c; + float HoP_C1, EoP_C1; + + // define the cut values ............. + if (qual == 0) { + TrkAvgDist_C0= 0.026; + HoP_C0 = 0.060; + EoP_C0 = 0.868; + TrtRatio_C0a = 0.227; + TrtRatio_C0b = 0.108; + TrtRatio_C0c = 0.151; + + HoP_C1 = 0.088; + EoP_C1 = 0.102; + } + else if (qual == 1) { + TrkAvgDist_C0= 0.051; + HoP_C0 = 0.090; + EoP_C0 = 0.812; + TrtRatio_C0a = 0.162; + TrtRatio_C0b = 0.069; + TrtRatio_C0c = 0.097; + + HoP_C1 = 0.195; + EoP_C1 = 1.076; + } + else if (qual == 2) { + TrkAvgDist_C0= 0.096; + HoP_C0 = 0.035; + EoP_C0 = 0.104; + TrtRatio_C0a = 0.107; + TrtRatio_C0b = 0.254; + TrtRatio_C0c = 0.085; + + HoP_C1 = 0.301; + EoP_C1 = 2.550; + + } + else if (qual == 3) { + TrkAvgDist_C0= 0.096; + HoP_C0 = 0.066; + EoP_C0 = 0.103; + TrtRatio_C0a = 0.098; + TrtRatio_C0b = 0.708; + TrtRatio_C0c = 0.056; + + HoP_C1 = 0.560; + EoP_C1 = 1.582; + } + else { + std::cout << "No such option for qual=" << qual << endl; + return false; + } + + if (qual == 1) { + if (tauElectronVeto(eta, TrkAvgDist, HoP, EoP, TrtRatio, 0)) + return true; + } + else if (qual == 2) { + if (tauElectronVeto(eta, TrkAvgDist, HoP, EoP, TrtRatio, 1)) + return true; + } + else if (qual == 3) { // tighter is defined also wrt to the medium + if (tauElectronVeto(eta, TrkAvgDist, HoP, EoP, TrtRatio, 2)) + return true; + } + + // ................................... + if ( fabs(eta) < 2.0 ) { // central taus + // + if (HoP > HoP_C0) { + if ( TrtRatio <= TrtRatio_C0a) return false; + else return true; + } + else { + if (TrkAvgDist > TrkAvgDist_C0) { + if (TrtRatio <= TrtRatio_C0b) return false; + else return true; + } + else { + if (TrtRatio <= TrtRatio_C0c && EoP <= EoP_C0) return false; + else return true; + } + } + } + else { // forward taus + if (HoP > HoP_C1) return false; + else { + if (EoP <= EoP_C1) return false; + else return true; + } + } +} + + +//----------------------------------------------------------------------------- +// Execution +//----------------------------------------------------------------------------- +StatusCode TauCutsEleVeto::execute(xAOD::TauJet* tau, FakeTauBits* /*bits*/, FakeTauScores* /*scores*/) +{ + + if (!detailsManager) + { + return StatusCode::FAILURE; + } + bool loose(false), medium(false), tight(false); + // demand exactly 1 track and calo or calo+track driven tau + if (tau->nTracks() == 1) + { +// const Analysis::TauCommonDetails* commonDetails(tau->details<Analysis::TauCommonDetails>()); + float etHadAtEMScale; + tau->detail(TauJetParameters::etHadAtEMScale,etHadAtEMScale); + float etEMAtEMScale; + tau->detail(TauJetParameters::etEMAtEMScale,etEMAtEMScale); + float lcScale = 1; + if(this->useLCscale) tau->detail(TauJetParameters::LC_TES_precalib,lcScale); + + float eta = tau->track(0)->eta();//detailsManager->getFloatDetailValue(Details::ABS_ETA_LEAD_TRACK); + float TrkAvgDist = detailsManager->getFloatDetailValue(Details::TRKAVGDIST); + float leadTrkPt = tau->track(0)->pt(); + float HoP = leadTrkPt!=0?etHadAtEMScale*lcScale/leadTrkPt:0; + float EoP = leadTrkPt!=0?etEMAtEMScale*lcScale/leadTrkPt:0; + //float HoP = detailsManager->getFloatDetailValue(Details::ETHADATEMSCALE)/leadTrkPt; + //float EoP = detailsManager->getFloatDetailValue(Details::ETEMATEMSCALE)/leadTrkPt; + float TrtRatio = detailsManager->getFloatDetailValue(Details::TRT_NHT_OVER_NLT); + + loose = tauElectronVeto(eta, TrkAvgDist, HoP, EoP, TrtRatio, 0); + medium = tauElectronVeto(eta, TrkAvgDist, HoP, EoP, TrtRatio, 1); + tight = tauElectronVeto(eta, TrkAvgDist, HoP, EoP, TrtRatio, 2); + } + +// Analysis::TauPID *p_tauid = tau->tauID(); + + tau->setIsTau(TauJetParameters::ElectronVetoLoose, loose); + tau->setIsTau(TauJetParameters::ElectronVetoMedium, medium); + tau->setIsTau(TauJetParameters::ElectronVetoTight, tight); + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/TauDetailsManager.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauDetailsManager.cxx new file mode 100644 index 00000000000..6b7401df7d2 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauDetailsManager.cxx @@ -0,0 +1,441 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: TauDetailsManager.cxx + * + * Author: Noel Dawe (end1@sfu.ca) + */ + +#include <iostream> + +#include "TauDiscriminant/TauDetailsManager.h" +#include "TauDiscriminant/TauPi0Clusters.h" +#include <utility> + +#include "xAODTau/TauJet.h" +#include "xAODTracking/TrackParticle.h" +// #include "TrkTrackSummary/TrackSummary.h" +#include "xAODTracking/VertexContainer.h" +#include "TrkEventPrimitives/VertexType.h" +#include "xAODCaloEvent/CaloClusterContainer.h" +#include "xAODCaloEvent/CaloCluster.h" +#include "FourMomUtils/P4Helpers.h" +#include "AnalysisUtils/AnalysisMisc.h" +#include "CaloGeoHelpers/CaloSampling.h" +#include "CaloUtils/CaloVertexedCluster.h" + +// redefine the macro to print strings instead of enums as in TauDetails.h +#undef ENUM_OR_STRING +#define ENUM_OR_STRING( x ) #x + +using CLHEP::GeV; +using namespace std; +using namespace xAOD; + +// Arrays of the string representations of the detail names +namespace Details { +string IntTauDetailString[] = { INT_TAU_DETAILS }; +string FloatTauDetailString[] = { FLOAT_TAU_DETAILS }; +string IntEventDetailString[] = { INT_EVENT_DETAILS }; +string FloatEventDetailString[] = { FLOAT_EVENT_DETAILS }; +} + +// The default value for all details +const float TauDetailsManager::LOW_NUMBER = -1111.; + +TauDetailsManager::TauDetailsManager(StoreGateSvc* storeGateSvc, bool isTrigger) +{ + this->storeGate = storeGateSvc; + this->doTrigger = isTrigger; + //hard-coded for a while + m_clusterCone = 0.2; + + // Initialize the vector containing the tau-based variables + this->float_data = vector<float>(Details::__FloatTauDetail__END__ + 1,LOW_NUMBER); + this->int_data = vector<int>(Details::__IntTauDetail__END__ + 1,int(LOW_NUMBER)); + + // Initialize the vector containing the event-based variables + this->float_event_data = vector<float>( Details::__FloatEventDetail__END__ + 1, LOW_NUMBER); + this->int_event_data = vector<int>(Details::__IntEventDetail__END__ + 1, int(LOW_NUMBER)); + + // Maps of the string representations to the addresses of the values in the above vectors + unsigned int i; + for (i = 0; i < this->float_data.size() - 1; ++i) { + this->float_details.insert( pair<string, float*>(Details::FloatTauDetailString[i], &this->float_data[i])); + } + for (i = 0; i < this->float_event_data.size() - 1; ++i) { + this->float_details.insert(pair<string, float*>(Details::FloatEventDetailString[i],&this->float_event_data[i])); + } + for (i = 0; i < this->int_data.size() - 1; ++i) { + this->int_details.insert( pair<string, int*>(Details::IntTauDetailString[i], &this->int_data[i])); + } + for (i = 0; i < this->int_event_data.size() - 1; ++i) { + this->int_details.insert( pair<string, int*>(Details::IntEventDetailString[i], &this->int_event_data[i])); + } +} + +bool TauDetailsManager::updateEvent() +{ + // Reset the buffers at the beginning of each event + this->float_event_data.assign(this->float_event_data.size(), LOW_NUMBER); + this->int_event_data.assign(this->int_event_data.size(), int(LOW_NUMBER)); + + if (this->storeGate && this->doTrigger) { + //vertex information not available at EF, thus use default values to get correct bin; also retrievin VertexContainer will crash for TrigTauDiscriminant + this->int_event_data[Details::NUMGOODVERTICES] = 1; + this->int_event_data[Details::NUM_PILEUP_AND_PRIMARY_VERTICES] = 1; + return true; + } else if (this->storeGate) { + const xAOD::VertexContainer* priVertices(0); + StatusCode sc = this->storeGate->retrieve(priVertices, "PrimaryVertices"); + if (sc.isFailure()) { + return false; + } + if (priVertices) { + this->int_event_data[Details::NUMVERTICES] = priVertices->size(); + + //Martin Flechl, Nov 16, 2010: calculate number of good vertices + int nGoodVtx(0); + int nPileupPrimaryVtx(0); + xAOD::VertexContainer::const_iterator vxIter = priVertices->begin(); + xAOD::VertexContainer::const_iterator vxIterEnd = priVertices->end(); + for (; vxIter != vxIterEnd; ++vxIter) { + if (!(*vxIter)) continue; + // FF, March 2014 + // attention: the lines below may work in Athena, but not in xAOD standalone mode, which is used for end-user analysis + /* + std::vector<Trk::VxTrackAtVertex*>* vxTrackAtVertex = (*vxIter)->vxTrackAtVertex(); + if (!vxTrackAtVertex) continue; + if ( vxTrackAtVertex->size() >= 4) nGoodVtx++; + + if ((vxTrackAtVertex->size() >= 4 && (*vxIter)->vertexType() == xAOD::VxType::PriVtx ) || \ + (vxTrackAtVertex->size() >= 2 && (*vxIter)->vertexType() == xAOD::VxType::PileUp ) ) nPileupPrimaryVtx++; + */ + + // this works also in xAOD standalone mode, however, did not checked if results are the same + int nTrackParticles = (*vxIter)->nTrackParticles(); + if (nTrackParticles >= 4) nGoodVtx++; + if ( (nTrackParticles >= 4 && (*vxIter)->vertexType() == xAOD::VxType::PriVtx) || + (nTrackParticles >= 2 && (*vxIter)->vertexType() == xAOD::VxType::PileUp) + ) + nPileupPrimaryVtx++; + + } + this->int_event_data[Details::NUMGOODVERTICES] = nGoodVtx; + this->int_event_data[Details::NUM_PILEUP_AND_PRIMARY_VERTICES] = nPileupPrimaryVtx; + } + } + return true; +} + +bool TauDetailsManager::setNpi0(xAOD::TauJet& tauJet, int nPi0) +{ + this->int_data[Details::TAU_PI0_N] = nPi0; + tauJet.setDetail(TauJetParameters::nPi0Topo, static_cast<int>(nPi0)); + + //ATH_MSG_VERBOSE("setting Npi0 = "<<nPi0); + //std::cout<<"setting Npi0 = "<<nPi0<<std::endl; + return true; +} + +// const version of TauDetailsManager::update +// calculate variables and store them only in internal memory +bool TauDetailsManager::update(const xAOD::TauJet& tauJet) +{ + // Reset the buffers before setting the variables of each tau + this->float_data.assign(this->float_data.size(), LOW_NUMBER); + this->int_data.assign(this->int_data.size(), int(LOW_NUMBER)); + + // there is no author flag currently + // so keeping for backward compatibility only + this->int_data[Details::AUTHOR] = 3; + + unsigned int numTrack(tauJet.nTracks()); + + //========================================================================================== + // get variables from tau EDM + //========================================================================================== + this->int_data[Details::CHARGE] = tauJet.charge(); + this->int_data[Details::NUMTRACK] = numTrack; + this->int_data[Details::NUMWIDETRACK] = tauJet.nWideTracks(); + + this->float_data[Details::ETA] = tauJet.eta(); + this->float_data[Details::ABS_ETA] = fabs(tauJet.eta()); + + this->float_data[Details::PHI] = tauJet.phi(); + this->float_data[Details::E] = tauJet.e(); + this->float_data[Details::ET] = tauJet.pt(); + this->float_data[Details::PT] = tauJet.pt(); + this->float_data[Details::M] = tauJet.m(); + + float etOverpTLeadTrk; + tauJet.detail(TauJetParameters::etOverPtLeadTrk, etOverpTLeadTrk); + this->float_data[Details::ETOVERPTLEADTRK] = etOverpTLeadTrk; + this->float_data[Details::PTLEADTRKOVERET] = etOverpTLeadTrk > 0 ? 1. / etOverpTLeadTrk : LOW_NUMBER; + + tauJet.detail(TauJetParameters::ipZ0SinThetaSigLeadTrk, this->float_data[Details::IPZ0SINTHETASIGLEADTRK]); + tauJet.detail(TauJetParameters::ipSigLeadTrk, this->float_data[Details::IPSIGLEADTRK]); + tauJet.detail(TauJetParameters::massTrkSys, this->float_data[Details::MASSTRKSYS]); + tauJet.detail(TauJetParameters::trkWidth2, this->float_data[Details::TRKWIDTH2]); + tauJet.detail(TauJetParameters::trFlightPathSig, this->float_data[Details::TRFLIGHTPATHSIG]); + + float etEflow = 0; + tauJet.detail(TauJetParameters::etEflow, etEflow); + this->float_data[Details::ETEFLOWOVERET] = (tauJet.pt() > 0) ? etEflow / tauJet.pt() : LOW_NUMBER; + + // this variable is not filled anymore by tauRec + //tauJet.detail(TauJetParameters::mEflow, this->float_data[Details::MEFLOW]); + + tauJet.detail(TauJetParameters::stripWidth2, this->float_data[Details::STRIPWIDTH2]); + tauJet.detail(TauJetParameters::EMRadius, this->float_data[Details::EMRADIUS]); + tauJet.detail(TauJetParameters::hadRadius, this->float_data[Details::HADRADIUS]); + tauJet.detail(TauJetParameters::isolFrac, this->float_data[Details::ISOLFRAC]); + tauJet.detail(TauJetParameters::centFrac, this->float_data[Details::CENTFRAC]); + tauJet.detail(TauJetParameters::nStrip, this->int_data[Details::NSTRIP]); + tauJet.detail(TauJetParameters::trkAvgDist, this->float_data[Details::TRKAVGDIST]); + + float etEMScale, etEMScale1, etEMScale2; + tauJet.detail(TauJetParameters::etEMAtEMScale, etEMScale1); + tauJet.detail(TauJetParameters::etHadAtEMScale, etEMScale2); + etEMScale = etEMScale1 + etEMScale2; + this->float_data[Details::EMFRACTIONATEMSCALE] = (etEMScale != 0) ? etEMScale1 / etEMScale : LOW_NUMBER; + + float emradius, hadradius; + tauJet.detail(TauJetParameters::EMRadius, emradius); + tauJet.detail(TauJetParameters::hadRadius, hadradius); + this->float_data[Details::CALRADIUS] = (etEMScale != 0) ? (etEMScale1 * emradius + etEMScale2 * hadradius) / etEMScale : LOW_NUMBER; + + // New cluster-based variables + tauJet.detail(TauJetParameters::lead2ClusterEOverAllClusterE, this->float_data[Details::LEAD2CLUSTEREOVERALLCLUSTERE]); + tauJet.detail(TauJetParameters::lead3ClusterEOverAllClusterE, this->float_data[Details::LEAD3CLUSTEREOVERALLCLUSTERE]); + tauJet.detail(TauJetParameters::caloIso, this->float_data[Details::CALO_ISO]); + tauJet.detail(TauJetParameters::caloIsoCorrected, this->float_data[Details::CALO_ISO_CORRECTED]); + + // Topocluster variables: + tauJet.detail(TauJetParameters::topoInvMass, this->float_data[Details::TOPOINVMASS]); + tauJet.detail(TauJetParameters::effTopoInvMass, this->float_data[Details::EFFTOPOINVMASS]); + + tauJet.detail(TauJetParameters::PSSFraction, this->float_data[Details::PSSFRACTION]); + tauJet.detail(TauJetParameters::ChPiEMEOverCaloEME, this->float_data[Details::CHPIEMEOVERCALOEME] ); + tauJet.detail(TauJetParameters::EMPOverTrkSysP, this->float_data[Details::EMPOVERTRKSYSP]); + + // get intermediate axis + TLorentzVector tauInterAxis = tauJet.p4(TauJetParameters::IntermediateAxis); + this->float_data[Details::INTERAXIS_ETA] = tauInterAxis.Eta(); + this->float_data[Details::INTERAXIS_PHI] = tauInterAxis.Phi(); + + // this variable is special: when TauDiscriminant is called first time, this variable is empty + // in case TauDiscriminant::TauDetailsManager is called after a full TauDiscriminant run or on a already full processed AOD/xAOD + // this variable is filled properly + this->float_data[Details::BDTJETSCORE] = tauJet.discriminant(TauJetParameters::BDTJetScore); + + + //========================================================================================== + // calculate now variables needed for TauID not calculated by tauRec + //========================================================================================== + const xAOD::Jet* pJetSeed = (*tauJet.jetLink()); + if (!pJetSeed) { + //ATH_MSG_WARNING("tau does not have jet seed"); + return StatusCode::SUCCESS; + } + + // JVF and PT_PILEUP + float pt_pileup = 0.; + if (!this->doTrigger) { + // jvf and sumPtTrk are now a vector and the old run1-type jvf value is stored in the 0-th element + // sumPtTrk is calculated wrt Vertices + std::vector<float> sumPtTrkvec; + std::vector<float> jvfvec; + + // ToDo: still need to check if the 500MeV threshold is correct + pJetSeed->getAttribute(xAOD::JetAttribute::SumPtTrkPt500, sumPtTrkvec); + pJetSeed->getAttribute(xAOD::JetAttribute::JVF, jvfvec); + + float jvf = 0.0; + float sumPtTrk = 0.0; + if (!jvfvec.empty() && !sumPtTrkvec.empty()) { + // ToDo: need to check if first vertex is the vertex we want to use here! + jvf = jvfvec[0]; + sumPtTrk = sumPtTrkvec[0]; + } else { + msg(MSG::WARNING) << "jvf value vector and/or sumPtTrk vector returned from seed jet is empty!" << endreq; + } + pt_pileup = (1.0 - jvf) * sumPtTrk; + this->float_data[Details::JVF] = jvf; + this->float_data[Details::PT_PILEUP] = pt_pileup; + } + + // track-based variables for pi0 counting and ele veto + if (numTrack > 0) { + // variables used by the cut-based e-veto + tauJet.detail(TauJetParameters::hadLeakEt, this->float_data[Details::HADLEAKET]); + tauJet.detail(TauJetParameters::sumEMCellEtOverLeadTrkPt, this->float_data[Details::SUMEMCELLETOVERLEADTRKPT]); + tauJet.detail(TauJetParameters::secMaxStripEt, this->float_data[Details::SECMAXSTRIPET]); + + // Used by cut-based eveto: + if (tauJet.track(0)) { + this->float_data[Details::ABS_ETA_LEAD_TRACK] = fabs( tauJet.track(0)->eta() ); + this->float_data[Details::TAU_ABSDELTAETA] = fabs( tauJet.track(0)->eta() - tauJet.eta() ); + this->float_data[Details::TAU_ABSDELTAPHI] = fabs( tauJet.track(0)->phi() - tauJet.phi() ); + this->float_data[Details::TAU_SEEDTRK_SECMAXSTRIPETOVERPT] = (tauJet.track(0)->pt() != 0) ? this->float_data[Details::SECMAXSTRIPET] / tauJet.track(0)->pt() : LOW_NUMBER; + // solve for E3 + float tau_sumETCellsLAr = this->float_data[Details::SUMEMCELLETOVERLEADTRKPT] * tauJet.track(0)->pt(); + float tau_sumEMCellET = etEMScale1; + float tau_E3 = tau_sumETCellsLAr - tau_sumEMCellET; + + // remove E3 + float tau_seedCalo_etHadAtEMScale_noE3 = etEMScale2 - tau_E3; + float tau_seedCalo_etEMAtEMScale_yesE3 = etEMScale1 + tau_E3; + + //calculate new EMFraction + this->float_data[Details::EMFRACTIONATEMSCALE_MOVEE3] = tau_seedCalo_etEMAtEMScale_yesE3 / (tau_seedCalo_etEMAtEMScale_yesE3 + tau_seedCalo_etHadAtEMScale_noE3); + } + + // for pi0 counting + float sumpT3Trk(0.); + float sumpT(0.); + float dRmin = -1 * LOW_NUMBER; + float dR; + + for (unsigned int i(0); i < numTrack; ++i) { + if (i < 3) sumpT3Trk += tauJet.track(i)->pt(); + sumpT += tauJet.track(i)->pt(); + dR = tauJet.p4().DeltaR(tauJet.track(i)->p4()); + if (dRmin > dR) dRmin = dR; + } + + this->float_data[Details::SUMPT3TRK] = sumpT3Trk; + this->float_data[Details::SUMPT] = sumpT; + this->float_data[Details::DRMIN] = dRmin; + tauJet.detail(TauJetParameters::dRmax, this->float_data[Details::DRMAX]); + + if (tauJet.pt() != 0) { + this->float_data[Details::SUMPT_OVER_ET] = sumpT / tauJet.pt(); + this->float_data[Details::SUMPT3TRK_OVER_ET] = sumpT3Trk / tauJet.pt(); + } + + if (sumpT3Trk != 0) { + this->float_data[Details::ETHAD_EM_OVER_SUMPT3TRK] = etEMScale2 / sumpT3Trk; + this->float_data[Details::ETEM_EM_OVER_SUMPT3TRK] = etEMScale1 / sumpT3Trk; + } + if (sumpT != 0) { + this->float_data[Details::ETHAD_EM_OVER_SUMPT] = etEMScale2 / sumpT; + this->float_data[Details::ETEM_EM_OVER_SUMPT] = etEMScale1 / sumpT; + } + + uint8_t numberOfTRTHighThresholdHits; + tauJet.track(0)->summaryValue(numberOfTRTHighThresholdHits, xAOD::numberOfTRTHighThresholdHits); + uint8_t numberOfTRTHits; + tauJet.track(0)->summaryValue(numberOfTRTHits, xAOD::numberOfTRTHits); + uint8_t numberOfTRTHighThresholdOutliers; + tauJet.track(0)->summaryValue(numberOfTRTHighThresholdOutliers, xAOD::numberOfTRTHighThresholdOutliers); + uint8_t numberOfTRTOutliers; + tauJet.track(0)->summaryValue(numberOfTRTOutliers, xAOD::numberOfTRTOutliers); + this->float_data[Details::TRT_NHT_OVER_NLT] = + (numberOfTRTHits + numberOfTRTOutliers) > 0 ? + float( numberOfTRTHighThresholdHits + numberOfTRTHighThresholdOutliers) / float(numberOfTRTHits + numberOfTRTOutliers) : LOW_NUMBER; + } + + //Pi0 Cluster finding variables + TauPi0Clusters tpc = TauPi0Clusters(tauJet); + + this->float_data[Details::PI0CL1_PT] = tpc.get_cl1_Pt(); + this->float_data[Details::PI0CL1_ETA] = tpc.get_cl1_Eta(); + this->float_data[Details::PI0CL1_PHI] = tpc.get_cl1_Phi(); + + this->float_data[Details::PI0CL2_PT] = tpc.get_cl2_Pt(); + this->float_data[Details::PI0CL2_ETA] = tpc.get_cl2_Eta(); + this->float_data[Details::PI0CL2_PHI] = tpc.get_cl2_Phi(); + + this->float_data[Details::VISTAU_PI0CL_PT] = tpc.get_tau_vis_Pt(); + this->float_data[Details::VISTAU_PI0CL_ETA] = tpc.get_tau_vis_Eta(); + this->float_data[Details::VISTAU_PI0CL_PHI] = tpc.get_tau_vis_Phi(); + this->float_data[Details::VISTAU_PI0CL_M] = tpc.get_tau_vis_M(); + this->float_data[Details::TAU_PI0_VISTAU_M] = tpc.get_tau_vis_M(); + this->float_data[Details::TAU_PTRATIO] = (tauJet.pt() != 0) ? tpc.get_tau_vis_Pt() / tauJet.pt() : LOW_NUMBER; + // this->int_data[Details::TAU_PI0_N] = 0; //this guy is set elsewhere + + // TRACK_ISO + float track_iso(0.); + for (unsigned int i_track(0); i_track < tauJet.nWideTracks(); ++i_track) { + track_iso += tauJet.wideTrack(i_track)->pt(); + } + this->float_data[Details::TRACK_ISO] = track_iso; + + //Corrected CENTRALITY FRACTION and FTRK + float centFrac; + tauJet.detail(TauJetParameters::centFrac, centFrac); + float corrFtrk = this->float_data[Details::PTLEADTRKOVERET]; + + int nVtx = this->int_event_data[Details::NUM_PILEUP_AND_PRIMARY_VERTICES]; + + if (nVtx != int(LOW_NUMBER) && !this->doTrigger) { + if (tauJet.pt() < 80 * GeV) + centFrac = centFrac + 0.003 * nVtx; + + if (corrFtrk != float(LOW_NUMBER)) + corrFtrk = corrFtrk + 0.003 * nVtx; + } + + this->float_data[Details::CORRCENTFRAC] = centFrac; + this->float_data[Details::CORRFTRK] = corrFtrk; + + return true; +} + +// non-const version of update +bool TauDetailsManager::update_with_edm(xAOD::TauJet& tauJet) +{ + // update first the internal storage of the DetailsManager and calculate variables + if (!this->update(tauJet)) return false; + + // update now the tau itself + tauJet.setDetail(TauJetParameters::ptRatioEflowTopo, static_cast<float>(this->float_data[Details::TAU_PTRATIO])); + tauJet.setDetail(TauJetParameters::mEflowTopo, static_cast<float>(this->float_data[Details::TAU_PI0_VISTAU_M])); + tauJet.setDetail(TauJetParameters::etEflowTopo, static_cast<float>(this->float_data[Details::VISTAU_PI0CL_PT])); + //nPi0 saved in TauDetailsManager::setPi0(int nPi0) method + return true; +} + +// Var Getters +const float* TauDetailsManager::getFloatDetailAddress(Details::FloatTauDetail detail) const +{ + return &this->float_data[detail]; +} + +const int* TauDetailsManager::getIntDetailAddress(Details::IntTauDetail detail) const +{ + return &this->int_data[detail]; +} + +const float* TauDetailsManager::getFloatDetailAddress(Details::FloatEventDetail detail) const +{ + return &this->float_event_data[detail]; +} + +const int* TauDetailsManager::getIntDetailAddress(Details::IntEventDetail detail) const +{ + return &this->int_event_data[detail]; +} + +float TauDetailsManager::getFloatDetailValue(Details::FloatTauDetail detail) const +{ + return this->float_data[detail]; +} + +int TauDetailsManager::getIntDetailValue(Details::IntTauDetail detail) const +{ + return this->int_data[detail]; +} + +float TauDetailsManager::getFloatDetailValue(Details::FloatEventDetail detail) const +{ + return this->float_event_data[detail]; +} + +int TauDetailsManager::getIntDetailValue(Details::IntEventDetail detail) const +{ + return this->int_event_data[detail]; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/TauDiscriBuilder.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauDiscriBuilder.cxx new file mode 100644 index 00000000000..01a9407dccf --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauDiscriBuilder.cxx @@ -0,0 +1,209 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauDiscriBuilder.cxx +// package: PhysicsAnalysis/TauID/TauDiscriminant +// authors: M. Wolter, A. Kaczmarska, Noel Dawe +// date: 13 March 2008 +//----------------------------------------------------------------------------- + +#include "TauDiscriminant/TauDiscriBuilder.h" +#include "TauDiscriminant/TauDiscriToolBase.h" +#include "TauDiscriminant/FakeTauBits.h" +#include "TauDiscriminant/FakeTauScores.h" + +#include "xAODTau/TauJetContainer.h" +#include "xAODTau/TauJet.h" +// #include "tauEvent/TauCommonDetails.h" +#include "xAODTau/TauDefs.h" + +#include "AthenaBaseComps/AthMessaging.h" +#include "GaudiKernel/ListItem.h" +#include "StoreGate/StoreGateSvc.h" + +using namespace xAOD; +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +TauDiscriBuilder::TauDiscriBuilder( const std::string &name, + ISvcLocator * pSvcLocator ) : + AthAlgorithm( name, pSvcLocator ), + tauInputContainerName( "TauContainer" ), + tools( this ), //make tools private + manager(0) +{ + declareProperty( "container", tauInputContainerName ); + declareProperty( "tools", tools, "List of TauDiscriToolBase tools" ); +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +TauDiscriBuilder::~TauDiscriBuilder() +{ +} + +//----------------------------------------------------------------------------- +// Initializer +//----------------------------------------------------------------------------- +StatusCode TauDiscriBuilder::initialize() +{ + StatusCode sc = StatusCode::SUCCESS; + + this->manager = new TauDetailsManager(&*evtStore()); + + //------------------------------------------------------------------------- + // No tools allocated! + //------------------------------------------------------------------------- + if( this->tools.size() == 0 ) + { + return StatusCode::FAILURE; + } + + //------------------------------------------------------------------------- + // Allocate tools + //------------------------------------------------------------------------- + ToolHandleArray<TauDiscriToolBase>::iterator tool_it(this->tools.begin()); + ToolHandleArray<TauDiscriToolBase>::iterator tool_end(this->tools.end()); + ATH_MSG_INFO("------------------------------------"); + ATH_MSG_INFO("List of tools in execution sequence:"); + unsigned int tool_count(0); + + for(; tool_it != tool_end; ++tool_it ) + { + if( tool_it->retrieve().isFailure() ) + { + ATH_MSG_WARNING("Cannot find tool named <" << *tool_it << ">"); + } + else + { + ++tool_count; + ATH_MSG_INFO(tool_it->name()); + if( (*tool_it)->prepare(*this->manager).isFailure() ) + { + ATH_MSG_FATAL("Initialization failed in tool " << tool_it->name()); + return sc; + } + } + } + ATH_MSG_INFO("------------------------------------"); + + if(tool_count == 0) + { + ATH_MSG_ERROR("Did not allocate any tool!"); + return StatusCode::FAILURE; + } + return sc; +} + +//----------------------------------------------------------------------------- +// Finalizer +//----------------------------------------------------------------------------- +StatusCode TauDiscriBuilder::finalize() +{ + delete this->manager; + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Execution +//----------------------------------------------------------------------------- +StatusCode TauDiscriBuilder::execute() +{ + xAOD::TauJetContainer *tau_container; + const xAOD::TauJetContainer *const_tau_container; + StatusCode sc = evtStore()->retrieve(const_tau_container, this->tauInputContainerName); + + tau_container = const_cast<TauJetContainer *>(const_tau_container); + + if (sc.isFailure() || ! tau_container) + { + ATH_MSG_WARNING("No input tau container found!"); + sc = StatusCode::SUCCESS; + return sc; + } + ATH_MSG_VERBOSE("Processing input tau Container Name = " << this->tauInputContainerName); + + FakeTauBits* fakeBits(0); + FakeTauBitsContainer* fakeBitsContainer(new FakeTauBitsContainer()); + + FakeTauScores* fakeScores(0); + FakeTauScoresContainer* fakeScoresContainer(new FakeTauScoresContainer()); + + // Update event-based variables + if (!this->manager->updateEvent()) + { + ATH_MSG_WARNING("Updating event-based variables in TauDetailsManager failed! Do not trust discriminant outputs!"); + return StatusCode::SUCCESS; + } + + xAOD::TauJetContainer::iterator tau_it(tau_container->begin()); + xAOD::TauJetContainer::iterator tau_end(tau_container->end()); + + // Loop over tau's: + for (; tau_it != tau_end; ++tau_it) + { + if (!this->manager->update_with_edm(**tau_it)) + { + ATH_MSG_WARNING("Updating tau-based variables in TauDetailsManager failed! Do not trust discriminant outputs!"); + return StatusCode::SUCCESS; + } + + ATH_MSG_VERBOSE(*this->manager); + + fakeBits = new FakeTauBits(*tau_it); + fakeScores = new FakeTauScores(*tau_it); + + //----------------------------------------------------------------- + // Process the candidate + //----------------------------------------------------------------- + ToolHandleArray<TauDiscriToolBase>::iterator tool_it(this->tools.begin()); + ToolHandleArray<TauDiscriToolBase>::iterator tool_end(this->tools.end()); + + //----------------------------------------------------------------- + // Loop stops when Failure indicated by one of the tools + //----------------------------------------------------------------- + for(; tool_it != tool_end; ++tool_it ) + { + ATH_MSG_VERBOSE("Invoking tool " << tool_it->name()); + sc = (*tool_it)->execute( *tau_it, fakeBits, fakeScores); + if( sc.isFailure() ) + { + ATH_MSG_FATAL("Execute failed in tool " << tool_it->name()); + return sc; + } + // TEMPORARY HACK + ATH_MSG_VERBOSE("Tool name: "<<tool_it->name()); + if(tool_it->name() == "TauPi0BDT") + { + ATH_MSG_VERBOSE("HACK FOR NPI0S"); + float Primary = fakeScores->getScore(TauScore::BDT_PI0_PRIMARY); + float Secondary = fakeScores->getScore(TauScore::BDT_PI0_SECONDARY); + int nPi0s = 0; + if (Primary < 0.465) nPi0s += 1; + if (Secondary < 0.565) nPi0s += 1; + + this->manager->setNpi0(**tau_it,nPi0s); + } + ATH_MSG_VERBOSE(*this->manager); + + } + fakeBitsContainer->push_back(fakeBits); + fakeScoresContainer->push_back(fakeScores); + } + + sc = evtStore()->record(fakeBitsContainer, "FakeTauBitsContainer", false); + if (sc.isFailure()) + { + ATH_MSG_WARNING("Could not record FakeTauBitsContainer in StoreGate!"); + return StatusCode::FAILURE; + } + sc = evtStore()->record(fakeScoresContainer, "FakeTauScoresContainer", false); + if (sc.isFailure()) + { + ATH_MSG_WARNING("Could not record FakeTauScoresContainer in StoreGate!"); + } + return sc; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/TauDiscriToolBase.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauDiscriToolBase.cxx new file mode 100644 index 00000000000..8c2e574a6fe --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauDiscriToolBase.cxx @@ -0,0 +1,14 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauDiscriToolBase.cxx +// package: TauDiscriminant +// authors: M. Wolter, A. Kaczmarska +// date: 13 March 2008 +//----------------------------------------------------------------------------- + +#include "TauDiscriminant/TauDiscriToolBase.h" + + diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/TauEleBDT.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauEleBDT.cxx new file mode 100644 index 00000000000..cd9576f04f6 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauEleBDT.cxx @@ -0,0 +1,209 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Tool for BDT analysis. + * + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#include "TauDiscriminant/TauEleBDT.h" +#include "TH2F.h" +#include <PathResolver/PathResolver.h> + +using namespace xAOD; + +StatusCode TauEleBDT::prepare(const TauDetailsManager& manager) +{ + if (this->eleBDTFile != "") + { + string eleBDTPath = PathResolver::find_file(this->eleBDTFile, "DATAPATH"); + if(eleBDTPath == "") + { + msg(MSG::FATAL) << "File: " << this->eleBDTFile << " not found! " << endreq; + return StatusCode::FAILURE; + } + + this->eleBDT = new MethodBDT("TauBDT:EleBDT"); + this->eleBDT->setDetails(manager); + + if (!this->eleBDT->build(eleBDTPath)) + { + msg(MSG::FATAL) << "Loading electron BDT file " << eleBDTPath << " failed!" << endreq; + return StatusCode::FAILURE; + } + + if (this->eleBitsFile != "") + { + string eleBitsPath = PathResolver::find_file(this->eleBitsFile, "DATAPATH"); + if(eleBitsPath == "") + { + msg(MSG::FATAL) << "File: " << this->eleBitsFile << " not found! " << endreq; + return StatusCode::FAILURE; + } + + this->eleBits = new MethodCuts("TauBDT:EleBits"); + this->eleBits->setDetails(manager); + this->eleBits->addVariable("BDT",&(this->eleScore),'F'); + + if (!this->eleBits->build(eleBitsPath)) + { + msg(MSG::FATAL) << "Loading ele bits file " << eleBitsPath << " failed!" << endreq; + return StatusCode::FAILURE; + } + } + if(this->eleBitsRootFile != ""){ + string eleBitsRootPath = PathResolver::find_file(this->eleBitsRootFile, "DATAPATH"); + if(eleBitsRootPath == "") + { + msg(MSG::FATAL) << "File: " << this->eleBitsRootFile << " not found! " << endreq; + return StatusCode::FAILURE; + } + + + this->cutsFile = new TFile(eleBitsRootPath.c_str()); + if(this->cutsFile){ + this->hloose = (TH2F*)this->cutsFile->Get("h2_BDTEleDecision_pteta_loose"); + this->hmedium = (TH2F*)this->cutsFile->Get("h2_BDTEleDecision_pteta_medium"); + this->htight = (TH2F*)this->cutsFile->Get("h2_BDTEleDecision_pteta_tight"); + } + + } + else + { + msg(MSG::FATAL) << "No BDT bits file was specified!" << endreq; + return StatusCode::FAILURE; + } + + + } + else + { + msg(MSG::FATAL) << "No BDTs were initialized!" << endreq; + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + +StatusCode TauEleBDT::execute(xAOD::TauJet *tauJet, FakeTauBits* /*bits*/, FakeTauScores* /*scores*/) +{ + +// Analysis::TauPID* tauJetID = tauJet->tauID(); + + // Initialize scores + tauJet->setDiscriminant(TauJetParameters::BDTEleScore, 0.); + + // Initialize bits + tauJet->setIsTau(TauJetParameters::EleBDTLoose, 0); + tauJet->setIsTau(TauJetParameters::EleBDTMedium, 0); + tauJet->setIsTau(TauJetParameters::EleBDTTight, 0); + + // do not assign a meaningful score for tau1P3P-only candidates. return. + + + // Set the response of the electron BDT + if (this->eleBDT) + { + this->eleScore = this->eleBDT->response(); + if (msgLvl(MSG::VERBOSE)) + { + msg(MSG::VERBOSE) << "BDTEleScore: " << this->eleScore << endreq; + } + if (this->eleScore < 0. || this->eleScore > 1.) + { + msg(MSG::ERROR) << "Error in computing BDTElecScore!" << endreq; + } + tauJet->setDiscriminant(TauJetParameters::BDTEleScore, this->eleScore); + } + + // if (this->eleBDT && this->eleBits) SL: comment out, set bits by hand + if (this->eleBDT) + { + + // SL: set bits by hand, do not use bits file + //tauJetID->setIsTau(TauJetParameters::EleBDTLoose, this->eleBits->response(0)); + //tauJetID->setIsTau(TauJetParameters::EleBDTMedium, this->eleBits->response(1)); + //tauJetID->setIsTau(TauJetParameters::EleBDTTight, this->eleBits->response(2)); + + if (tauJet->nTracks() == 1){ + double eta = fabs(tauJet->track(0)->eta()); + double pt = tauJet->pt(); + + if(!this->cutsFile) { + msg(MSG::ERROR)<<"Cannot open EleBDT cut file"<<endreq; + tauJet->setIsTau(TauJetParameters::EleBDTLoose, 0 ); + tauJet->setIsTau(TauJetParameters::EleBDTMedium, 0 ); + tauJet->setIsTau(TauJetParameters::EleBDTTight, 0 ); + + return StatusCode::SUCCESS; + } + + if(!hloose || !hmedium || !htight){ + msg(MSG::ERROR)<<"Cannot get EleBDT cut histograms"<<endreq; + tauJet->setIsTau(TauJetParameters::EleBDTLoose, 0 ); + tauJet->setIsTau(TauJetParameters::EleBDTMedium, 0 ); + tauJet->setIsTau(TauJetParameters::EleBDTTight, 0 ); + + + return StatusCode::SUCCESS; + + } + + if(pt/1000. > 799) pt = 799*1000.0; + if(eta > 2.99) eta = 2.99; + + float score_loose = hloose->GetBinContent(hloose->FindBin(pt/1000.,eta)); + bool failed_loose = this->eleScore < score_loose; + + float score_medium = hmedium->GetBinContent(hmedium->FindBin(pt/1000.,eta)); + bool failed_medium = this->eleScore < score_medium; + + float score_tight = htight->GetBinContent(htight->FindBin(pt/1000.,eta)); + bool failed_tight = this->eleScore < score_tight; + + tauJet->setIsTau(TauJetParameters::EleBDTLoose, failed_loose ); + tauJet->setIsTau(TauJetParameters::EleBDTMedium, failed_medium ); + tauJet->setIsTau(TauJetParameters::EleBDTTight, failed_tight ); + + + + + + + } + else if(tauJet->nTracks() > 1){ + tauJet->setIsTau(TauJetParameters::EleBDTLoose, 0 ); + tauJet->setIsTau(TauJetParameters::EleBDTMedium, 0 ); + tauJet->setIsTau(TauJetParameters::EleBDTTight, 0 ); + + + + } + + if (msgLvl(MSG::VERBOSE)) + { + msg(MSG::VERBOSE) << "Passes ele loose: " << tauJet->isTau(TauJetParameters::EleBDTLoose) << endreq; + msg(MSG::VERBOSE) << "Passes ele medium: " << tauJet->isTau(TauJetParameters::EleBDTMedium) << endreq; + msg(MSG::VERBOSE) << "Passes ele tight: " << tauJet->isTau(TauJetParameters::EleBDTTight) << endreq; + } + } + + return StatusCode::SUCCESS; +} + +StatusCode TauEleBDT::finalize() +{ + if(this->cutsFile){ + this->cutsFile->Close(); + delete this->cutsFile; + //delete this->hloose; + //delete this->hmedium; + //delete this->htight; + } + + delete this->eleBDT; + delete this->eleBits; + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/TauJetBDT.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauJetBDT.cxx new file mode 100644 index 00000000000..d532cab8ed4 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauJetBDT.cxx @@ -0,0 +1,245 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Tool for BDT analysis. + * + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#include "TauDiscriminant/TauJetBDT.h" + +using namespace xAOD; + +StatusCode TauJetBDT::prepare(const TauDetailsManager& manager) +{ + if (this->jetBDTFile != "") + { + string jetBDTPath = PathResolver::find_file(this->jetBDTFile, "DATAPATH"); + + if(jetBDTPath == "") + { + msg(MSG::FATAL) << "File: " << this->jetBDTFile << " not found! " << endreq; + return StatusCode::FAILURE; + } + + this->jetBDT = new MethodBDT("TauBDT:JetBDT"); + this->jetBDT->setDetails(manager); + + if (!this->jetBDT->build(jetBDTPath)) + { + msg(MSG::FATAL) << "Loading jet BDT file " << jetBDTPath << " failed!" << endreq; + return StatusCode::FAILURE; + } + + if (this->jetSigBitsFile != "") + { + string jetSigBitsPath = PathResolver::find_file(this->jetSigBitsFile, "DATAPATH"); + if(jetSigBitsPath == "") + { + msg(MSG::FATAL) << "File: " << this->jetSigBitsFile << " not found! " << endreq; + return StatusCode::FAILURE; + } + + this->jetSigBits = new MethodCuts("TauBDT:JetSigBits"); + this->jetSigBits->setDetails(manager); + this->jetSigBits->addVariable("BDT",&(this->jetScore),'F'); + + if (!this->jetSigBits->build(jetSigBitsPath)) + { + msg(MSG::FATAL) << "Loading jet bits file " << jetSigBitsPath << " failed!" << endreq; + return StatusCode::FAILURE; + } + } + + // Flat signal transformed jet score + if (this->jetSigTransFile != "") + { + string jetSigTransPath = PathResolver::find_file(this->jetSigTransFile, "DATAPATH"); + + if(jetSigTransPath == "") + { + msg(MSG::FATAL) << "File: " << this->jetSigTransFile << " not found! " << endreq; + return StatusCode::FAILURE; + } + + this->jetSigTrans = new MethodTransform("TauBDT:JetBDT:SignalTranform"); + this->jetSigTrans->setDetails(manager); + this->jetSigTrans->addVariable("BDT",&(this->jetScore),'F'); + + if (!this->jetSigTrans->build(jetSigTransPath)) + { + msg(MSG::FATAL) << "Loading jet BDT signal transformation file " << jetSigTransPath << " failed!" << endreq; + return StatusCode::FAILURE; + } + } + + // Flat background transformed jet score + if (this->jetBkgTransFile != "") + { + string jetBkgTransPath = PathResolver::find_file(this->jetBkgTransFile, "DATAPATH"); + + if(jetBkgTransPath == "") + { + msg(MSG::FATAL) << "File: " << this->jetBkgTransFile << " not found! " << endreq; + return StatusCode::FAILURE; + } + + this->jetBkgTrans = new MethodTransform("TauBDT:JetBDT:BackgroundTranform"); + this->jetBkgTrans->setDetails(manager); + this->jetBkgTrans->addVariable("BDT",&(this->jetScore),'F'); + + if (!this->jetBkgTrans->build(jetBkgTransPath)) + { + msg(MSG::FATAL) << "Loading jet BDT background transformation file " << jetBkgTransPath << " failed!" << endreq; + return StatusCode::FAILURE; + } + } + if (this->jetBkgBitsFile != "") + { + string jetBkgBitsPath = PathResolver::find_file(this->jetBkgBitsFile, "DATAPATH"); + if(jetBkgBitsPath == "") + { + msg(MSG::FATAL) << "File: " << this->jetBkgBitsFile << " not found! " << endreq; + return StatusCode::FAILURE; + } + + this->jetBkgBits = new MethodCuts("TauBDT:JetBkgBits"); + this->jetBkgBits->setDetails(manager); + this->jetBkgBits->addVariable("BDT",&(this->jetScore),'F'); + + if (!this->jetBkgBits->build(jetBkgBitsPath)) + { + msg(MSG::FATAL) << "Loading jet bits file " << jetBkgBitsPath << " failed!" << endreq; + return StatusCode::FAILURE; + } + } + } + else + { + msg(MSG::FATAL) << "No BDTs were initialized!" << endreq; + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + +StatusCode TauJetBDT::execute(xAOD::TauJet *tauJet, FakeTauBits* /*bits*/, FakeTauScores* /*scores*/) +{ + +// Analysis::TauPID* tauJetID = tauJet->tauID(); + bool loose, medium, tight; + + // Initialize scores + tauJet->setDiscriminant(TauJetParameters::BDTJetScore, static_cast<float>(0.)); + tauJet->setDiscriminant(TauJetParameters::BDTJetScoreSigTrans, static_cast<float>(0.)); + tauJet->setDiscriminant(TauJetParameters::BDTJetScoreBkgTrans, static_cast<float>(0.)); + + // Initialize bits + tauJet->setIsTau(TauJetParameters::JetBDTSigLoose, false); + tauJet->setIsTau(TauJetParameters::JetBDTSigMedium, false); + tauJet->setIsTau(TauJetParameters::JetBDTSigTight, false); + + tauJet->setIsTau(TauJetParameters::JetBDTBkgLoose, false); + tauJet->setIsTau(TauJetParameters::JetBDTBkgMedium, false); + tauJet->setIsTau(TauJetParameters::JetBDTBkgTight, false); + + // do not assign a meaningful score for tau1P3P-only candidates. return. + + + // Set the response of the jet BDT + if (this->jetBDT) + { + + + this->jetScore = this->jetBDT->response(); + if (msgLvl(MSG::VERBOSE)) + { + msg(MSG::VERBOSE) << "BDTJetScore: " << this->jetScore << endreq; + } + if (this->jetScore < 0. || this->jetScore > 1.) + { + msg(MSG::ERROR) << "Error in computing BDTJetScore!" << endreq; + } + tauJet->setDiscriminant(TauJetParameters::BDTJetScore, this->jetScore); + } + else + { + tauJet->setDiscriminant(TauJetParameters::BDTJetScore, 0.); + } + + if (this->jetBDT && this->jetSigBits) + { + loose = this->jetSigBits->response(0); + medium = this->jetSigBits->response(1); + tight = this->jetSigBits->response(2); + tauJet->setIsTau(TauJetParameters::JetBDTSigLoose, loose); + tauJet->setIsTau(TauJetParameters::JetBDTSigMedium, medium); + tauJet->setIsTau(TauJetParameters::JetBDTSigTight, tight); + if (msgLvl(MSG::DEBUG)) + { + if (!((!loose && !medium && !tight) || (loose && !medium && !tight) || (loose && medium && !tight) || (loose && medium && tight))) + { + msg(MSG::VERBOSE) << "Bad bits!" << endreq; + } + msg(MSG::DEBUG) << "ET: " << tauJet->pt() << endreq; + msg(MSG::DEBUG) << "jet sig loose: " << tauJet->isTau(TauJetParameters::JetBDTSigLoose) << endreq; + msg(MSG::DEBUG) << "jet sig medium: " << tauJet->isTau(TauJetParameters::JetBDTSigMedium) << endreq; + msg(MSG::DEBUG) << "jet sig tight: " << tauJet->isTau(TauJetParameters::JetBDTSigTight) << endreq; + } + } + + if (this->jetSigTrans) + { + float jetSigTransScore(this->jetSigTrans->response()); + if (msgLvl(MSG::VERBOSE)) + { + msg(MSG::VERBOSE) << "Signal Transformed BDTJetScore: " << jetSigTransScore << endreq; + } + tauJet->setDiscriminant(TauJetParameters::BDTJetScoreSigTrans, jetSigTransScore); + } + + if (this->jetBkgTrans) + { + float jetBkgTransScore(this->jetBkgTrans->response()); + if (msgLvl(MSG::VERBOSE)) + { + msg(MSG::VERBOSE) << "Background Transformed BDTJetScore: " << jetBkgTransScore << endreq; + } + tauJet->setDiscriminant(TauJetParameters::BDTJetScoreBkgTrans, jetBkgTransScore); + } + + if (this->jetBDT && this->jetBkgBits) + { + loose = this->jetBkgBits->response(0); + medium = this->jetBkgBits->response(1); + tight = this->jetBkgBits->response(2); + tauJet->setIsTau(TauJetParameters::JetBDTBkgLoose, loose); + tauJet->setIsTau(TauJetParameters::JetBDTBkgMedium, medium); + tauJet->setIsTau(TauJetParameters::JetBDTBkgTight, tight); + if (msgLvl(MSG::VERBOSE)) + { + if (!((!loose && !medium && !tight) || (loose && !medium && !tight) || (loose && medium && !tight) || (loose && medium && tight))) + { + msg(MSG::VERBOSE) << "Bad bits!" << endreq; + } + msg(MSG::VERBOSE) << "ET: " << tauJet->pt() << endreq; + msg(MSG::VERBOSE) << "jet bkg loose: " << tauJet->isTau(TauJetParameters::JetBDTBkgLoose) << endreq; + msg(MSG::VERBOSE) << "jet bkg medium: " << tauJet->isTau(TauJetParameters::JetBDTBkgMedium) << endreq; + msg(MSG::VERBOSE) << "jet bkg tight: " << tauJet->isTau(TauJetParameters::JetBDTBkgTight) << endreq; + } + } + + return StatusCode::SUCCESS; +} + +StatusCode TauJetBDT::finalize() +{ + delete this->jetBDT; + delete this->jetSigBits; + delete this->jetBkgBits; + delete this->jetSigTrans; + delete this->jetBkgTrans; + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/TauLLH.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauLLH.cxx new file mode 100644 index 00000000000..3b966a1ce7e --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauLLH.cxx @@ -0,0 +1,85 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * file: TauLLH.cxx + * + * Author: Martin Flechl (mflechl@cern.ch) + * + */ + +#include "TauDiscriminant/TauLLH.h" +#include "xAODTau/TauJetContainer.h" +#include "xAODTau/TauJet.h" +// #include "tauEvent/TauCommonDetails.h" +// #include "tauEvent/TauPID.h" +// #include "tauEvent/TauJetParameters.h" +#include "xAODTau/TauDefs.h" +#include <PathResolver/PathResolver.h> + +using namespace xAOD; + +//----------------------------------------------------------------------------- +// Initializer +//----------------------------------------------------------------------------- +StatusCode TauLLH::prepare(const TauDetailsManager& manager) +{ + //defllh cannot be used yet + // m_defllh = new MethodLLH("llhdef"); + m_safellh = new MethodLLH("llhsafe"); + //m_safellh = new MethodLLH("llhsafe",true); + + // m_defllh->setDetails(this->manager); + m_safellh->setDetails(manager); + + std::string jetPDFPath = PathResolver::find_file(m_fileNameJetPDF, "DATAPATH"); + std::string tauPDFPath = PathResolver::find_file(m_fileNameTauPDF, "DATAPATH"); + std::string LMTCutsPath = PathResolver::find_file(m_fileNameLMTCuts, "DATAPATH"); + + + std::string fileNames=tauPDFPath+","+jetPDFPath+","+LMTCutsPath; + if ( !m_safellh->build(fileNames) ) { + ATH_MSG_FATAL("unable to build safe likelihood"); + return StatusCode::FAILURE; + } + + // set trigger flag + m_safellh->setDoTrigger(manager); + + return StatusCode :: SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Finalizer +//----------------------------------------------------------------------------- +StatusCode TauLLH :: finalize() +{ + // delete m_defllh; + delete m_safellh; + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Execution +//----------------------------------------------------------------------------- +StatusCode TauLLH::execute(xAOD::TauJet* tau, FakeTauBits* /*bits*/, FakeTauScores* /*scores*/) +{ +// Analysis::TauPID *p_tauid = tau->tauID(); + + bool loose = m_safellh->response(0); + bool medium = m_safellh->response(1); + bool tight = m_safellh->response(2); + float value = m_safellh->response(3); + + //default llh value + tau->setIsTau(TauJetParameters::TauLlhLoose, loose); + tau->setIsTau(TauJetParameters::TauLlhMedium, medium); + tau->setIsTau(TauJetParameters::TauLlhTight, tight); + tau->setDiscriminant(TauJetParameters::Likelihood, value); + tau->setDiscriminant(TauJetParameters::SafeLikelihood, value); + + return StatusCode :: SUCCESS; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/TauMuonVeto.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauMuonVeto.cxx new file mode 100644 index 00000000000..845b0b4d866 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauMuonVeto.cxx @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TauDiscriminant/TauMuonVeto.h" +#include "xAODTau/TauJetContainer.h" +#include "xAODTau/TauJet.h" +// #include "tauEvent/TauCommonDetails.h" +// #include "tauEvent/TauPID.h" +#include "xAODTau/TauDefs.h" +#include "TauDiscriminant/TauDetails.h" +#include <PathResolver/PathResolver.h> + +using namespace xAOD; +//----------------------------------------------------------------------------- +// Initializer +//----------------------------------------------------------------------------- +StatusCode TauMuonVeto::prepare(const TauDetailsManager& manager) +{ + this->detailsManager = &manager; + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Finalizer +//----------------------------------------------------------------------------- +StatusCode TauMuonVeto::finalize() +{ + return StatusCode::SUCCESS; +} + +bool tauMuonVeto(int ntracks, float EMfrac, float ptEt, float eta) { + + if(ntracks != 1) return false; + if( (eta > -0.1 && eta < 0.1) || (eta > 1.15 && eta < 1.3) ){ + if(EMfrac < 0.15 && ptEt > 0.9) return true; + if(EMfrac > 0.80 && ptEt > 1.0) return true; + } + else { + if(EMfrac < 0.18 && ptEt > 1.9) return true; + if(EMfrac > 0.82 && ptEt < 0.12) return true; + } + return false; + +} + +//----------------------------------------------------------------------------- +// Execution +//----------------------------------------------------------------------------- +StatusCode TauMuonVeto::execute(xAOD::TauJet* tau, FakeTauBits* /*bits*/, FakeTauScores* /*scores*/) +{ + if (!detailsManager) + { + return StatusCode::FAILURE; + } + + float ptEt = detailsManager->getFloatDetailValue(Details::PTLEADTRKOVERET); + float EMfrac = detailsManager->getFloatDetailValue(Details::EMFRACTIONATEMSCALE); + + int ntracks = tau->nTracks(); + float eta = tau->eta(); + + bool muVeto = tauMuonVeto(ntracks, EMfrac, ptEt, eta); + +// Analysis::TauPID *p_tauid = tau->tauID(); + + tau->setIsTau(TauJetParameters::MuonVeto, muVeto); + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/TauPi0BDT.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauPi0BDT.cxx new file mode 100644 index 00000000000..d11b75f17c0 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauPi0BDT.cxx @@ -0,0 +1,107 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * Tool for pi0 BDT analysis. + * + * Author: Noel Dawe (Noel%dot%Dawe%at%cern%dot%ch) + */ + +#include "TauDiscriminant/TauPi0BDT.h" + +StatusCode TauPi0BDT::prepare(const TauDetailsManager& manager) +{ + // Primary pi0 BDT preparation + if (this->pi0BDTPrimaryFile != "") + { + string pi0BDTPrimaryPath = PathResolver::find_file(this->pi0BDTPrimaryFile, "DATAPATH"); + if(pi0BDTPrimaryPath == "") + { + msg(MSG::FATAL) << "File: " << this->pi0BDTPrimaryFile << " not found! " << endreq; + return StatusCode::FAILURE; + } + + this->pi0BDTPrimary = new MethodBDT("TauBDT:Pi0BDTPrimary"); + this->pi0BDTPrimary->addVariable("EMPOverTrkSysP", manager.getFloatDetailAddress(Details::EMPOVERTRKSYSP),'F'); + this->pi0BDTPrimary->addVariable("ChPiEMEOverCaloEME", manager.getFloatDetailAddress(Details::CHPIEMEOVERCALOEME),'F'); + this->pi0BDTPrimary->addVariable("PSSFraction", manager.getFloatDetailAddress(Details::PSSFRACTION),'F'); + this->pi0BDTPrimary->addVariable("EtOverPtLeadTrk", manager.getFloatDetailAddress(Details::ETOVERPTLEADTRK),'F'); + //this->pi0BDTPrimary->addVariable("mEflow", manager.getFloatDetailAddress(Details::MEFLOW),'F'); + this->pi0BDTPrimary->addVariable("nStrip", manager.getIntDetailAddress(Details::NSTRIP),'I'); + + + if (!this->pi0BDTPrimary->build(pi0BDTPrimaryPath)) + { + msg(MSG::FATAL) << "Loading primary pi0 BDT file " << pi0BDTPrimaryPath << " failed!" << endreq; + return StatusCode::FAILURE; + } + } + + // Secondary pi0 BDT preparation + if (this->pi0BDTSecondaryFile != "") + { + string pi0BDTSecondaryPath = PathResolver::find_file(this->pi0BDTSecondaryFile, "DATAPATH"); + if(pi0BDTSecondaryPath == "") + { + msg(MSG::FATAL) << "File: " << this->pi0BDTSecondaryFile << " not found! " << endreq; + return StatusCode::FAILURE; + } + + this->pi0BDTSecondary = new MethodBDT("TauBDT:Pi0BDTSecondary"); + this->pi0BDTSecondary->addVariable("EMPOverTrkSysP", manager.getFloatDetailAddress(Details::EMPOVERTRKSYSP),'F'); + this->pi0BDTSecondary->addVariable("ChPiEMEOverCaloEME", manager.getFloatDetailAddress(Details::CHPIEMEOVERCALOEME),'F'); + this->pi0BDTSecondary->addVariable("PSSFraction", manager.getFloatDetailAddress(Details::PSSFRACTION),'F'); + this->pi0BDTSecondary->addVariable("EtOverPtLeadTrk", manager.getFloatDetailAddress(Details::ETOVERPTLEADTRK),'F'); + //this->pi0BDTSecondary->addVariable("mEflow", manager.getFloatDetailAddress(Details::MEFLOW),'F'); + this->pi0BDTSecondary->addVariable("nStrip", manager.getIntDetailAddress(Details::NSTRIP),'I'); + + if (!this->pi0BDTSecondary->build(pi0BDTSecondaryPath)) + { + msg(MSG::FATAL) << "Loading secondary pi0 BDT file " << pi0BDTSecondaryPath << " failed!" << endreq; + return StatusCode::FAILURE; + } + } + + if (!this->pi0BDTPrimary && !this->pi0BDTSecondary) + { + msg(MSG::FATAL) << "No BDTs were initialized!" << endreq; + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + +StatusCode TauPi0BDT::execute(xAOD::TauJet* /*tauJet*/, FakeTauBits* /*bits*/, FakeTauScores* scores) +{ + // Get primary pi0 BDT score + if (this->pi0BDTPrimary && scores) + { + float pi0BDTPrimaryScore(this->pi0BDTPrimary->response()); + if (msgLvl(MSG::VERBOSE)) + { + msg(MSG::VERBOSE) << "Primary Pi0 BDT score: " << pi0BDTPrimaryScore << endreq; + } + scores->setScore(TauScore::BDT_PI0_PRIMARY, pi0BDTPrimaryScore); + } + + // Get secondary pi0 BDT score + if (this->pi0BDTSecondary && scores) + { + float pi0BDTSecondaryScore(this->pi0BDTSecondary->response()); + if (msgLvl(MSG::VERBOSE)) + { + msg(MSG::VERBOSE) << "Secondary Pi0 BDT score: " << pi0BDTSecondaryScore << endreq; + } + scores->setScore(TauScore::BDT_PI0_SECONDARY, pi0BDTSecondaryScore); + } + + return StatusCode::SUCCESS; +} + +StatusCode TauPi0BDT::finalize() +{ + delete this->pi0BDTPrimary; + delete this->pi0BDTSecondary; + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/TauPi0Clusters.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauPi0Clusters.cxx new file mode 100644 index 00000000000..b496a1a0587 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/TauPi0Clusters.cxx @@ -0,0 +1,185 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + /** + * file: TauPi0Clusters.cxx + * + * Author: Michel Trottier-McDonald (mtm@cern.ch) + */ + +#include "TauDiscriminant/TauPi0Clusters.h" +#include <utility> + +#include "xAODTau/TauJet.h" +#include "xAODTau/TauJetContainer.h" +#include "xAODTracking/TrackParticle.h" +#include "xAODCaloEvent/CaloClusterContainer.h" +#include "xAODCaloEvent/CaloCluster.h" +#include "AnalysisUtils/AnalysisMisc.h" +#include "xAODTracking/VertexContainer.h" +#include "CLHEP/Geometry/Vector3D.h" +#include "CaloGeoHelpers/CaloSampling.h" +#include "CaloUtils/CaloVertexedCluster.h" + +#include <TLorentzVector.h> + +#include "math.h" + +//--------------------------------------------------------- +// Constructor +//--------------------------------------------------------- +TauPi0Clusters::TauPi0Clusters(const xAOD::TauJet& tauJet) : m_cl1_Pt(0.), + m_cl1_Eta(0.), + m_cl1_Phi(0.), + m_cl2_Pt(0.), + m_cl2_Eta(0.), + m_cl2_Phi(0.), + m_tau_vis_Pt(0.), + m_tau_vis_Eta(0.), + m_tau_vis_Phi(0.), + m_tau_vis_M(0.) +{ + runPi0Finder(tauJet); +} + + + + +//--------------------------------------------------------- +// run Pi0Finder +//--------------------------------------------------------- +void TauPi0Clusters::runPi0Finder(const xAOD::TauJet& tauJet) +{ + //Get tracks + int nTracks = tauJet.nTracks(); + std::vector<TLorentzVector> tracks; + + for(int i = 0; i < nTracks; ++i) + { + float track_Pt = tauJet.track(i)->pt(); + float track_Eta = tauJet.track(i)->eta(); + float track_Phi = tauJet.track(i)->phi(); + + if(track_Pt > 0.0 and track_Eta < 5.0) + { + TLorentzVector newTrack = TLorentzVector(); + newTrack.SetPtEtaPhiM(track_Pt, track_Eta, track_Phi, 0.0); + tracks.push_back(newTrack); + } + } + + + //Get clusters + + std::vector<const xAOD::CaloCluster*> Clusters; + + const xAOD::Jet* pJetSeed = (*tauJet.jetLink()); + xAOD::JetConstituentVector jcv = pJetSeed->getConstituents(); + + xAOD::JetConstituentVector::const_iterator firstcluster = jcv.begin(); + xAOD::JetConstituentVector::const_iterator lastcluster = jcv.end(); + + for ( ; firstcluster != lastcluster; firstcluster++ ) { + const xAOD::CaloCluster *p_cluster = dynamic_cast<const xAOD::CaloCluster*> ((*firstcluster)->rawConstituent()); //to get to cluster-specific variables + if (!p_cluster) continue; + Clusters.push_back(p_cluster); + } + + + + // now insert clusters into event ordered by energy + // this makes it much faster to recalculate cluster-based + // variables in macros later + + int nClusters = int(Clusters.size()); + + std::vector<TLorentzVector> clusters; + std::vector<float> PSSFs; + std::vector<float> EM2Fs; + std::vector<float> EM3Fs; + + if(nClusters > 0) + { + + AnalysisUtils::Sort::e (&Clusters); + + for(int i = 0; i < nClusters; ++i) + { + const xAOD::CaloCluster *p_cluster = Clusters[i]; + // Simplified Sampling information + float PreSampler = p_cluster->eSample(CaloSampling::PreSamplerB) + p_cluster->eSample(CaloSampling::PreSamplerE); + float EMLayer1 = p_cluster->eSample(CaloSampling::EMB1) + p_cluster->eSample(CaloSampling::EME1); + float EMLayer2 = p_cluster->eSample(CaloSampling::EMB2) + p_cluster->eSample(CaloSampling::EME2); + float EMLayer3 = p_cluster->eSample(CaloSampling::EMB3) + p_cluster->eSample(CaloSampling::EME3); + + float Energy = p_cluster->rawE(); + + float PSSF = (PreSampler + EMLayer1)/Energy; + float EM2F = EMLayer2/Energy; + float EM3F = EMLayer3/Energy; + + if(PSSF < 0.) PSSF = 0.; + if(PSSF > 1.) PSSF = 1.; + + if(EM2F < 0.) EM2F = 0.; + if(EM2F > 1.) EM2F = 1.; + + if(EM3F < 0.) EM3F = 0.; + if(EM3F > 1.) EM3F = 1.; + + xAOD::CaloVertexedCluster* clusterCorr; + if (tauJet.vertexLink()) { + // Corrected cluster direction information (leave as jet constituents on purpose!) + clusterCorr = new xAOD::CaloVertexedCluster(*p_cluster, (*tauJet.vertexLink())->position()); + } + else { + //no correction + clusterCorr = new xAOD::CaloVertexedCluster(*p_cluster); + } + + float cluster_Eta = clusterCorr->eta(); + float cluster_Pt = clusterCorr->e()/cosh(cluster_Eta); + float cluster_Phi = clusterCorr->phi(); + + if(cluster_Pt > 0.0 && cluster_Eta < 5.0) + { + TLorentzVector newCluster = TLorentzVector(); + newCluster.SetPtEtaPhiM(cluster_Pt, cluster_Eta, cluster_Phi, 0.0); + clusters.push_back(newCluster); + PSSFs.push_back(PSSF); + EM2Fs.push_back(EM2F); + EM3Fs.push_back(EM3F); + } + + // clean up corrected cluster + if (clusterCorr) delete clusterCorr; + + } + } + + if(nTracks > 0 && nClusters > 0) + { + + Pi0Finder pi0F = Pi0Finder(tracks, clusters, PSSFs, EM2Fs, EM3Fs); + TLorentzVector cl1 = pi0F.pi0TLV1(); + TLorentzVector cl2 = pi0F.pi0TLV2(); + TLorentzVector tau = pi0F.visTauTLV(); + + m_cl1_Pt = cl1.Pt(); + if(m_cl1_Pt > 0.0) + m_cl1_Eta = cl1.Eta(); + m_cl1_Phi = cl1.Phi(); + + m_cl2_Pt = cl2.Pt(); + if(m_cl2_Pt > 0.0) + m_cl2_Eta = cl2.Eta(); + m_cl2_Phi = cl2.Phi(); + + m_tau_vis_Pt = tau.Pt(); + if(m_tau_vis_Pt > 0.0) + m_tau_vis_Eta = tau.Eta(); + m_tau_vis_Phi = tau.Phi(); + m_tau_vis_M = tau.M(); + } +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/components/TauDiscri_entries.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/components/TauDiscri_entries.cxx new file mode 100755 index 00000000000..a7d37c09dd0 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/components/TauDiscri_entries.cxx @@ -0,0 +1,32 @@ +#include "TauDiscriminant/TauDiscriBuilder.h" +#include "TauDiscriminant/TauCutsEleVeto.h" +#include "TauDiscriminant/TauCuts.h" +#include "TauDiscriminant/TauLLH.h" +#include "TauDiscriminant/TauJetBDT.h" +#include "TauDiscriminant/TauEleBDT.h" +#include "TauDiscriminant/TauPi0BDT.h" +#include "TauDiscriminant/TauMuonVeto.h" +#include "GaudiKernel/DeclareFactoryEntries.h" + +DECLARE_ALGORITHM_FACTORY( TauDiscriBuilder ) + +DECLARE_TOOL_FACTORY( TauCutsEleVeto ) +DECLARE_TOOL_FACTORY( TauCuts ) +DECLARE_TOOL_FACTORY( TauLLH ) +DECLARE_TOOL_FACTORY( TauJetBDT ) +DECLARE_TOOL_FACTORY( TauEleBDT ) +DECLARE_TOOL_FACTORY( TauPi0BDT ) +DECLARE_TOOL_FACTORY( TauMuonVeto ) + +DECLARE_FACTORY_ENTRIES(TauDiscriminant) +{ + DECLARE_ALGORITHM( TauDiscriBuilder ) + + DECLARE_TOOL( TauCutsEleVeto ) + DECLARE_TOOL( TauCuts ) + DECLARE_TOOL( TauLLH ) + DECLARE_TOOL( TauJetBDT ) + DECLARE_TOOL( TauEleBDT ) + DECLARE_TOOL( TauPi0BDT ) + DECLARE_TOOL( TauMuonVeto ) +} diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/src/components/TauDiscri_load.cxx b/PhysicsAnalysis/TauID/TauDiscriminant/src/components/TauDiscri_load.cxx new file mode 100755 index 00000000000..e4cf8518b62 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/src/components/TauDiscri_load.cxx @@ -0,0 +1,3 @@ +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(TauDiscriminant) diff --git a/PhysicsAnalysis/TauID/TauDiscriminant/svn-authors b/PhysicsAnalysis/TauID/TauDiscriminant/svn-authors new file mode 100644 index 00000000000..7614aaf23a6 --- /dev/null +++ b/PhysicsAnalysis/TauID/TauDiscriminant/svn-authors @@ -0,0 +1,22 @@ +alibrari = Atlas Librarian <Atlas.Librarian@cern.ch> +end = Noel Dawe <Noel.Dawe@cern.ch> +felzmann = Ulrich Felzmann <ulif@unimelb.edu.au> +jgodfrey = Jennifer Godfrey <Jennifer.Lynn.Godfrey@cern.ch> +mflechl = Martin Flechl <Martin.Flechl@cern.ch> +reece = Ryan Reece <Ryan.Reece@cern.ch> +slai = Stan Lai <Stan.Lai@cern.ch> +wolter = Marcin Wolter <Marcin.Wolter@cern.ch> +derue = Frederic Derue <Frederic.Derue@cern.ch> +kojin = Koji Nakamura <Koji.Nakamura@cern.ch> +morgens = Marcus Morgenstern <marcus.morgenstern@tu-dresden.de> +felixf = Felix Friedrich <felix.friedrich@cern.ch> +pmalecki = Pawel Malecki <pawel.malecki@cern.ch> +mtm = Michel Trottier-McDonald <mta58@sfu.ca> +kongt = KG <tankg@unimelb.edu.au> +jkeller = John Stakely Keller <john.stakely.keller@cern.ch> +rompotis = Nikolaos Rompotis <nikolaos.rompotis@cern.ch> +sbedikia = Susie Bedikian <susie.bedikian@cern.ch> +simonyan = Margar Simonyan <Margar.Simonyan@cern.ch> +apingel = Almut Pingel <almut.pingel@cern.ch> +wahrmund = Unknown Unknown <Unknown@cern.ch> +droussea = David Rousseau <rousseau@lal.in2p3.fr> -- GitLab