00001 #ifndef EGAMMAMVACALIB_EGAMMAMVATREE
00002 #define EGAMMAMVACALIB_EGAMMAMVATREE
00003
00004 #include <functional>
00005 #include <string>
00006 #include <map>
00007 #include <array>
00008 #include <vector>
00009 #include <tuple>
00010 #include <cmath>
00011 #include <set>
00012 #include <cstdint>
00013 #include <numeric>
00014
00015 #include "xAODEgamma/Egamma.h"
00016 #include "xAODEgamma/Electron.h"
00017 #include "xAODEgamma/Photon.h"
00018 #include "xAODEgamma/EgammaxAODHelpers.h"
00019 #include "xAODCaloEvent/CaloCluster.h"
00020
00021 #include <TTree.h>
00022 #include <TLorentzVector.h>
00023
00024 #include <AsgTools/AsgMessaging.h>
00025
00026 #include <egammaMVACalib/egammaMVALayerDepth.h>
00027
00028
00029
00050 #ifndef __CINT__
00051 namespace detail
00052 {
00053
00054
00055
00056 template<typename T> inline std::string ROOT_type_name() {
00057
00058 return ""; }
00059 template<> inline std::string ROOT_type_name<int>() { return "I"; }
00060 template<> inline std::string ROOT_type_name<float>() { return "F"; }
00061 template<> inline std::string ROOT_type_name<bool>() { return "O"; }
00062 }
00063 #endif
00064
00067 class egammaMVATreeEgamma : public TTree, public asg::AsgMessaging
00068 {
00069 public:
00070
00071 egammaMVATreeEgamma(const std::string& name,
00072 const std::string& prefix,
00073 const std::set<std::string>& variables,
00074 bool use_layer_corrected=true);
00075
00076
00077
00078
00079
00080
00081
00085 void update(const xAOD::Egamma* egamma);
00086 void update(const xAOD::Egamma* egamma, const xAOD::CaloCluster* cluster);
00087 private:
00088 void init_variables(const std::set<std::string>& variables);
00089 std::string m_prefix;
00090 bool m_use_layer_corrected = true;
00091 protected:
00092 template<typename T> const T* get_ptr(const std::string&) const
00093 {
00094 static_assert((sizeof(T) == 0), "Type must be int/float");
00095 return nullptr;
00096 }
00097 template<typename T, typename MAPSTRINGFUNCTION, typename CONTAINER>
00098 void search_var_and_add(const std::string& var_name,
00099 const MAPSTRINGFUNCTION& map_string_function,
00100 CONTAINER& container)
00101 {
00102
00103 auto it_function = map_string_function.find(var_name);
00104 if (it_function != map_string_function.end()) {
00105 container.emplace_back(var_name, it_function->second, T());
00106 }
00107 }
00108
00109 template<typename T, typename MAPSTRINGFUNCTION, typename CONTAINER>
00110 void create_structure(const std::set<std::string> vars,
00111 const MAPSTRINGFUNCTION& map_string_function,
00112 CONTAINER& container)
00113 {
00114
00115
00116
00117 for (const auto var_name : vars) {
00118 search_var_and_add<float>(var_name, map_string_function, container);
00119 }
00120
00121 for (auto& it: container) {
00122 ATH_MSG_DEBUG("creating branch " << std::get<0>(it) << " at " << &std::get<2>(it));
00123 const std::string root_type_name = detail::ROOT_type_name<T>();
00124
00125
00126
00127
00128
00129 Branch((std::get<0>(it)).c_str(), &std::get<2>(it));
00130
00131 }
00132 }
00133 protected:
00134 typedef std::tuple<std::string, std::function<float(const xAOD::CaloCluster&)>, float> FloatElement;
00135 std::vector<FloatElement> m_functions_float_from_calo_cluster;
00136 typedef std::tuple<std::string, std::function<float(const xAOD::Egamma&)>, float> FloatElementParticle;
00137 std::vector<FloatElementParticle> m_functions_float_from_particle;
00138 public:
00139 template<typename T> const T& get_ref(const std::string& var_name) const
00140 {
00141 const T* ptr = get_ptr<T>(var_name);
00142 if (!ptr) { throw std::runtime_error("var " + var_name + " not present"); }
00143 return *ptr;
00144 }
00145
00146
00147
00148 };
00149
00150 template<> const float* egammaMVATreeEgamma::get_ptr<float>(const std::string&) const;
00151 template<> const int* egammaMVATreeEgamma::get_ptr<int>(const std::string&) const;
00152
00153 namespace egammaMVATreeHelpers { struct ConversionHelper; }
00154
00155 class egammaMVATreePhoton : public egammaMVATreeEgamma
00156 {
00157 public:
00158 egammaMVATreePhoton(const std::string& name,
00159 const std::set<std::string>& variables,
00160 bool use_layer_corrected=true,
00161 bool force_conversion_to_zero_when_null_photon=false);
00162 void update(const xAOD::Photon* photon);
00163 void update(const xAOD::Photon* photon, const xAOD::CaloCluster* cluster);
00164
00165 private:
00166 bool m_force_conversion_to_zero_when_null_photon;
00167 template<typename T> const T* get_ptr(const std::string& var_name) const {
00168 return egammaMVATreeEgamma::get_ptr<T>(var_name);
00169 }
00170 void init_variables(const std::set<std::string>& variables);
00171 typedef std::tuple<std::string, std::function<float(const xAOD::Photon&)>, float> FloatElement;
00172 typedef std::tuple<std::string, std::function<int(const xAOD::Photon&)>, int> IntElement;
00173 typedef std::tuple<std::string, std::function<float(const egammaMVATreeHelpers::ConversionHelper&)>, float> FloatElementConv;
00174 typedef std::tuple<std::string, std::function<int(const egammaMVATreeHelpers::ConversionHelper&)>, int> IntElementConv;
00175 std::vector<FloatElement> m_functions_float_from_photon;
00176 std::vector<IntElement> m_functions_int_from_photon;
00177 std::vector<FloatElementConv> m_functions_float_from_ConversionHelper;
00178 std::vector<IntElementConv> m_functions_int_from_ConversionHelper;
00179 public:
00180 template<typename T> const T& get_ref(const std::string& var_name) const
00181 {
00182 const T* ptr = get_ptr<T>(var_name);
00183 if (!ptr) { throw std::runtime_error("var " + var_name + " not present"); }
00184 return *ptr;
00185 }
00186
00187
00188
00189 };
00190
00191 template<> const float* egammaMVATreePhoton::get_ptr<float>(const std::string&) const;
00192 template<> const int* egammaMVATreePhoton::get_ptr<int>(const std::string&) const;
00193
00194 class egammaMVATreeElectron : public egammaMVATreeEgamma
00195 {
00196 public:
00197 egammaMVATreeElectron(const std::string& name,
00198 const std::set<std::string>& variables,
00199 bool use_layer_corrected=true);
00200 void update(const xAOD::Electron* electron);
00201 void update(const xAOD::Electron* electron, const xAOD::CaloCluster* cluster);
00202 private:
00203 template<typename T> const T* get_ptr(const std::string& var_name) const {
00204 return egammaMVATreeEgamma::get_ptr<T>(var_name);
00205 }
00206 void init_variables(const std::set<std::string>& variables);
00207 typedef std::tuple<std::string, std::function<float(const xAOD::Electron&)>, float> FloatElement;
00208 typedef std::tuple<std::string, std::function<int(const xAOD::Electron&)>, int> IntElement;
00209 std::vector<FloatElement> m_functions_float_from_electron;
00210 std::vector<IntElement> m_functions_int_from_electron;
00211 public:
00212 template<typename T> const T& get_ref(const std::string& var_name) const
00213 {
00214 const T* ptr = get_ptr<T>(var_name);
00215 if (!ptr) { throw std::runtime_error("var " + var_name + " not present"); }
00216 return *ptr;
00217 }
00218
00219
00220
00221 };
00222
00223 template<> const float* egammaMVATreePhoton::get_ptr<float>(const std::string&) const;
00224 template<> const int* egammaMVATreePhoton::get_ptr<int>(const std::string&) const;
00225
00227 namespace egammaMVATreeHelpers
00228 {
00229
00230
00231
00232 inline float compute_cl_eta(const xAOD::CaloCluster& cluster) { return cluster.eta(); }
00233 inline float compute_cl_phi(const xAOD::CaloCluster& cluster) { return cluster.phi(); }
00234 inline float compute_cl_e(const xAOD::CaloCluster& cluster) { return cluster.e(); }
00235 inline float compute_cl_etaCalo(const xAOD::CaloCluster& cluster) {
00236 double tmp = 0.;
00237 if(! (cluster.retrieveMoment(xAOD::CaloCluster::ETACALOFRAME, tmp))) {
00238 throw std::runtime_error("etaCalo not found in CaloCluster object");
00239 }
00240 return tmp;
00241 }
00242 inline float compute_cl_phiCalo(const xAOD::CaloCluster& cluster) {
00243 double tmp = 0.;
00244 if(! (cluster.retrieveMoment(xAOD::CaloCluster::PHICALOFRAME, tmp))) {
00245 throw std::runtime_error("phiCalo not found in CaloCluster object");
00246 }
00247 return tmp;
00248 }
00249 inline float compute_cl_etas1(const xAOD::CaloCluster& cluster) { return cluster.etaBE(1); }
00250 inline float compute_cl_etas2(const xAOD::CaloCluster& cluster) { return cluster.etaBE(2); }
00251 inline float compute_rawcl_Es0(const xAOD::CaloCluster& cl) { return cl.energyBE(0); }
00252
00253
00254
00255
00256
00257 inline float compute_rawcl_Es1(const xAOD::CaloCluster& cl) { return cl.energyBE(1); }
00258 inline float compute_rawcl_Es2(const xAOD::CaloCluster& cl) { return cl.energyBE(2); }
00259 inline float compute_rawcl_Es3(const xAOD::CaloCluster& cl) { return cl.energyBE(3); }
00260
00261 inline float compute_correctedcl_Es0(const xAOD::CaloCluster& cl) { return cl.isAvailable<double>("correctedcl_Es0") ? cl.auxdataConst<double>("correctedcl_Es0") : cl.energyBE(0); }
00262 inline float compute_correctedcl_Es1(const xAOD::CaloCluster& cl) { return cl.isAvailable<double>("correctedcl_Es1") ? cl.auxdataConst<double>("correctedcl_Es1") : cl.energyBE(1); }
00263 inline float compute_correctedcl_Es2(const xAOD::CaloCluster& cl) { return cl.isAvailable<double>("correctedcl_Es2") ? cl.auxdataConst<double>("correctedcl_Es2") : cl.energyBE(2); }
00264 inline float compute_correctedcl_Es3(const xAOD::CaloCluster& cl) { return cl.isAvailable<double>("correctedcl_Es3") ? cl.auxdataConst<double>("correctedcl_Es3") : cl.energyBE(3); }
00265
00266 inline float compute_rawcl_Eacc(const xAOD::CaloCluster& cl) { return cl.energyBE(1) + cl.energyBE(2) + cl.energyBE(3); }
00267 inline float compute_rawcl_f0(const xAOD::CaloCluster& cl) { return cl.energyBE(0) / (cl.energyBE(1) + cl.energyBE(2) + cl.energyBE(3)); }
00268
00269 inline float compute_correctedcl_Eacc(const xAOD::CaloCluster& cl) { return compute_correctedcl_Es1(cl) + compute_correctedcl_Es2(cl) + compute_correctedcl_Es3(cl); }
00270 inline float compute_correctedcl_f0(const xAOD::CaloCluster& cl) { return compute_correctedcl_Es0(cl) / (compute_correctedcl_Eacc(cl)); }
00271
00272
00273 inline float compute_calibHitsShowerDepth(const std::array<float, 4>& cl, float eta)
00274 {
00275 const std::array<float, 4> radius(get_MVAradius(eta));
00276
00277
00278 const float denominator = cl[0] + cl[1] + cl[2] + cl[3];
00279 if (denominator == 0) return 0.;
00280
00281 return (radius[0] * cl[0]
00282 + radius[1] * cl[1]
00283 + radius[2] * cl[2]
00284 + radius[3] * cl[3]) / denominator;
00285 }
00286
00287 inline float compute_rawcl_calibHitsShowerDepth(const xAOD::CaloCluster& cl)
00288 {
00289 const std::array<float, 4> cluster_array { compute_rawcl_Es0(cl),
00290 compute_rawcl_Es1(cl),
00291 compute_rawcl_Es2(cl),
00292 compute_rawcl_Es3(cl) };
00293 return compute_calibHitsShowerDepth(cluster_array, compute_cl_eta(cl));
00294 }
00295
00296 inline float compute_correctedcl_calibHitsShowerDepth(const xAOD::CaloCluster& cl) {
00297 const std::array<float, 4> cluster_array { compute_correctedcl_Es0(cl),
00298 compute_correctedcl_Es1(cl),
00299 compute_correctedcl_Es2(cl),
00300 compute_correctedcl_Es3(cl) };
00301 return compute_calibHitsShowerDepth(cluster_array, compute_cl_eta(cl));
00302 }
00303
00304
00305
00306
00307
00308 inline float compute_el_charge(const xAOD::Electron& el) { return el.charge(); }
00309 inline float compute_el_tracketa(const xAOD::Electron& el) { return el.trackParticle()->eta(); }
00310 inline float compute_el_trackpt(const xAOD::Electron& el) { return el.trackParticle()->pt(); }
00311 inline float compute_el_trackz0(const xAOD::Electron& el) { return el.trackParticle()->z0(); }
00312 inline float compute_el_refittedTrack_qoverp(const xAOD::Electron& el) { return el.trackParticle()->qOverP(); }
00313 inline int compute_el_author(const xAOD::Electron& el) { return el.auxdata<unsigned short int>("author"); }
00314
00315
00316
00317 inline int compute_ph_convFlag(const xAOD::Photon& ph) {
00318 const auto original = xAOD::EgammaHelpers::conversionType(&ph);
00319 if (original == 3) return 2;
00320 else if (original != 0) return 1;
00321 else return original;
00322 }
00323
00324 struct ConversionHelper
00325 {
00326 ConversionHelper(const xAOD::Photon* ph)
00327 : m_vertex(ph ? ph->vertex() : nullptr),
00328 m_tp0(m_vertex ? m_vertex->trackParticle(0) : nullptr),
00329 m_tp1(m_vertex ? m_vertex->trackParticle(1) : nullptr),
00330 m_pt1conv(0.), m_pt2conv(0.)
00331 {
00332 static asg::AsgMessaging static_msg("ConversionHelper");
00333 static_msg.msg(MSG::DEBUG) << "init conversion helper";
00334 if (!m_vertex) return;
00335
00336 static SG::AuxElement::Accessor<float> accPt1("pt1");
00337 static SG::AuxElement::Accessor<float> accPt2("pt2");
00338 if (accPt1.isAvailable(*m_vertex) && accPt2.isAvailable(*m_vertex))
00339 {
00340 m_pt1conv = accPt1(*m_vertex);
00341 m_pt2conv = accPt2(*m_vertex);
00342 }
00343 else
00344 {
00345 static_msg.msg(MSG::WARNING) << "pt1/pt2 not available, will approximate from first measurements";
00346 m_pt1conv = getPtAtFirstMeasurement(m_tp0);
00347 m_pt2conv = getPtAtFirstMeasurement(m_tp1);
00348 }
00349 }
00350
00351 ConversionHelper(const xAOD::Photon& ph)
00352 : ConversionHelper(&ph) { }
00353
00354 inline float ph_Rconv() const { return m_vertex ? hypot(m_vertex->position().x(), m_vertex->position().y()) : 0; }
00355 inline float ph_zconv() const { return m_vertex ? m_vertex->position().z() : 0.; }
00356 inline int ph_convtrk1nPixHits() const {
00357 if (!m_tp0) { return 0; }
00358 uint8_t hits;
00359 m_tp0->summaryValue(hits, xAOD::numberOfPixelHits);
00360 return hits;
00361 }
00362 inline int ph_convtrk2nPixHits() const {
00363 if (!m_tp1) return 0;
00364 uint8_t hits;
00365 m_tp1->summaryValue(hits, xAOD::numberOfPixelHits);
00366 return hits;
00367 }
00368 inline int ph_convtrk1nSCTHits() const {
00369 if (!m_tp0) { return 0; }
00370 uint8_t hits;
00371 m_tp0->summaryValue(hits, xAOD::numberOfSCTHits);
00372 return hits;
00373 }
00374 inline int ph_convtrk2nSCTHits() const {
00375 if (!m_tp1) { return 0; }
00376 uint8_t hits;
00377 m_tp1->summaryValue(hits, xAOD::numberOfSCTHits);
00378 return hits;
00379 }
00380 inline float ph_pt1conv() const { return m_pt1conv; }
00381 inline float ph_pt2conv() const { return m_pt2conv; }
00382 inline float ph_ptconv() const {
00383
00384
00385
00386 TLorentzVector sum;
00387 if (m_tp0) sum += m_tp0->p4();
00388 if (m_tp1) sum += m_tp1->p4();
00389 return sum.Perp();
00390 }
00391 private:
00392 float getPtAtFirstMeasurement(const xAOD::TrackParticle* tp) const
00393 {
00394 if (!tp) return 0;
00395 for (unsigned int i = 0; i < tp->numberOfParameters(); ++i)
00396 if (tp->parameterPosition(i) == xAOD::FirstMeasurement)
00397 return hypot(tp->parameterPX(i), tp->parameterPY(i));
00398 static asg::AsgMessaging static_msg("ConversionHelper");
00399 static_msg.msg(MSG::WARNING) << "Could not find first parameter, return pt at perigee";
00400 return tp->pt();
00401 }
00402 const xAOD::Vertex* m_vertex;
00403 const xAOD::TrackParticle* m_tp0;
00404 const xAOD::TrackParticle* m_tp1;
00405 float m_pt1conv, m_pt2conv;
00406 };
00407 }
00408
00409 #endif