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