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