5 Scripts and functions to set the BeamParameters from known configurations
8 from basf2
import B2FATAL, B2INFO
13 beamparameter_defaults = {
32 beamparameter_presets = {
44 "covHER": np.array([0.00513]) ** 2,
45 "covLER": np.array([0.002375]) ** 2,
47 "bunchHER": np.array([10.2e-3, 59e-6, 6.0]) * 1e-1,
48 "bunchLER": np.array([7.75e-3, 59e-6, 5.0]) * 1e-1,
50 "Y1S": (
"SuperKEKB", {
54 "Y2S": (
"SuperKEKB", {
58 "Y3S": (
"SuperKEKB", {
62 "Y4S": (
"SuperKEKB", {
66 "Y5S": (
"SuperKEKB", {
90 "Y1D1": (
"SuperKEKB", {
94 "Y2D1": (
"SuperKEKB", {
98 "Y6S": (
"SuperKEKB", {
102 "Yb10775": (
"SuperKEKB", {
106 "KEKB-Belle": (
None, {
107 "energyHER": 7.998213,
108 "energyLER": 3.499218,
116 "energyHER": 1.02 / 2.,
117 "energyLER": 1.02 / 2.,
122 def __get_4vector(energy, angle):
123 """Calculate an 4vector for electron/positron from energy and angle"""
126 pz = (energy ** 2 - m ** 2) ** .5
127 v = ROOT.TLorentzVector(0, 0, pz, energy)
129 angle = math.pi + angle
134 def rot_matrix_y(angle):
135 """Return rotation matrix for a rotation of angle around the y-axis"""
138 return np.matrix([(c, 0, s), (0, 1, 0), (-s, 0, c)])
141 def cov_matrix(beamsize, angle):
142 """Return the covariance matrix for the given bunch size and angle with
143 respect to the z axis"""
145 angle = math.pi + angle
146 rot = rot_matrix_y(angle)
147 cov = np.matrix(np.diag(beamsize ** 2))
148 return rot * cov * rot.T
151 def calculate_beamspot(pos_her, pos_ler, size_her, size_ler, angle_her, angle_ler):
153 Function to calculate position and covariance matrix of the beamspot.
155 This function calculates the mean position and the covariance matrix for the
156 beamspot from the bunch positions, bunch sizes and the angles of the beam
157 with respect to the z-axis. It assumes normal distributed bunch densities and
158 multiplies the PDFs for the two bunches to get a resulting beamspot
160 negative angles are interpreted as "math.pi - abs(angle)"
163 pos_her (list): mean position of the HER bunch (in cm)
164 pos_ler (list): mean position of the LER bunch (in cm)
165 size_her (list): HER bunch size in cm
166 size_ler (list): LER bunch size in cm
167 angle_her (float): angle between HER direction and z-axis
168 angle_her (float): angle between LER direction and z-axis
171 pos (array): array (x, y, z) with the spot center in cm
172 cov (matrix): covariance matrix of the beam spot
175 cov_her = cov_matrix(size_her, angle_her)
176 cov_ler = cov_matrix(size_ler, angle_ler)
178 cov_sum_i = (cov_her + cov_ler).I
181 cov_spot = cov_her * cov_sum_i * cov_ler
182 beampos_spot = np.array(
183 cov_ler * cov_sum_i * np.matrix(pos_her).T +
184 cov_her * cov_sum_i * np.matrix(pos_ler).T
186 return beampos_spot, cov_spot
189 def add_beamparameters(path, name, E_cms=None, **argk):
190 """Add BeamParameter module to a given path
193 path (basf2.Path instance): path to add the module to
194 name (str): name of the beamparameter settings to use
195 E_cms (float): center of mass energy. If not None the beamenergies will
196 be scaled accordingly to achieve E_cms
198 Additional keyword arguments will be passed directly to the module as parameters.
201 values = calculate_beamparameters(name, E_cms)
203 module = path.add_module(
"BeamParameters")
204 module.set_name(
"BeamParameters:%s" % name)
212 def calculate_beamparameters(name, E_cms=None):
213 """Get/calculate the necessary beamparameter values from the given preset name,
214 optionally scale it to achieve the given cms energy
217 name (str): name of the beamparameter settings to use
218 E_cms (float): center of mass energy. If not None the beamenergies will
219 be scaled accordingly to achieve E_cms
221 if name
not in beamparameter_presets:
222 B2FATAL(
"Unknown beamparameter preset: '%s', use one of %s" %
223 (name,
", ".join(sorted(beamparameter_presets.keys()))))
227 values = beamparameter_defaults.copy()
232 def collect_values(preset, name):
233 parent, values = beamparameter_presets[name]
234 if parent
is not None:
235 collect_values(preset, parent)
236 preset.update(values)
238 collect_values(preset, name)
241 for k
in values.keys():
243 if isinstance(preset[k], np.ndarray):
244 values[k] = list(preset[k].flat)
246 values[k] = preset[k]
249 if "bunchHER" in preset
and "bunchLER" in preset:
250 her_size = preset[
"bunchHER"]
251 ler_size = preset[
"bunchLER"]
252 her_angle = values[
"angleXHER"]
253 ler_angle = values[
"angleXLER"]
254 _, cov = calculate_beamspot(
255 [0, 0, 0], [0, 0, 0], her_size, ler_size, her_angle, ler_angle
257 values[
"covVertex"] = list(cov.flat)
259 if E_cms
is not None:
260 ler = __get_4vector(values[
"energyLER"], values[
"angleXLER"])
261 her = __get_4vector(values[
"energyHER"], values[
"angleXHER"])
262 mass = (her + ler).M()
264 B2INFO(
"Scaling beam energies by %g to obtain E_cms = %g GeV" % (scale, E_cms))
265 values[
"energyHER"] *= scale
266 values[
"energyLER"] *= scale
271 if __name__ ==
"__main__":
275 np.set_printoptions(precision=3)
279 values = beamparameter_presets[
"SuperKEKB"][1]
280 beampos_spot, cov_spot = calculate_beamspot(
281 [0, 0, 0], [0, 0, 0],
282 values[
"bunchHER"], values[
"bunchLER"],
283 values[
"angleXHER"], values[
"angleXLER"],
285 print(
"Beamspot position:")
287 print(
"Beamspot covariance:")
289 print(
"Beamspot dimensions (in mm, axes in arbitary order):")
290 print(np.linalg.eig(cov_spot)[0] ** .5 * 10)
294 from matplotlib
import pyplot
as pl
296 cov_her = cov_matrix(values[
"bunchHER"], values[
"angleXHER"])
298 cov_ler = cov_matrix(values[
"bunchLER"], values[
"angleXLER"])
300 points_her = np.random.multivariate_normal([0, 0, 0], cov_her, 1000)
302 points_ler = np.random.multivariate_normal([0, 0, 0], cov_ler, 1000)
304 points_spot = np.random.multivariate_normal(beampos_spot, cov_spot, 1000)
305 pl.scatter(points_her[:, 2], points_her[:, 0], s=5, marker=
".", c=
"b", edgecolors=
"None", label=
"HER")
306 pl.scatter(points_ler[:, 2], points_ler[:, 0], s=5, marker=
".", c=
"r", edgecolors=
"None", label=
"LER")
307 pl.scatter(points_spot[:, 2], points_spot[:, 0], s=5, marker=
".", c=
"g", edgecolors=
"None", label=
"spot")
317 eher = values[
"energyHER"]
319 eler = values[
"energyLER"]
321 aher = values[
"angleXHER"]
323 aler = values[
"angleXLER"]
328 ler = __get_4vector(eher, aher)
330 her = __get_4vector(eler, aler)
332 mass = (her + ler).M()
333 print(
"Nominal CMS Energy: ", mass)
343 for name, energy
in sorted(targets.items()):
345 scale = energy / mass
347 "%s": ("SuperKEKB", { # m(%s) = %.3f GeV
350 }),""" % (name, name, energy, eher * scale, eler * scale))
352 for name, energy
in sorted(targets.items()):
354 scale = (energy - 60e-3) / mass
356 "%s-off": ("%s", { # m(%s) - 60 MeV = %.3f GeV
359 }),""" % (name, name, name, energy - 60e-3, eher * scale, eler * scale))