Belle II Software  release-06-02-00
particleWeighting.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 from basf2 import B2FATAL, B2RESULT, Path, process, conditions, register_module
13 import b2test_utils
14 import modularAnalysis as ma
15 from variables import variables
16 import random
17 from ROOT import TFile
18 
19 
24 
25 # Add some bin constructors
26 
27 
28 def make_1D_bin(name, min_val, max_val):
29  return {name: [min_val, max_val]}
30 
31 
32 def make_2D_bin(bin_x, bin_y):
33  bin_2d = bin_x.copy()
34  bin_2d.update(bin_y)
35  return bin_2d
36 
37 
38 def make_3D_bin(bin_x, bin_y, bin_z):
39  bin_3d = bin_x.copy()
40  bin_3d.update(bin_y).update(bin_z)
41  return bin_3d
42 
43 
44 def check(ntupleName, treeName):
45  """
46  Verify results make sense.
47  """
48  ntuplefile = TFile(ntupleName)
49  ntuple = ntuplefile.Get(treeName)
50 
51  if ntuple.GetEntries() == 0:
52  B2FATAL("No pions saved")
53 
54  if not(ntuple.GetEntries("binID > 0 ") > 0):
55  B2FATAL("Binning was applied incorrectly: no pions in physical bins")
56  else:
57  B2RESULT("Bins are defined")
58 
59  if not(ntuple.GetEntries("Weight > 0") > 0):
60  B2FATAL("Weights are not applied")
61  else:
62  B2RESULT("Weights are applied")
63 
64 
70 
71 
72 # Define bin ranges. Bins may be of different size
73 # They shouldn't event cover the whole parameter space
74 bins_x = [make_1D_bin("p", 0, 2),
75  make_1D_bin("p", 2, 3),
76  make_1D_bin("p", 3, 4)]
77 
78 bins_y = [make_1D_bin("pz", 0, 1),
79  make_1D_bin("pz", 1, 5)]
80 
81 
82 # Here would be input from the experts.
83 # We don't have real calibration tables yet
84 # So we use randomized info.
85 # Bin IDs will be automatically assigned as follows:
86 #
87 # p|0-2|2-3|3-4|
88 # pz| | | |
89 # -------------
90 # 0-1| 0 | 2 | 4 |
91 # ---------------|
92 # 1-5| 1 | 3 | 5 |
93 # -------------
94 
95 tableIDNotSpec = []
96 random.seed()
97 for xbin in bins_x:
98  for ybin in bins_y:
99  weightInfo = {}
100  weightInfo["Weight"] = float(random.randint(0, 100)) / 100
101  weightInfo["StatErr"] = float(random.randint(100, 200)) / 100
102  weightInfo["SystErr"] = float(10)
103  tableIDNotSpec.append([weightInfo, make_2D_bin(xbin, ybin)])
104 
105 # Now let's assign binIDs manually (to be able to assign identical IDs for different bins)
106 # Let's do this structure of bins (out-of-range bin -1 is assigned later):
107 #
108 # p|0-2|2-3|3-4|
109 # pz| | | |
110 # ---------------|
111 # | |
112 # ------------- |
113 # 0-1| 43| 45| | |
114 # ------------ | |
115 # 1-5| 44| 46| |
116 # ------------- |
117 # | -1|
118 # ---------------|
119 tableIDSpec = []
120 random.seed()
121 binID = 42
122 weightInfo = {}
123 for xbin in bins_x:
124  for ybin in bins_y:
125  if binID < 46:
126  binID += 1
127  weightInfo = {}
128  weightInfo["Weight"] = float(random.randint(0, 100)) / 100
129  weightInfo["StatErr"] = float(random.randint(100, 200)) / 100
130  weightInfo["SystErr"] = float(10)
131  tableIDSpec.append([[weightInfo, make_2D_bin(xbin, ybin)], binID])
132 
133 # And of course let's define out-of-range bin info
134 outOfRangeWeightInfo = {}
135 outOfRangeWeightInfo["Weight"] = -1
136 outOfRangeWeightInfo["StatErr"] = -1
137 outOfRangeWeightInfo["SystErr"] = -1
138 
139 # we create payloads so let's switch to an empty, temporary directory
141  conditions.testing_payloads = ["localdb/database.txt"]
142 
143  # Now, let's configure table creator
144  addtable = register_module('ParticleWeightingLookUpCreator')
145  addtable.param('tableIDNotSpec', tableIDNotSpec)
146  addtable.param('outOfRangeWeight', outOfRangeWeightInfo)
147  addtable.param('experimentHigh', 1003)
148  addtable.param('experimentLow', 1003)
149  addtable.param('runHigh', 1000)
150  addtable.param('runLow', 0)
151  addtable.param('tableName', "ParticleReweighting:TestMomentum")
152 
153  addtable2 = register_module('ParticleWeightingLookUpCreator')
154  addtable2.param('tableIDSpec', tableIDSpec)
155  addtable2.param('outOfRangeWeight', outOfRangeWeightInfo)
156  addtable2.param('experimentHigh', 1003)
157  addtable2.param('experimentLow', 1003)
158  addtable2.param('runHigh', 1000)
159  addtable2.param('runLow', 0)
160  addtable2.param('tableName', "ParticleReweighting:TestMomentum2")
161 
162  testpath = Path()
163  testpath.add_module(addtable)
164  testpath.add_module(addtable2)
165  testpath.add_module('EventInfoSetter', evtNumList=[100], runList=[0], expList=[1003])
166 
167  # Process the events to create database payloads
168  process(testpath)
169  B2RESULT("Weights are created and loaded to DB")
170 
171  # Now, let's test if it weights are applied
172  main = Path()
173  ntupleName = 'particleWeighting.root'
174  treeName = 'pitree'
175  inputfile = b2test_utils.require_file('analysis/tests/mdst.root')
176  ma.inputMdst("default", inputfile, path=main)
177 
178  # use the MC truth information to generate pion lists
179  ma.fillParticleListFromMC('pi+:gen', '', path=main)
180 
181  # ID of weight table is taken from B2A904
182  weight_table_id = "ParticleReweighting:TestMomentum"
183 
184  # We know what weight info will be added (see B2A904),
185  # so we add aliases and add it to tools
186  variables.addAlias('Weight', 'extraInfo(' + weight_table_id + '_Weight)')
187  variables.addAlias('StatErr', 'extraInfo(' + weight_table_id + '_StatErr)')
188  variables.addAlias('SystErr', 'extraInfo(' + weight_table_id + '_SystErr)')
189  variables.addAlias('binID', 'extraInfo(' + weight_table_id + '_binID)')
190  varsPi = ['p', 'pz', 'Weight', 'StatErr', 'SystErr', 'binID']
191 
192  # We configure weighing module
193  reweighter = register_module('ParticleWeighting')
194  reweighter.param('tableName', weight_table_id)
195  reweighter.param('particleList', 'pi+:gen')
196  main.add_module(reweighter)
197 
198  # write out the flat ntuple
199  ma.variablesToNtuple('pi+:gen', varsPi, filename=ntupleName, treename=treeName, path=main)
200 
201  # Process the events
203 
204  check(ntupleName, treeName)
205 
206 B2RESULT("Weights were applied correctly")
def require_file(filename, data_type="", py_case=None)
Definition: __init__.py:54
def clean_working_directory()
Definition: __init__.py:185
def safe_process(*args, **kwargs)
Definition: __init__.py:233