Belle II Software light-2609-luna
produceTrainingInputs.py
1#!/usr/bin/env python3
2
3
10
11
35
36import argparse
37
38import basf2 as b2
39import modeSelector
40import modularAnalysis as ma
41from modeSelector import config
42from variables import variables as vm
43
44# Parse arguments (basf2 strips its own args, remaining go to script)
45parser = argparse.ArgumentParser()
46parser.add_argument('--input', nargs='+', default=None,
47 help='Input ROOT file(s) with FEI B meson candidates')
48parser.add_argument('--output', default='modeSelector_training',
49 help='Output prefix for training files (default: modeSelector_training)')
50parser.add_argument('--cont-fraction', type=float, default=0.25,
51 help='Continuum keep fraction relative to the 30% BB band (default: 0.25)')
52args = parser.parse_args()
53
54# Resolved after parsing so that --input works without the validation file installed
55if args.input is None:
56 args.input = [b2.find_file('udst16_feiHadronic.root', 'validation')]
57
58# Set up logging
59b2.set_log_level(b2.LogLevel.INFO)
60b2.set_random_seed(1337)
61
62# Create path
63my_path = b2.create_path()
64
65# Input files
66ma.inputMdstList(filelist=args.input, path=my_path)
67
68# Prepend the analysis globaltag
69b2.conditions.prepend_globaltag(ma.getAnalysisGlobaltag())
70
71# FEI list identifier
72fei_identifier = 'feiHadronic'
73
74# Define the particle lists to process
75particle_lists = [f'B+:{fei_identifier}', f'B0:{fei_identifier}']
76
77# MC truth matching (required for training labels)
78for plist in particle_lists:
79 ma.matchMCTruth(plist, path=my_path)
80
81# Apply simple eventRandom cuts on the raw FEI lists.
82BASE_FRACTION = 0.3
83ma.applyEventCuts(
84 f'[[isContinuumEvent == 1] and [eventRandom < {BASE_FRACTION * args.cont_fraction}]] or '
85 f'[[isContinuumEvent != 1] and [eventRandom < {BASE_FRACTION}]]',
86 path=my_path
87)
88
89# Define ROE masks for continuum suppression
90track_mask = "[[dr < 2] and [abs(dz) < 4] and [pt > 0.2] and [thetaInCDCAcceptance==1]]"
91ecl_mask = ("[[[[clusterReg==1] and [E>0.080]] or [[clusterReg==2] and [E > 0.03]] "
92 "or [[clusterReg==3] and [E > 0.06]]] and [clusterNHits > 1.5] "
93 "and [abs(clusterTiming) < 200] and [thetaInCDCAcceptance==1]]")
94cleanMask = ("cleanMask", track_mask, ecl_mask)
95
96# Apply FEI calibration cuts and build continuum suppression on kept events.
97for b in ['B+', 'B0']:
98 ma.applyCuts(f'{b}:{fei_identifier}', '[Mbc > 5.23] and [-0.15 < deltaE < 0.1]', path=my_path)
99
100 # Build the Rest of Event
101 ma.buildRestOfEvent(f'{b}:{fei_identifier}', path=my_path)
102 ma.appendROEMasks(f'{b}:{fei_identifier}', [cleanMask], path=my_path)
103
104 # Build continuum suppression (provides cosTBTO variable)
105 ma.buildContinuumSuppression(f'{b}:{fei_identifier}', 'cleanMask', path=my_path)
106
107 # Apply cosTBTO cut
108 ma.applyCuts(f'{b}:{fei_identifier}', 'cosTBTO < 0.9', path=my_path)
109
110# Build event shape variables (sphericity, thrust, etc.) only for kept events.
111ma.buildEventShape(
112 allMoments=False,
113 cleoCones=False,
114 jets=False,
115 collisionAxis=False,
116 harmonicMoments=True,
117 foxWolfram=True,
118 sphericity=True,
119 thrust=True,
120 path=my_path
121)
122
123modeSelector.addGeneratedDecayWeights(
124 bp_list=f'B+:{fei_identifier}',
125 b0_list=f'B0:{fei_identifier}',
126 path=my_path
127)
128
129# Wrap B+ and B0 in a common Upsilon(4S) candidate and merge lists, so the
130# per-candidate signal-truth ntuple below can dump both sectors with a single
131# variablesToNtuple call (same pattern as applyModeSelector.py). ExtraInfo set by
132# ModeSelector on the B+/B0 candidate is read back below via daughter(0, ...).
133for b, b_str in zip(['B+', 'B0'], ['Bp', 'B0']):
134 ma.reconstructDecay(
135 f'Upsilon(4S):{b_str} -> {b}:{fei_identifier}',
136 '',
137 allowChargeViolation=True,
138 path=my_path
139 )
140ma.copyLists('Upsilon(4S):trainCandidates', ['Upsilon(4S):Bp', 'Upsilon(4S):B0'], path=my_path)
141
142# Run ModeSelector in training mode (no NN models needed). Features and MC truth
143# are exposed via EventExtraInfo/ExtraInfo for the variablesToNtuple calls below.
145 bp_list=f'B+:{fei_identifier}',
146 b0_list=f'B0:{fei_identifier}',
147 training_mode=True,
148 path=my_path
149)
150
151output_filename = f'{args.output}.root'
152
153# Event-level ntuple: raw features + per-event truth/label scalars, one row per event.
154# Aliased to plain identifiers so the resulting branch names are predictable (no ROOT
155# name-mangling of the eventExtraInfo(...)/extraInfo(...) meta-variable syntax).
156n_raw_features = len(config.FEATURE_BLOCKS) * config.N_INPUT_IDS + len(config.EVENT_FEATURES) + 4
157event_truth_fields = [
158 'is_cont', 'gen_pdg', 'bp_gen_decay_mode_id', 'b0_gen_decay_mode_id',
159 'bp_gen_fei_calib_weight', 'b0_gen_fei_calib_weight', 'bp_is_best',
160 'best_sigprob', 'best_bp_sigprob_iid', 'best_b0_sigprob_iid',
161 'bp_tag_is_gen', 'b0_tag_is_gen', 'fei_calib_weight',
162 'best_bp_iid', 'best_bp_dp', 'best_b0_iid', 'best_b0_dp',
163]
164event_variables = []
165for i in range(n_raw_features):
166 alias = f'ms_feat_{i:04d}'
167 vm.addAlias(alias, f'eventExtraInfo(modeSelector_feat_{i:04d})')
168 event_variables.append(alias)
169for name in event_truth_fields:
170 alias = f'ms_tr_{name}'
171 vm.addAlias(alias, f'eventExtraInfo(modeSelector_tr_{name})')
172 event_variables.append(alias)
173
174ma.variablesToNtuple(
175 '', variables=event_variables, treename='events',
176 filename=output_filename, path=my_path
177)
178
179# Candidate-level ntuple: one row per B+/B0 candidate. Rows with a set
180# ms_sig_input_id are the deduplicated true-signal candidates.
181sig_candidate_aliases = {
182 'ms_sig_input_id': 'daughter(0, extraInfo(modeSelector_trainSigInputId))',
183 'ms_sig_btag_index': 'daughter(0, mostcommonBTagIndex)',
184 'ms_sig_delta_p': 'daughter(0, mostcommonBTagDeltaP)',
185 'ms_sig_sigprob': 'daughter(0, extraInfo(SignalProbability))',
186}
187for alias, expression in sig_candidate_aliases.items():
188 vm.addAlias(alias, expression)
189
190ma.variablesToNtuple(
191 'Upsilon(4S):trainCandidates',
192 variables=list(sig_candidate_aliases.keys()),
193 treename='sig_candidates',
194 filename=output_filename, path=my_path
195)
196
197# Process events
198b2.process(my_path)
199
200print(b2.statistics)
modeSelector(bp_list, b0_list, payload_cat_model=None, payload_main_model=None, output_variable='BplusScore', cat_model_path=None, main_model_path=None, addDstarVetoReco=True, training_mode=False, skip_nn_evaluation=False, store_fei_calib_weight=False, debug=False, debug_max_events=10, path=None)
Definition __init__.py:57