Belle II Software  light-2403-persian
edge_features.py
1 
8 
9 
10 import sys
11 import numpy as np
12 
13 
14 def 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 
62 def 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)
85 available_features = {
86  "edge_costheta": compute_cosTheta,
87  "edge_doca": compute_doca,
88 }
89 
90 
91 def _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 
103 def 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