Belle II Software development
udst_purge_list.py
1#!/usr/bin/env python3
2
3
10
11import basf2
12from mdst import add_mdst_output
13import modularAnalysis as ma
14import vertex as vtx
15from variables import variables as vm
16import argparse
17
18
19def preprocess_roe_data(listName, charge, path):
20 ''' Process/select events on top of the skim processing:
21 -- vertex fit
22 -- select of the positive/negative charge
23 -- extra cuts
24 '''
25 # charge
26 if not (charge == 0):
27 if listName.find("B0") == 0:
28 basf2.B2ERROR(f"Inconsistency between neutral list {listName} and charge requirement {charge}")
29 ma.variablesToEventExtraInfo(listName, {'charge': 'bcharge'}, path=path)
30 vm.addAlias('bcharge', 'eventExtraInfo(bcharge)')
31
32 # Filter:
33 empty_path = basf2.create_path()
34 cfilter = basf2.register_module('VariableToReturnValue')
35 cfilter.param('variable', 'bcharge')
36 cfilter.if_value(f'!={charge}', empty_path)
37 path.add_module(cfilter).set_name("chargeFilter")
38
39 # vertex fit
40 vtx.treeFit(listName, path=path)
41 ma.variablesToEventExtraInfo(listName, {'chiProb': 'chiProb'}, path=path)
42 vm.addAlias('fitProb', 'eventExtraInfo(chiProb)')
43
44 # filter failed fits ...
45 empty_path2 = basf2.create_path()
46 fitfilter = basf2.register_module('VariableToReturnValue')
47 fitfilter.param('variable', 'fitProb')
48 fitfilter.if_value('<0', empty_path2)
49 path.add_module(fitfilter).set_name("fitFilter")
50
51 # require one candidate per event
52 vm.addAlias('nB', f'nParticlesInList({listName})')
53 eventFilter = basf2.register_module('VariableToReturnValue')
54 eventFilter.param('variable', 'nB')
55 eventFilter.if_value('!=1', empty_path2)
56 path.add_module(eventFilter).set_name("eventFilter")
57
58 # store extra momentum/vertex position information
59 Vars = {'px': 'PX', 'py': 'PY', 'pz': 'PZ', 'x': 'X', 'y': 'Y', 'z': 'Z',
60 'IPX': 'IPX', 'IPY': 'IPY', 'IPZ': 'IPZ'}
61 ma.variablesToEventExtraInfo(listName, Vars, path=path)
62
63
64def list_select_roe_data(listName, path):
65
66 filter1 = basf2.register_module("UdstListFilter")
67 filter1.param("listName", listName)
68 filter1.param("keepNotInList", True)
69 path.add_module(filter1).set_name("filter1")
70
71
72def preprocess_signal_mc(listName, charge, path):
73 # charge
74 if not (charge == 0):
75 if listName.find("B0") == 0:
76 basf2.B2ERROR(f"Inconsistency between neutral list {listName} and charge requirement {charge}")
77 ma.variablesToEventExtraInfo(listName, {'charge': 'bcharge'}, path=path)
78 vm.addAlias('bcharge', 'eventExtraInfo(bcharge)')
79 empty_path = basf2.create_path()
80 cfilter = basf2.register_module('VariableToReturnValue')
81 cfilter.param('variable', 'bcharge')
82 cfilter.if_value(f'!={charge}', empty_path)
83 path.add_module(cfilter).set_name("chargeFilter")
84
85 vm.addAlias('nB', f'nParticlesInList({listName})')
86 empty_path2 = basf2.create_path()
87 eventFilter = basf2.register_module('VariableToReturnValue')
88 eventFilter.param('variable', 'nB')
89 eventFilter.if_value('!=1', empty_path2)
90 path.add_module(eventFilter).set_name("eventFilter")
91
92 Vars = {'mcPX': 'PX', 'mcPY': 'PY', 'mcPZ': 'PZ',
93 'mcDecayVertexX': 'X',
94 'mcDecayVertexY': 'Y',
95 'mcDecayVertexZ': 'Z',
96 'IPX': 'IPX', 'IPY': 'IPY', 'IPZ': 'IPZ'
97 }
98 ma.variablesToEventExtraInfo(listName, Vars, path=path)
99
100
101def list_select_signal_mc(listName, path):
102 filter2 = basf2.register_module("UdstListFilter")
103 filter2.param("listName", listName)
104 filter2.param("keepNotInList", False)
105 path.add_module(filter2).set_name("filter2")
106
107
108def prepare_path(FileIn, ListName, icharge, isROE, FileOut):
109 '''
110 Return processing path
111 FileIn -- input file name
112 ListName -- B+ or B0 decay chain of the skim
113 icharge -- charge (0, -1 or +1)
114 isROE -- ROE (data) if true, signal (MC) if false
115 FileOut -- output file name
116 '''
117 main = basf2.Path()
118
119 # input
120 input1 = basf2.register_module('RootInput')
121 input1.param('inputFileName', FileIn)
122 main.add_module(input1).set_name("input1")
123
124 if (isROE):
125 preprocess_roe_data(ListName, icharge, main)
126 list_select_roe_data(ListName, main)
127 else:
128 preprocess_signal_mc(ListName, icharge, main)
129 list_select_signal_mc(ListName, main)
130
131 # output
132 additionalBranches = ['EventExtraInfo']
133
134 add_mdst_output(main, filename=FileOut, additionalBranches=additionalBranches)
135
136 # progress
137 main.add_module('Progress')
138
139 basf2.print_path(main)
140 return main
141
142
143def get_parser():
144 """Handles the command-line argument parsing.
145
146 Returns:
147 argparse.Namespace: The parsed arguments.
148 """
149 parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
150 parser.add_argument("--fileIn", help='Input file name.', required=True)
151 parser.add_argument('--listName', help='Name of the particle list to keep (isSignal) or to remove.', required=True)
152 parser.add_argument("--isSignal", action='store_true', help='If added, the input is signal MC')
153 parser.add_argument("--charge", default='pos',
154 help='Filter charge. Possible values are :code:`pos`, :code:`neg` or :code:`zero`. Default is :code:`pos`')
155 parser.add_argument("--fileOut", default='test.root', help='Output file name. Default: :code:`test.root`')
156
157 return parser
158
159
160
161if __name__ == '__main__':
162
163 args = get_parser().parse_args()
164
165 list1 = args.listName
166 signal = args.isSignal
167 charge = args.charge
168 fileOut = args.fileOut
169 fileIn = args.fileIn
170
171 if charge == 'zero':
172 icharge = 0
173 elif charge == 'pos':
174 icharge = 1
175 elif charge == 'neg':
176 icharge = -1
177
178 main = prepare_path(fileIn, list1, icharge, not signal, fileOut)
179 basf2.process(main)