Belle II Software  release-08-01-10
vxdcdc_alignment.py
1 
8 
9 """
10 
11 Simultaneous Global and Local VXD and CDC (layers-only) alignment with Millepede II
12 
13 The 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 
20 Time-dependence can be (manually) configured for VXD half-shells and CDC layers.
21 For 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 
25 Note that the first run in your requested iov will be added automatically.
26 
27 """
28 
29 from prompt import CalibrationSettings
30 from prompt.calibrations.caf_cdc import settings as cdc_calibration
31 
32 collection_names = ["physics", "cosmic", "hadron", "mumu", "offip"]
33 
34 default_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 
64 settings = 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 
73 def 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 
108 def 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 
129 def 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 
174 def get_calibrations(input_data, **kwargs):
175 
176  import basf2
177 
178  from caf.utils import IoV
179 
180  import millepede_calibration as mpc
181 
182  import alignment.constraints
183  import alignment.parameters
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 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