Belle II Software development
edge_features.py
1
8
9
10import sys
11import numpy as np
12
13
14def compute_doca(name_values):
15 """
16 Computes DOCA between two tracks.
17
18 Args:
19 name_values (dict): Dictionary of numpy arrays containing px, py, pz, x, y, z.
20
21 Returns:
22 numpy.ndarray: Array containing doca values.
23 """
24 eps = 1e-7
25
26 px = name_values["px"]
27 py = name_values["py"]
28 pz = name_values["pz"]
29 x = name_values["x"]
30 y = name_values["y"]
31 z = name_values["z"]
32
33 p = np.array([px, py, pz]).T
34 r = np.array([x, y, z]).T
35
36 n_parts = len(px)
37
38 # Momenta cross-product
39 v = np.cross(p, p[:, None]).reshape(-1, 3)
40 # Norm of each cross-product
41 v_norm = np.linalg.norm(v, axis=1).reshape((-1, 1))
42 # Suppress divide by 0 warnings in the diagonal (anyway it will be ignored)
43 v_norm[v_norm == 0] = 1
44 v_u = v / v_norm
45
46 # Difference in 3-positions
47 dr = np.subtract(r, r[:, None]).reshape(-1, 3)
48 # Dot products between r and v_u
49 dr_x_vu = (
50 np.dot(dr, v_u.T).diagonal().reshape((1, -1))
51 )
52
53 # Doca computed here
54 doca = np.linalg.norm(v_u * dr_x_vu.T - dr * (v_norm < eps), axis=1).reshape(
55 n_parts, n_parts
56 )
57
58 # Remove diagonal elements and flatten
59 return doca[~np.eye(doca.shape[0], dtype=bool)]
60
61
62def compute_cosTheta(name_values):
63 """
64 Computes cosinus of angle between two tracks.
65
66 Args:
67 name_values (dict): Dictionary of numpy arrays containing p, px, py, pz.
68
69 Returns:
70 numpy.ndarray: Array containing cosinus of theta values.
71 """
72 ux = name_values["px"] / name_values["p"]
73 uy = name_values["py"] / name_values["p"]
74 uz = name_values["pz"] / name_values["p"]
75
76 u = np.array([ux, uy, uz]).T
77
78 costheta = np.inner(u, u)
79
80 # Remove diagonal elements and flatten
81 return costheta[~np.eye(costheta.shape[0], dtype=bool)]
82
83
84# Put here available features with respective functions (prepend edge_ to the name)
85available_features = {
86 "edge_costheta": compute_cosTheta,
87 "edge_doca": compute_doca,
88}
89
90
91def _available_edge_features(feat, name_values):
92 """
93 Returns value of edge feature if contained in dictionary available_features.
94 """
95 if feat not in available_features:
96 sys.exit(
97 "Requested edge feature not available, but you could add it in grafei/data/edge_features.py!"
98 )
99
100 return available_features[feat](name_values)
101
102
103def compute_edge_features(edge_feature_names, features, x):
104 """
105 Computes a series of edge features starting from node features.
106
107 Args:
108 edge_feature_names (list): List of edge features names.
109 features (list): List of node feature names.
110 x (numpy.ndarray): Array of node features.
111
112 Returns:
113 numpy.ndarray: Array of edge features.
114 """
115
116 # Will be filled and converted to np.ndarray of shape [E, F_e] with
117 # E=nodes*(nodes-1) (assume no self-interactions) and F_e number of edge features
118 edge_features = []
119 # Remove `feat_` from feature names
120 features = [f.replace("feat_", "") for f in features]
121
122 # Associate node feature names with values
123 name_values = dict(zip(features, x.T))
124
125 # Compute edge features
126 for feat in edge_feature_names:
127 feature_values = _available_edge_features(feat, name_values)
128 edge_features.append(feature_values)
129
130 return np.array(edge_features).T