ATLAS Offline Software
Loading...
Searching...
No Matches
TruthDerivationTester.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5/* Simple class for working with truth DAODs */
6/* Goal is to validate truth DAOD contents:
7 MET_Truth
8 Truth particles with aux: TruthElectrons, TruthMuons, TruthPhotons, TruthTaus, TruthNeutrinos, TruthBSM, TruthBottom, TruthTop, TruthBoson
9 Full collections with aux: TruthWbosonWithDecayParticles, TruthWbosonWithDecayVertices
10 AntiKt4TruthDressedWZJets.GhostCHadronsFinalCount.GhostBHadronsFinalCount.pt.HadronConeExclTruthLabelID.PartonTruthLabelID.TrueFlavor // with Aux
11 AntiKt10TruthTrimmedPtFrac5SmallR20Jets.pt.Tau1_wta.Tau2_wta.Tau3_wta.D2 // with Aux
12 TruthEvents.Q.XF1.XF2.PDGID1.PDGID2.PDFID1.PDFID2.X1.X2.crossSection
13 xAOD::TruthMetaDataContainer#TruthMetaData // with Aux
14 Plus extra features
15*/
16
17// Setup for reading ATLAS data
18#ifdef XAOD_STANDALONE
19#include "xAODRootAccess/Init.h"
21#else
23#include "GaudiKernel/SmartIF.h"
24#endif
25
26// Boost for argument parsing
27#include <boost/program_options.hpp>
28namespace po = boost::program_options;
29
30// Truth weight tool
34//#include "PMGTools/PMGTruthWeightTool.h"
35
36// ATLAS data dependencies
45
46// ROOT dependencies
47#include <TFile.h>
48#include <TChain.h>
49#include <TH1D.h>
50
51// STL includes
52#include <iostream>
53#include <cmath>
54#include <format>
55
56// Helper macro for retrieving containers from the event
57#define CHECK_RETRIEVE( container , name ) { \
58 if (!event.retrieve( container , name ).isSuccess()){ \
59 Error( APP_NAME , "%s", std::format ("Could not load event {} from the file!" , name ).c_str()); \
60 return 1; \
61 } \
62 }
63
64// Helper for counting children
66 if (!p) return 0;
67 int children = 0;
68 for (size_t n=0;n<p->nChildren();++n){
69 children += countChildren( p->child(n) );
70 }
71 return children;
72}
73
74// Helper for counting parents
76 if (!p) return 0;
77 int parents = 0;
78 for (size_t n=0;n<p->nParents();++n){
79 parents += countParents( p->parent(n) );
80 }
81 return parents;
82}
83
84// Main routine... here we go!
85int main(int argc, char **argv) {
86
87 // The application's name:
88 const char* APP_NAME = argv[ 0 ];
89
90 // Make sure things know we are not in StatusCode land
91 using namespace asg::msgUserCode;
93
94 // Setup for reading -- if this fails, we have major problems
95#ifdef XAOD_STANDALONE
96 if ( ! xAOD::Init().isSuccess() ) {
97 std::cerr << "Cannot initialise xAOD access !" << std::endl;
98 return 1;
99 }
100 ANA_MSG_INFO("Using xAOD access");
101#else
102 SmartIF<IAppMgrUI> app = POOL::Init();
103 ANA_MSG_INFO("Using POOL access");
104#endif
105
106 // Get and parse the command-line arguments
107 po::options_description desc("Running a simple truth analysis");
108 std::string outputName,inputName;
109 desc.add_options()
110 ("help,h", "print usage and exit")
111 ("output,o", po::value<std::string>(&outputName), "Output file name")
112 ("input,i", po::value<std::string>(&inputName), "Input file name")
113 ("nevents", po::value<int>()->default_value(-1), "number of events to run on (set to -1 to ignore it")
114 ;
115
116 po::variables_map vm;
117 po::store( po::command_line_parser(argc, argv).options(desc).run(), vm);
118 po::notify(vm);
119
120 if (vm.count("help")) {
121 std::cout << desc << std::endl;
122 return 1;
123 }
124
125 long long nevents = -1;
126 if (vm.count("nevents")) {
127 nevents = vm["nevents"].as<int>();
128 }
129
130 Info( "Reading from %s and writing to %s" , inputName.c_str() , outputName.c_str() );
131
132 // Input chain
133 std::unique_ptr< TFile > ifile( TFile::Open( inputName.c_str() , "READ" ) );
134 ANA_CHECK( ifile.get() );
135#ifdef XAOD_STANDALONE
137#else
139#endif
140 ANA_CHECK( event.readFrom( ifile.get() ) );
141
142 // Load metadata
143 event.getEntries();
144
145 // Make some temporary variables that we'll get out during the event loop
146 const size_t nParticleContainers = 9;
147 std::string particleKeyList[nParticleContainers] = { "TruthElectrons", "TruthMuons", "TruthPhotons", "TruthTaus", "TruthNeutrinos", "TruthBSM", "TruthBottom", "TruthTop", "TruthBoson" };
148 const xAOD::TruthEventContainer* xTruthEventContainer(nullptr);
149 const xAOD::EventInfo* xEventInfo(nullptr);
150 const xAOD::JetContainer* smallRJets(nullptr);
151 const xAOD::JetContainer* largeRJets(nullptr);
152 const xAOD::TruthMetaDataContainer* truthMeta(nullptr);
153 const xAOD::MissingETContainer* truthMET(nullptr);
154 const xAOD::TruthParticleContainer * truthParticles[nParticleContainers];
155 for (size_t n=0;n<nParticleContainers;++n) truthParticles[n] = nullptr;
156
157/*
158 Missing full collections with aux: TruthBosonsWithDecayParticles, TruthBosonsWithDecayVertices
159*/
160 // Make histograms
161 // MET histograms
162 TH1D* h_metNonInt = new TH1D("MET_NonInt","",50,0,500.);
163 TH1D* h_metInt = new TH1D("MET_Int","",50,0,200.);
164 TH1D* h_metIntOut = new TH1D("MET_IntOut","",50,0,100.);
165 TH1D* h_metIntMuons = new TH1D("MET_IntMuons","",50,0,300.);
166 // Particle collections: pT and connections for all
167 TH1D* h_partPt[nParticleContainers];
168 for (size_t n=0;n<nParticleContainers;++n) h_partPt[n] = new TH1D((particleKeyList[n]+"_pT").c_str(),"",50,0.,500.);
169 TH1D* h_partConn[nParticleContainers];
170 for (size_t n=0;n<nParticleContainers;++n) h_partConn[n] = new TH1D((particleKeyList[n]+"_Connections").c_str(),"",35,-10,25);
171 // Isolation for e/y/u/tau
172 TH1D* h_elPtCone = new TH1D("ElPtCone","",50,0.,20.);
173 TH1D* h_elEtCone = new TH1D("ElEtCone","",50,0.,20.);
174 TH1D* h_muPtCone = new TH1D("MuPtCone","",50,0.,20.);
175 TH1D* h_muEtCone = new TH1D("MuEtCone","",50,0.,20.);
176 TH1D* h_phPtCone = new TH1D("PhPtCone","",50,0.,20.);
177 TH1D* h_phEtCone = new TH1D("PhEtCone","",50,0.,20.);
178 // MCTC decorations for e/y/u/tau/nu
179 TH1D* h_elType = new TH1D("ElType","",50,0,50);
180 TH1D* h_elOrig = new TH1D("ElOrigin","",50,0,50);
181 TH1D* h_muType = new TH1D("MuType","",50,0,50);
182 TH1D* h_muOrig = new TH1D("MuOrigin","",50,0,50);
183 TH1D* h_phType = new TH1D("PhType","",50,0,50);
184 TH1D* h_phOrig = new TH1D("PhOrigin","",50,0,50);
185 TH1D* h_taType = new TH1D("TaType","",50,0,50);
186 TH1D* h_taOrig = new TH1D("TaOrigin","",50,0,50);
187 TH1D* h_nuType = new TH1D("NuType","",50,0,50);
188 TH1D* h_nuOrig = new TH1D("NuOrigin","",50,0,50);
189 // Dressed momenta for e/mu/tau
190 TH1D* h_elDressedPt = new TH1D("ElDressedPt","",50,0.,200.);
191 TH1D* h_muDressedPt = new TH1D("MuDressedPt","",50,0.,200.);
192 TH1D* h_taDressedPt = new TH1D("TaDressedPt","",50,0.,200.);
193 // Truth jets: pT, three flavor classifiers
194 TH1D* h_jetPt = new TH1D("JetPt","",50,0,500.);
195 TH1D* h_jetFTAG = new TH1D("JetFTAG","",25,0,25);
196 TH1D* h_jetJeMe = new TH1D("JetJeMe","",25,0,25);
197 TH1D* h_jetFull = new TH1D("JetFull","",50,0,50);
198 // Large R : pT, tau2, D2
199 TH1D* h_jetLRPt = new TH1D("JetLRPt","",50,0,500.);
200 TH1D* h_jetLRT2 = new TH1D("JetLRT2","",50,0,500.);
201 TH1D* h_jetLRD2 = new TH1D("JetLRD2","",50,0,500.);
202 // Truth events: PDF info , cross section , filter outcome
203 TH1D* h_x1 = new TH1D("X1","",50,0,1.);
204 TH1D* h_x2 = new TH1D("X2","",50,0,1.);
205 TH1D* h_xsec = new TH1D("XSec","",50,0,1.);
206 TH1D* h_HTFilt = new TH1D("HTFilt","",50,0,1000.);
207 // Lazy for truth weights
208 asg::AnaToolHandle< PMGTools::IPMGTruthWeightTool > weightTool("PMGTools::PMGTruthWeightTool/PMGTruthWeightTool");
209 ANA_CHECK(weightTool.retrieve());
210
211 // For the weights in the file
212 std::vector<TH1D*> h_weights;
213 // For testing the truth metadata
214 uint32_t channelNumber = 0;
215 std::vector<std::string> weightNames;
216
217 // Into the event loop, with an optional cap
218 long long nEvents = nevents > 0 ? std::min(static_cast<long long>(event.getEntries()), nevents) : event.getEntries();
219 Info( APP_NAME , "Beginning event loop over %llu events." , nEvents );
220 for (long evt=0;evt<nEvents;++evt){
221 // Grab the data
222 event.getEntry(evt);
223 if (evt%1000==0) Info( APP_NAME , "Working on entry %lu" , evt );
224
225 // Get the containers out
226 CHECK_RETRIEVE( xTruthEventContainer , "TruthEvents" )
227 CHECK_RETRIEVE( xEventInfo , "EventInfo" )
228 CHECK_RETRIEVE( smallRJets , "AntiKt4TruthDressedWZJets" )
229 CHECK_RETRIEVE( largeRJets , "AntiKt10TruthTrimmedPtFrac5SmallR20Jets" )
230 CHECK_RETRIEVE( truthMET , "MET_Truth" )
231 for (size_t n=0;n<nParticleContainers;++n){
232 CHECK_RETRIEVE( truthParticles[n] , particleKeyList[n] )
233 }
234
235 if (!event.retrieveMetaInput( truthMeta , "TruthMetaData" ).isSuccess()){
236 Error( APP_NAME , "Could not load event TruthMetaData from the file!" );
237 return 1;
238 }
239
240 // Metadata check
241 if (truthMeta->size()>1){
242 Error( APP_NAME , "Truth metadata size: %lu . No one will look past item 0!" , truthMeta->size() );
243 return 1;
244 }
245 if (channelNumber==0){
246 channelNumber = (*truthMeta)[0]->mcChannelNumber();
247 weightNames = std::vector<std::string>((*truthMeta)[0]->weightNames());
248 Info( APP_NAME , "Got channel number %u and %lu weight names" , channelNumber , weightNames.size() );
249 }
250 if (channelNumber != (*truthMeta)[0]->mcChannelNumber()){
251 Error( APP_NAME , "Channel number changed mid-file! Was: %u now: %u " , channelNumber , (*truthMeta)[0]->mcChannelNumber() );
252 return 1;
253 }
254 if (weightNames != (*truthMeta)[0]->weightNames() ){
255 Error( APP_NAME , "Weights have changed!" );
256 for (size_t n=0;n<std::max( weightNames.size() , (*truthMeta)[0]->weightNames().size() );++n){
257 std::cerr << " " << n << " ";
258 if (n<weightNames.size()) std::cerr << weightNames[n] << " ";
259 else std::cerr << "- ";
260 if (n<(*truthMeta)[0]->weightNames().size()) std::cerr << (*truthMeta)[0]->weightNames()[n] << " ";
261 else std::cerr << "- ";
262 std::cerr << std::endl;
263 }
264 return 1;
265 }
266 // Event weight handling
267 if (h_weights.size()==0){
268 // First event, init!
269 for (auto & name : weightNames ){
270 h_weights.push_back( new TH1D(("h_W_"+name).c_str(),"",100,-10.,10.) );
271 }
272 h_weights.push_back( new TH1D("h_W_nominalTest","",100,-10.,10.) );
273 }
274 for (size_t n=0;n<weightNames.size();++n) h_weights[n]->Fill( weightTool->getWeight(xEventInfo,weightNames[n]) );
275 // Eventually this should be the nominal weight without needing to give an explicit name
276 h_weights[weightNames.size()]->Fill( weightTool->getWeight(xEventInfo," nominal ") );
277 // Event info
278 float x1=0.,x2=0.;
279 (*xTruthEventContainer)[0]->pdfInfoParameter( x1 , xAOD::TruthEvent::X1 );
280 (*xTruthEventContainer)[0]->pdfInfoParameter( x2 , xAOD::TruthEvent::X2 );
281 h_x1->Fill( x1 );
282 h_x2->Fill( x2 );
283 h_xsec->Fill( (*xTruthEventContainer)[0]->crossSection() );
284 static const SG::ConstAccessor<float> GenFiltHTAcc ("GenFiltHT");
285 h_HTFilt->Fill( GenFiltHTAcc (*xEventInfo ) );
286 // For MET: NonInt, Int, IntOut, IntMuons
287 h_metNonInt->Fill( (*truthMET)["NonInt"]->met()*0.001 );
288 h_metNonInt->Fill( (*truthMET)["Int"]->met()*0.001 );
289 h_metNonInt->Fill( (*truthMET)["IntOut"]->met()*0.001 );
290 h_metNonInt->Fill( (*truthMET)["IntMuons"]->met()*0.001 );
291 // Truth particles
292 for (size_t n=0;n<nParticleContainers;++n){ // PT and connections for all
293 for (const auto * p : *truthParticles[n]){
294 h_partPt[n]->Fill( p->pt() );
295 h_partConn[n]->Fill( countChildren( p ) );
296 h_partConn[n]->Fill( -1-countParents( p ) );
297 }
298 }
299
300 static const SG::ConstAccessor<float> ptcone30Acc("ptcone30");
301 static const SG::ConstAccessor<float> ptcone20Acc("ptcone20");
302 static const SG::ConstAccessor<float> etcone20Acc("etcone20");
303 static const SG::ConstAccessor<float> pt_dressedAcc("pt_dressed");
304 static const SG::ConstAccessor<float> pt_vis_dressedAcc("pt_vis_dressed");
305 static const SG::ConstAccessor<float> Tau2_wtaAcc("Tau2_wta");
306 static const SG::ConstAccessor<float> D2Acc("D2");
307 static const SG::ConstAccessor<unsigned int> classifierParticleTypeAcc("classifierParticleType");
308 static const SG::ConstAccessor<unsigned int> classifierParticleOriginAcc("classifierParticleOrigin");
309 static const SG::ConstAccessor<int> HadronConeExclTruthLabelIDAcc("HadronConeExclTruthLabelID");
310 static const SG::ConstAccessor<int> PartonTruthLabelIDAcc("PartonTruthLabelID");
311 static const SG::ConstAccessor<int> TrueFlavorAcc("TrueFlavor");
312
313 for (const auto * p : *truthParticles[0]){ // Electrons
314 h_elPtCone->Fill( ptcone30Acc(*p)*0.001 );
315 h_elEtCone->Fill( etcone20Acc(*p)*0.001 );
316 h_elDressedPt->Fill( pt_dressedAcc(*p)*0.001 );
317 h_elType->Fill( classifierParticleTypeAcc(*p) );
318 h_elOrig->Fill( classifierParticleOriginAcc(*p) );
319 }
320 for (const auto * p : *truthParticles[1]){ // Muons
321 h_muPtCone->Fill( ptcone30Acc(*p)*0.001 );
322 h_muEtCone->Fill( etcone20Acc(*p)*0.001 );
323 h_muDressedPt->Fill( pt_dressedAcc(*p)*0.001 );
324 h_muType->Fill( classifierParticleTypeAcc(*p) );
325 h_muOrig->Fill( classifierParticleOriginAcc(*p) );
326 }
327 for (const auto * p : *truthParticles[2]){ // Photons
328 h_phPtCone->Fill( ptcone20Acc(*p)*0.001 );
329 h_phEtCone->Fill( etcone20Acc(*p)*0.001 );
330 h_phType->Fill( classifierParticleTypeAcc(*p) );
331 h_phOrig->Fill( classifierParticleOriginAcc(*p) );
332 }
333 for (const auto * p : *truthParticles[3]){ // Taus
334 h_taDressedPt->Fill( pt_vis_dressedAcc(*p)*0.001 );
335 h_taType->Fill( classifierParticleTypeAcc(*p) );
336 h_taOrig->Fill( classifierParticleOriginAcc(*p) );
337 }
338 for (const auto * p : *truthParticles[4]){ // Neutrinos
339 h_nuType->Fill( classifierParticleTypeAcc(*p) );
340 h_nuOrig->Fill( classifierParticleOriginAcc(*p) );
341 }
342 for (const auto * j : *smallRJets){ // Small-R jets
343 h_jetPt->Fill( j->pt()*0.001 );
344 h_jetFTAG->Fill( HadronConeExclTruthLabelIDAcc(*j) );
345 h_jetJeMe->Fill( PartonTruthLabelIDAcc(*j) );
346 h_jetFull->Fill( TrueFlavorAcc(*j) );
347 }
348 for (const auto * j : *largeRJets){ // Large-R jets
349 h_jetLRPt->Fill( j->pt()*0.001 );
350 h_jetLRT2->Fill( Tau2_wtaAcc(*j) );
351 h_jetLRD2->Fill( D2Acc(*j) );
352 }
353
354 } // End of event loop
355 Info( APP_NAME , "Done with event loop" );
356
357 // Output file
358 TFile * oRoot = new TFile(outputName.c_str(),"RECREATE");
359 oRoot->cd();
360
361 // Write histograms
362 // MET histograms
363 h_metNonInt->Write();
364 h_metInt->Write();
365 h_metIntOut->Write();
366 h_metIntMuons->Write();
367 // Truth particle histograms
368 for (size_t n=0;n<nParticleContainers;++n) h_partPt[n]->Write();
369 for (size_t n=0;n<nParticleContainers;++n) h_partConn[n]->Write();
370 h_elPtCone->Write();
371 h_elEtCone->Write();
372 h_muPtCone->Write();
373 h_muEtCone->Write();
374 h_phPtCone->Write();
375 h_phEtCone->Write();
376 h_elDressedPt->Write();
377 h_muDressedPt->Write();
378 h_taDressedPt->Write();
379 h_elType->Write();
380 h_elOrig->Write();
381 h_muType->Write();
382 h_muOrig->Write();
383 h_phType->Write();
384 h_phOrig->Write();
385 h_taType->Write();
386 h_taOrig->Write();
387 h_nuType->Write();
388 h_nuOrig->Write();
389 // Truth jet histograms
390 h_jetPt->Write();
391 h_jetFTAG->Write();
392 h_jetJeMe->Write();
393 h_jetFull->Write();
394 h_jetLRPt->Write();
395 h_jetLRT2->Write();
396 h_jetLRD2->Write();
397 // Event histograms
398 h_x1->Write();
399 h_x2->Write();
400 h_xsec->Write();
401 h_HTFilt->Write();
402 for (auto * h : h_weights) h->Write();
403
404 // Close up -- all done!
405 oRoot->Close();
406
407 // trigger finalization of all services and tools created by the Gaudi Application
408#ifndef XAOD_STANDALONE
409 if (app->finalize().isFailure()){
410 Warning( APP_NAME , "Finalization failed?" );
411 }
412#endif
413
414 Info( APP_NAME , "All done -- goodbye." );
415
416 return 0;
417}
#define APP_NAME
Helper class to provide constant type-safe access to aux data.
#define ANA_MSG_INFO(xmsg)
Macro printing info messages.
#define ANA_CHECK(EXP)
check whether the given expression was successful
#define ANA_CHECK_SET_TYPE(TYPE)
set the type for ANA_CHECK to report failures
int countParents(const xAOD::TruthParticle *p)
#define CHECK_RETRIEVE(container, name)
int countChildren(const xAOD::TruthParticle *p)
Header file for AthHistogramAlgorithm.
size_type size() const noexcept
Returns the number of elements in the collection.
Helper class to provide constant type-safe access to aux data.
a modified tool handle that allows its owner to configure new tools from the C++ side
StatusCode retrieve()
initialize the tool
Tool for accessing xAOD files outside of Athena.
@ kClassAccess
Access auxiliary data using the aux containers.
const int nEvents
int main()
Definition hello.cxx:18
IAppMgrUI * Init(const char *options="POOLRootAccess/basic.opts")
Bootstraps (creates and configures) the Gaudi Application with the provided options file.
TruthEventContainer_v1 TruthEventContainer
Declare the latest version of the truth event container.
StatusCode Init(const char *appname)
Function initialising ROOT/PyROOT for using the ATLAS EDM.
Definition Init.cxx:31
EventInfo_v1 EventInfo
Definition of the latest event info version.
TruthMetaDataContainer_v1 TruthMetaDataContainer
Declare the latest version of the truth vertex container.
TruthParticle_v1 TruthParticle
Typedef to implementation.
JetContainer_v1 JetContainer
Definition of the current "jet container version".
TruthParticleContainer_v1 TruthParticleContainer
Declare the latest version of the truth particle container.
int run(int argc, char *argv[])