12Scripts and functions to set the BeamParameters from known configurations
15from basf2
import B2FATAL, B2INFO
20beamparameter_defaults = {
39beamparameter_presets = {
51 "covHER": np.array([0.00513]) ** 2,
52 "covLER": np.array([0.002375]) ** 2,
54 "bunchHER": np.array([10.2e-3, 59e-6, 6.0]) * 1e-1,
55 "bunchLER": np.array([7.75e-3, 59e-6, 5.0]) * 1e-1,
57 "Y1S": (
"SuperKEKB", {
61 "Y2S": (
"SuperKEKB", {
65 "Y3S": (
"SuperKEKB", {
69 "Y4S": (
"SuperKEKB", {
73 "Y5S": (
"SuperKEKB", {
97 "Y1D1": (
"SuperKEKB", {
101 "Y2D1": (
"SuperKEKB", {
105 "Y6S": (
"SuperKEKB", {
109 "Yb10775": (
"SuperKEKB", {
113 "KEKB-Belle": (
None, {
114 "energyHER": 7.998213,
115 "energyLER": 3.499218,
123 "energyHER": 1.02 / 2.,
124 "energyLER": 1.02 / 2.,
129def __get_4vector(energy, angle):
130 """Calculate an 4vector for electron/positron from energy and angle"""
133 pz = (energy ** 2 - m ** 2) ** .5
134 v = ROOT.Math.PxPyPzEVector(0, 0, pz, energy)
136 angle = math.pi + angle
137 rotationY = ROOT.Math.RotationY(angle)
142def rot_matrix_y(angle):
143 """Return rotation matrix for a rotation of angle around the y-axis"""
146 return np.matrix([(c, 0, s), (0, 1, 0), (-s, 0, c)])
149def cov_matrix(beamsize, angle):
150 """Return the covariance matrix for the given bunch size and angle with
151 respect to the z axis"""
153 angle = math.pi + angle
154 rot = rot_matrix_y(angle)
155 cov = np.matrix(np.diag(beamsize ** 2))
156 return rot * cov * rot.T
159def calculate_beamspot(pos_her, pos_ler, size_her, size_ler, angle_her, angle_ler):
161 Function to calculate position and covariance matrix of the beamspot.
163 This function calculates the mean position
and the covariance matrix
for the
164 beamspot
from the bunch positions, bunch sizes
and the angles of the beam
165 with respect to the z-axis. It assumes normal distributed bunch densities
and
166 multiplies the PDFs
for the two bunches to get a resulting beamspot
168 negative angles are interpreted
as "math.pi - abs(angle)"
171 pos_her (list): mean position of the HER bunch (
in cm)
172 pos_ler (list): mean position of the LER bunch (
in cm)
173 size_her (list): HER bunch size
in cm
174 size_ler (list): LER bunch size
in cm
175 angle_her (float): angle between HER direction
and z-axis
176 angle_her (float): angle between LER direction
and z-axis
179 pos (array): array (x, y, z)
with the spot center
in cm
180 cov (matrix): covariance matrix of the beam spot
183 cov_her = cov_matrix(size_her, angle_her)
184 cov_ler = cov_matrix(size_ler, angle_ler)
186 cov_sum_i = (cov_her + cov_ler).I
189 cov_spot = cov_her * cov_sum_i * cov_ler
190 beampos_spot = np.array(
191 cov_ler * cov_sum_i * np.matrix(pos_her).T +
192 cov_her * cov_sum_i * np.matrix(pos_ler).T
194 return beampos_spot, cov_spot
197def add_beamparameters(path, name, E_cms=None, **argk):
198 """Add BeamParameter module to a given path.
199 Note that if you append this to the path, you will
not
200 read the configuration of BeamParameters
from the database
201 Beware that this function does
not mimic at all the behaviour
202 of the official MC samples.
204 path (basf2.Path instance): path to add the module to
205 name (str): name of the beamparameter settings to use
206 E_cms (float): center of mass energy. If
not None the beamenergies will
207 be scaled accordingly to achieve E_cms
209 Additional keyword arguments will be passed directly to the module
as parameters.
212 values = calculate_beamparameters(name, E_cms)
214 module = path.add_module(
"BeamParameters")
215 module.set_name(f
"BeamParameters:{name}")
223def calculate_beamparameters(name, E_cms=None):
224 """Get/calculate the necessary beamparameter values from the given preset name,
225 optionally scale it to achieve the given cms energy
228 name (str): name of the beamparameter settings to use
229 E_cms (float): center of mass energy. If not None the beamenergies will
230 be scaled accordingly to achieve E_cms
232 if name
not in beamparameter_presets:
233 B2FATAL(
"Unknown beamparameter preset: '%s', use one of %s" %
234 (name,
", ".join(sorted(beamparameter_presets.keys()))))
238 values = beamparameter_defaults.copy()
243 def collect_values(preset, name):
244 parent, values = beamparameter_presets[name]
245 if parent
is not None:
246 collect_values(preset, parent)
247 preset.update(values)
249 collect_values(preset, name)
252 for k
in values.keys():
254 if isinstance(preset[k], np.ndarray):
255 values[k] = list(preset[k].flat)
257 values[k] = preset[k]
260 if "bunchHER" in preset
and "bunchLER" in preset:
261 her_size = preset[
"bunchHER"]
262 ler_size = preset[
"bunchLER"]
263 her_angle = values[
"angleXHER"]
264 ler_angle = values[
"angleXLER"]
265 _, cov = calculate_beamspot(
266 [0, 0, 0], [0, 0, 0], her_size, ler_size, her_angle, ler_angle
268 values[
"covVertex"] = list(cov.flat)
270 if E_cms
is not None:
271 ler = __get_4vector(values[
"energyLER"], values[
"angleXLER"])
272 her = __get_4vector(values[
"energyHER"], values[
"angleXHER"])
273 mass = (her + ler).M()
275 B2INFO(f
"Scaling beam energies by {scale:g} to obtain E_cms = {E_cms:g} GeV")
276 values[
"energyHER"] *= scale
277 values[
"energyLER"] *= scale
282def _get_collisions_invariant_mass(experiment, run, verbose=False):
284 Convenient function for getting the collisions invariant mass by querying the BeamParameters object
in the Conditions Database.
285 Calling this function directly might have undesired side effects: users should always use
286 :func:`get_collisions_invariant_mass()`
in their steering files.
289 experiment (int): experiment number of the basf2 process
290 run (int): run number of the basf2 process
291 verbose (bool):
if True, it prints some INFO messages, e.g. the invariant mass retrieved
from the CDB
293 from ROOT
import Belle2
as B2
295 B2.DataStore.Instance().setInitializeActive(
True)
296 event_meta_data = B2.PyStoreObj(
'EventMetaData')
297 event_meta_data.registerInDataStore()
298 event_meta_data.assign(B2.EventMetaData(0, run, experiment),
True)
299 B2.DataStore.Instance().setInitializeActive(
False)
301 beams = B2.PyDBObj(
'BeamParameters')
302 if not beams.isValid():
303 B2FATAL(
'BeamParameters is not valid')
304 collisions_invariant_mass = beams.getMass()
307 B2INFO(
'Info for BeamParameters:\n'
308 f
' collisions invariant mass [GeV]: {collisions_invariant_mass}\n'
309 f
' IoV: {beams.getIoV().getExperimentLow()}, {beams.getIoV().getRunLow()}, '
310 f
'{beams.getIoV().getExperimentHigh()}. {beams.getIoV().getRunHigh()}\n'
311 f
' revision: {beams.getRevision()}\n'
312 f
' globaltag: {beams.getGlobaltag()}')
314 B2.DataStore.Instance().reset()
316 return collisions_invariant_mass
319def get_collisions_invariant_mass(experiment, run, verbose=False):
321 Convenient function for getting the collisions invariant mass by querying the BeamParameters object
in the Conditions Database.
322 It
is useful
for setting the center of mass energy when producing Monte Carlo samples
with external generators (e.g. MadGraph,
323 WHIZARD) which are
not directly interfaced
with basf2.
326 experiment (int): experiment number of the basf2 process
327 run (int): run number of the basf2 process
328 verbose (bool):
if True, it prints some INFO messages, e.g. the invariant mass retrieved
from the CDB
331 def _run_function_in_process(func, *args, **kwargs):
333 Small helper function for running another function
in a process
and thus avoiding undesired side effects.
335 from multiprocessing
import Pool
337 with Pool(processes=1)
as pool:
339 result = pool.apply_async(func, args, kwargs)
341 output = result.get()
345 return _run_function_in_process(
346 func=_get_collisions_invariant_mass, experiment=experiment, run=run, verbose=verbose
350if __name__ ==
"__main__":
355 np.set_printoptions(precision=3)
360 values = beamparameter_presets[
"SuperKEKB"][1]
362 beampos_spot, cov_spot = calculate_beamspot(
363 [0, 0, 0], [0, 0, 0],
364 values[
"bunchHER"], values[
"bunchLER"],
365 values[
"angleXHER"], values[
"angleXLER"],
368 print(
"Beamspot position:")
370 print(
"Beamspot covariance:")
372 print(
"Beamspot dimensions (in mm, axes in arbitary order):")
373 print(np.linalg.eig(cov_spot)[0] ** .5 * 10)
377 from matplotlib
import pyplot
as pl
379 cov_her = cov_matrix(values[
"bunchHER"], values[
"angleXHER"])
381 cov_ler = cov_matrix(values[
"bunchLER"], values[
"angleXLER"])
383 points_her = np.random.multivariate_normal([0, 0, 0], cov_her, 1000)
385 points_ler = np.random.multivariate_normal([0, 0, 0], cov_ler, 1000)
387 points_spot = np.random.multivariate_normal(beampos_spot, cov_spot, 1000)
389 pl.scatter(points_her[:, 2], points_her[:, 0], s=5, marker=
".", c=
"b", edgecolors=
"None", label=
"HER")
390 pl.scatter(points_ler[:, 2], points_ler[:, 0], s=5, marker=
".", c=
"r", edgecolors=
"None", label=
"LER")
391 pl.scatter(points_spot[:, 2], points_spot[:, 0], s=5, marker=
".", c=
"g", edgecolors=
"None", label=
"spot")
402 eher = values[
"energyHER"]
404 eler = values[
"energyLER"]
406 aher = values[
"angleXHER"]
408 aler = values[
"angleXLER"]
413 ler = __get_4vector(eher, aher)
415 her = __get_4vector(eler, aler)
417 mass = (her + ler).M()
418 print(
"Nominal CMS Energy: ", mass)
428 for name, energy
in sorted(targets.items()):
430 scale = energy / mass
431 print(f
""" "{name}": (
"SuperKEKB", {{
432 "energyHER": {eher * scale:.3f},
433 "energyLER": {eler * scale:.3f},
436 for name, energy
in sorted(targets.items()):
438 scale = (energy - 60e-3) / mass
443 }}),
""".format(name, name, name, energy - 60e-3, eher * scale, eler * scale))