Belle II Software development
vxdcdc_alignment.py
1
8
9"""
10
11Simultaneous Global and Local VXD and CDC (layers-only) alignment with Millepede II
12
13The input collections can be (only single tracks currently):
14- cosmics (hlt skim) - mandatorry
15- physics - all raw data -> once off-ip is available, this can be omitted
16- hadron - for "low" momentum tracks from IP
17- mumu - mumu_2trk or mumu_tight - for high momentum tracks from IP
18- offip - not yet available - tracks from outside IP (beam background, beam-gas)
19
20Time-dependence can be (manually) configured for VXD half-shells and CDC layers.
21For example to allow VXD alignment to change in run 10, 20 an 30 in experiment 12, you set:
22
23>>> timedep_vxd : [[0, 10, 12], [0, 20, 12], [0, 30, 12]]
24
25Note that the first run in your requested iov will be added automatically.
26
27"""
28
29from prompt import CalibrationSettings
30from prompt.calibrations.caf_cdc import settings as cdc_calibration
31
32collection_names = ["physics", "cosmic", "hadron", "mumu", "offip"]
33
34default_config = {
35 'max_iterations': 3,
36 'min_entries': 1000000,
37
38 'method': 'diagonalization 3 0.1',
39 'scaleerrors': 1.,
40 'entries': 100,
41
42 'minPValue': 0.00001,
43
44 "physics.min_events": 400000,
45 "physics.max_processed_events_per_file": 2000,
46
47 "cosmic.min_events": 1000000,
48 "cosmic.max_processed_events_per_file": 5000,
49
50 "hadron.min_events": 100000,
51 "hadron.max_processed_events_per_file": 1000,
52
53 "mumu.min_events": 400000,
54 "mumu.max_processed_events_per_file": 3000,
55
56 "offip.min_events": 400000,
57 "offip.max_processed_events_per_file": 2000,
58
59 "timedep_vxd": [],
60 "timedep_cdc": []
61}
62
63
64settings = CalibrationSettings(name="VXD and CDC Alignment",
65 expert_username="bilkat",
66 description=__doc__,
67 input_data_formats=["raw"],
68 input_data_names=collection_names,
69 expert_config=default_config,
70 depends_on=[cdc_calibration])
71
72
73def select_files(all_input_files, min_events, max_processed_events_per_file):
74 import basf2
75 from random import choice
76 from prompt.utils import events_in_basf2_file
77 # Let's iterate, taking a sample of files from the total (no repeats or replacement) until we get enough events
78 total_events = 0
79 chosen_files = []
80 while total_events < min_events:
81 # If the set is empty we must have used all available files. Here we break and continue. But you may want to
82 # raise an Error...
83 if not all_input_files:
84 break
85 # Randomly select a file
86 new_file_choice = choice(all_input_files)
87 # Remove it from the list so it can't be chosen again
88 all_input_files.remove(new_file_choice)
89 # Find the number of events in the file
90 total_events_in_file = events_in_basf2_file(new_file_choice)
91 if not total_events_in_file:
92 # Uh Oh! Zero event file, skip it
93 continue
94
95 events_contributed = min(total_events_in_file, max_processed_events_per_file)
96
97 chosen_files.append(new_file_choice)
98 total_events += events_contributed
99
100 basf2.B2INFO(f"Total chosen files = {len(chosen_files)}")
101 basf2.B2INFO(f"Total events in chosen files = {total_events}")
102 if total_events < min_events:
103 basf2.B2FATAL(
104 f"There weren't enough files events selected when max_processed_events_per_file={max_processed_events_per_file}")
105 return chosen_files
106
107
108def create_std_path():
109 import basf2
110 import rawdata as raw
111 import reconstruction as reco
112
113 path = basf2.create_path()
114 path.add_module('Progress')
115 path.add_module('RootInput')
116 path.add_module('Gearbox')
117 path.add_module('Geometry')
118 raw.add_unpackers(path)
119 path.add_module('SetupGenfitExtrapolation')
120 reco.add_reconstruction(
121 path,
122 pruneTracks=False,
123 skipGeometryAdding=True,
124 )
125 path.add_module('DAFRecoFitter')
126 return path
127
128
129def create_cosmics_path():
130 import basf2
131 import rawdata as raw
132 import reconstruction as reco
133 import modularAnalysis as ana
134
135 path = basf2.create_path()
136 path.add_module('Progress')
137 # Remove all non-raw data to run the full reco again
138 path.add_module('RootInput')
139 path.add_module('Gearbox')
140 path.add_module('Geometry')
141 path.add_module(
142 "TriggerSkim",
143 triggerLines=["software_trigger_cut&filter&cosmic"]).if_value(
144 "==0",
145 basf2.Path(),
146 basf2.AfterConditionPath.END)
147
148 raw.add_unpackers(path)
149 path.add_module('SetupGenfitExtrapolation')
150 reco.add_cosmics_reconstruction(
151 path,
152 pruneTracks=False,
153 skipGeometryAdding=True,
154 addClusterExpertModules=False,
155 merge_tracks=True
156 )
157
158 path.add_module('SetRecoTrackMomentum', automatic=True)
159 path.add_module('DAFRecoFitter', pdgCodesToUseForFitting=[13])
160
161 ana.fillParticleList(
162 'mu+:goodForVXDCDCAlignment',
163 '[z0 <= 57. or abs(d0) >= 26.5] and abs(dz) > 0.4 and nTracks == 1',
164 path=path)
165 path.add_module('SkimFilter', particleLists=['mu+:goodForVXDCDCAlignment']).if_false(basf2.create_path())
166
167 return path
168
169
172
173
174def get_calibrations(input_data, **kwargs):
175
176 import basf2
177
178 from caf.utils import IoV
179
180 import millepede_calibration as mpc
181
184
185 from random import seed
186 seed(1234)
187
188 cfg = kwargs['expert_config']
189 files = dict()
190
191 for colname in collection_names:
192 file_to_iov = input_data[colname]
193 input_files = list(file_to_iov.keys())
194
195 if not len(input_files):
196 files[colname] = []
197 continue
198
199 basf2.B2INFO(f"Selecting files for: {colname}")
200 input_files = select_files(input_files[:], cfg[f'{colname}.min_events'], cfg[f'{colname}.max_processed_events_per_file'])
201 files[colname] = input_files
202
203 # Get the overall IoV we want to cover for this request, including the end values
204 requested_iov = kwargs.get("requested_iov", None)
205 # The actual value our output IoV payload should have. Notice that we've set it open ended.
206 output_iov = IoV(requested_iov.exp_low, requested_iov.run_low, -1, -1)
207
208 # Pede command options
209 method = cfg['method']
210 scaleerrors = cfg['scaleerrors']
211 entries = cfg['entries']
212
213 timedep = []
214
215 timedep_vxd = cfg['timedep_vxd']
216 timedep_cdc = cfg['timedep_cdc']
217
218 if len(timedep_vxd):
219 slices = [(erx[0], erx[1], erx[2]) for erx in timedep_vxd] + [(0, requested_iov.run_low, requested_iov.exp_low)]
220 timedep.append(
222 if len(timedep_cdc):
223 slices = [(erx[0], erx[1], erx[2]) for erx in timedep_cdc] + [(0, requested_iov.run_low, requested_iov.exp_low)]
224 timedep.append((alignment.parameters.cdc_layers(), slices))
225
226 cal = mpc.create(
227 name='VXDCDCalignment',
228 dbobjects=['VXDAlignment', 'CDCAlignment'],
229 collections=[
230 mpc.make_collection("cosmic", path=create_cosmics_path(), tracks=["RecoTracks"]),
231 mpc.make_collection("physics", path=create_std_path(), tracks=["RecoTracks"]),
232 mpc.make_collection("hadron", path=create_std_path(), tracks=["RecoTracks"]),
233 mpc.make_collection("mumu", path=create_std_path(), tracks=["RecoTracks"]),
234 mpc.make_collection("offip", path=create_std_path(), tracks=["RecoTracks"])
235 ],
236 tags=None,
237 files=files,
238 timedep=timedep,
239 constraints=[
240 alignment.constraints.VXDHierarchyConstraints(type=2, pxd=True, svd=True),
241 alignment.constraints.CDCLayerConstraints(z_offset=True, z_scale=False)
242 ],
243 fixed=alignment.parameters.vxd_sensors(rigid=False, surface2=False, surface3=False, surface4=True),
244 commands=[
245 f"method {method}",
246 f"scaleerrors {scaleerrors} {scaleerrors}",
247 f"entries {entries}"],
248 params=dict(minPValue=cfg['minPValue'], externalIterations=0),
249 min_entries=cfg['min_entries'])
250
251 for colname in collection_names:
252 max_processed_events_per_file = cfg[f'{colname}.max_processed_events_per_file']
253 basf2.set_module_parameters(
254 cal.collections[colname].pre_collector_path,
255 'RootInput',
256 entrySequences=[f'0:{max_processed_events_per_file}'])
257
258 # Bugfix for Condor:
259 from alignment.prompt_utils import fix_mille_paths_for_algo
260 fix_mille_paths_for_algo(cal.algorithms[0])
261
262 # Most values like database chain and backend args are overwritten by b2caf-prompt-run. But some can be set.
263 cal.max_iterations = cfg['max_iterations']
264
265 # Force the output payload IoV to be correct.
266 # It may be different if you are using another strategy like SequentialRunByRun so we ask you to set this up correctly.
267 for algorithm in cal.algorithms:
268 algorithm.params = {"apply_iov": output_iov}
269
270 return [cal]
def vxd_halfshells(pxd=True, svd=True, parameters=None, ying=True, yang=True, pat=True, mat=True)
Definition: parameters.py:92
def vxd_sensors(layers=None, rigid=True, surface=True, surface2=True, surface3=True, surface4=True, parameters=None)
Definition: parameters.py:157
def cdc_layers(layers=None)
Definition: parameters.py:12