Belle II Software  release-05-01-25
flavorTaggerTrainingNtuple.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
5 """
6  <header>
7  <contact>Fernando Abudinen</contact>
8  <description>This file tests the functionality of sampling needed to train the flavor tagger.
9  </description>
10  </header>
11 """
12 
13 import b2test_utils
14 import basf2
15 from basf2 import set_random_seed, create_path, process
16 import modularAnalysis as ma
17 from variables import variables as vm
18 import flavorTagger as ft
19 import ROOT
20 import os
21 import math
22 import unittest
23 
24 # make logging more reproducible by replacing some strings
26 set_random_seed("1337")
27 testinput = [b2test_utils.require_file('analysis/tests/Btonunubar.root')]
28 
29 
31 testpath = create_path()
32 testpath.add_module('RootInput', inputFileNames=testinput)
33 
34 ma.findMCDecay(list_name='B0:sig', decay='B0 -> nu_tau anti-nu_tau', writeOut=True, path=testpath)
35 
36 ma.matchMCTruth('B0:sig', path=testpath)
37 
38 # Test to build a rest of event from the MC B0 decaying to two neutrinos
39 ma.buildRestOfEvent('B0:sig', path=testpath)
40 
41 # Test MC association of MC particle
42 ma.applyCuts('B0:sig', ' abs(isRelatedRestOfEventB0Flavor) == 1', path=testpath)
43 
44 
46 roe_path = create_path()
47 deadEndPath = create_path()
48 
49 ma.signalSideParticleListsFilter(
50  ['B0:sig'],
51  'nROE_Charged(, 0) > 0 and abs(qrCombined) == 1',
52  roe_path,
53  deadEndPath)
54 
55 # Create list of ROE electrons
56 ma.fillParticleList('e+:inRoe', 'isInRestOfEvent > 0.5 and passesROEMask() > 0.5 and ' +
57  'isNAN(p) !=1 and isInfinity(p) != 1', path=roe_path)
58 
59 # Save pseudo training sample
60 methodPrefixEventLevel = "FlavorTagger_Belle2_B2nunuBGx1EventLevelElectronFBDT"
61 targetVariable = 'isRightCategory(Electron)'
62 ma.applyCuts('e+:inRoe', 'isRightCategory(mcAssociated) > 0', path=roe_path)
63 
64 # Skip electrons if list is empty
65 eventLevelpath = create_path()
66 SkipEmptyParticleList = basf2.register_module("SkimFilter")
67 SkipEmptyParticleList.set_name('SkimFilter_EventLevelElectron')
68 SkipEmptyParticleList.param('particleLists', 'e+:inRoe')
69 SkipEmptyParticleList.if_true(eventLevelpath, basf2.AfterConditionPath.CONTINUE)
70 roe_path.add_module(SkipEmptyParticleList)
71 
72 ntuple = basf2.register_module('VariablesToNtuple')
73 ntuple.param('fileName', methodPrefixEventLevel + "sampled0.root")
74 ntuple.param('treeName', methodPrefixEventLevel + "_tree")
75 
76 # Call variable aliases from flavor tagger
77 ft.set_FlavorTagger_pid_aliases()
78 # Alias for pidProbabilityExpert(11, ALL)
79 vm.addAlias(f"eid_ALL", f"pidProbabilityExpert(11, ALL)")
80 
81 variablesToBeSaved = ['useCMSFrame(p)',
82  'useCMSFrame(pt)',
83  'p',
84  'pt',
85  'cosTheta',
86  'electronID',
87  'eid_ALL',
88  'eid_TOP',
89  'eid_ARICH',
90  'eid_ECL',
91  'BtagToWBosonVariables(recoilMassSqrd)',
92  'BtagToWBosonVariables(pMissCMS)',
93  'BtagToWBosonVariables(cosThetaMissCMS)',
94  'BtagToWBosonVariables(EW90)',
95  'cosTPTO',
96  'chiProb',
97  'hasHighestProbInCat(e+:inRoe, isRightTrack(Electron))',
98  targetVariable, 'ancestorHasWhichFlavor',
99  'isSignal', 'mcPDG', 'mcErrors', 'genMotherPDG',
100  'nMCMatches', 'B0mcErrors'
101  ]
102 ntuple.param('variables', variablesToBeSaved)
103 ntuple.param('particleList', 'e+:inRoe')
104 eventLevelpath.add_module(ntuple)
105 
106 testpath.for_each('RestOfEvent', 'RestOfEvents', roe_path)
107 
108 
109 
111  process(testpath, 5)
112 
113  # Testing
114  assert os.path.isfile(methodPrefixEventLevel + "sampled0.root"), methodPrefixEventLevel + "sampled0.root" + " wasn't created"
115  f = ROOT.TFile(methodPrefixEventLevel + "sampled0.root")
116  t1 = f.Get(methodPrefixEventLevel + "_tree")
117  assert bool(t1), methodPrefixEventLevel + "_tree" + " isn't contained in file"
118  assert t1.GetEntries() > 0, methodPrefixEventLevel + "_tree" + "contains zero entries"
119  for iVariable in variablesToBeSaved:
120  iROOTVariable = str(ROOT.Belle2.makeROOTCompatible(iVariable))
121  assert t1.GetListOfBranches().Contains(iROOTVariable), iROOTVariable +\
122  " branch is missing from " + methodPrefixEventLevel + "_tree"
123 
124  assert t1.GetEntries() == 40, "40 entries should be saved in the test training ntuple, otherwise some problem happened."
125 
126  mcPDGCodes = [
127  211.0, 211.0, 211.0, 211.0, 211.0, 321.0, 13.0, 11.0,
128  211.0, 211.0, 211.0, 11.0, 211.0, 211.0, 211.0, 211.0,
129  211.0, 11.0, 211.0, 211.0, 211.0, 211.0, 211.0, 211.0, 211.0,
130  2212.0, 211.0, 211.0, 2212.0, 211.0, 13.0, 211.0, 211.0,
131  211.0, 211.0, 211.0, 211.0, 321.0, 321.0, 211.0]
132 
133  for iEntry in range(t1.GetEntries()):
134  t1.GetEntry(iEntry)
135  assert abs(t1.useCMSFrame__bop__bc) > 0, " p* should be greater than 0"
136  assert abs(t1.useCMSFrame__bopt__bc) > 0, " pt* should be greater than 0"
137  assert abs(t1.p) > 0, " p should be greater than 0"
138  assert abs(t1.pt) > 0, " pt should be greater than 0"
139  assert abs(t1.cosTheta) > 0, " cosTheta should be greater than 0"
140  assert abs(t1.eid_ALL) > 0, " electronID should be greater than 0"
141  assert abs(t1.eid_TOP) > 0, " eid_TOP should be greater than 0"
142  assert abs(t1.eid_ARICH) > 0, " eid_ARICH should be greater than 0"
143  assert abs(t1.eid_ECL) > 0, "eid_ECL should be greater than 0"
144  assert abs(t1.BtagToWBosonVariables__borecoilMassSqrd__bc) > 0, " recoilMassSqrd should be greater than 0"
145  assert abs(t1.BtagToWBosonVariables__bopMissCMS__bc) > 0, " pMissCMS should be greater than 0"
146  assert abs(t1.BtagToWBosonVariables__bocosThetaMissCMS__bc) > 0, " cosThetaMissCMS should be greater than 0"
147  assert abs(t1.BtagToWBosonVariables__boEW90__bc) > 0, " EW90 should be greater than 0"
148  assert abs(t1.cosTPTO) > 0, " cosTPTO should be greater than 0"
149  assert abs(t1.chiProb) > 0, " chiProb should be greater than 0"
150  if math.isnan(
151  t1.hasHighestProbInCat__boe__pl__clinRoe__cm__spisRightTrack__boElectron__bc__bc
152  ):
153  basf2.B2FATAL(" hasHighestProbInCat Electron should not be nan")
154  if math.isnan(t1.isRightCategory__boElectron__bc):
155  basf2.B2FATAL(" isRightCategory Electron should not be nan ")
156  if math.isnan(t1.ancestorHasWhichFlavor):
157  basf2.B2FATAL(" ancestorHasWhichFlavor should not be nan")
158  if math.isnan(t1.isSignal):
159  basf2.B2FATAL(" isSignal should not be nan")
160  assert abs(t1.mcPDG) == mcPDGCodes[iEntry], " Some mismatch between PDG codes happened in entry " + iEntry
161  if math.isnan(t1.mcErrors):
162  basf2.B2FATAL(" mcErrors should not be equal to nan")
163  assert abs(t1.genMotherPDG) > 0, " genMotherPDG should be greater than 0"
164  assert abs(t1.nMCMatches) > 0, " nMCMatches should be greater than 0"
b2test_utils.configure_logging_for_tests
def configure_logging_for_tests(user_replacements=None)
Definition: __init__.py:99
b2test_utils.clean_working_directory
def clean_working_directory()
Definition: __init__.py:176
b2test_utils.require_file
def require_file(filename, data_type="", py_case=None)
Definition: __init__.py:47