Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CandidatesForMiddleSp.ipp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file CandidatesForMiddleSp.ipp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2022 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 namespace Acts {
10 
11 template <typename external_space_point_t>
13  std::size_t n_low, std::size_t n_high) {
14  m_max_size_high = n_high;
15  m_max_size_low = n_low;
16 
17  // protection against default numbers
18  // it may cause std::bad_alloc if we don't protect
19  if (n_high == std::numeric_limits<std::size_t>::max() or
20  n_low == std::numeric_limits<std::size_t>::max()) {
21  return;
22  }
23 
24  // Reserve enough memory for all collections
25  m_storage.reserve(n_low + n_high);
26  m_indices_high.reserve(n_high);
27  m_indices_low.reserve(n_low);
28 }
29 
30 template <typename external_space_point_t>
32  std::vector<std::size_t>& indices, std::size_t& current_size) {
33  // Remove the candidate with the lowest weight in the collection
34  // By construction, this element is always the first element in the
35  // collection.
36  // The removal works this way: the first element of the collection
37  // is overwritten with the last element of the collection.
38  // The number of stored elements (current_size) is lowered by 1
39  // The new first element is moved down in the tree to its correct position
40  std::swap(indices[0], indices[current_size - 1]);
41  bubbledw(indices, 0, --current_size);
42 }
43 
44 template <typename external_space_point_t>
46  const std::size_t n, const std::size_t max_size) const {
47  // If the element exists, its index is lower than the current number
48  // of stored elements
49  return n < max_size;
50 }
51 
52 template <typename external_space_point_t>
54  const std::vector<std::size_t>& indices, std::size_t n) const {
55  // Get the weight of the n-th element
56  return m_storage[indices[n]].weight;
57 }
58 
59 template <typename external_space_point_t>
61  // do not clear max size, this is set only once
62  // reset to 0 the number of stored elements
63  m_n_high = 0;
64  m_n_low = 0;
65  // Reset all values to default
66  m_storage.clear();
67  m_indices_high.clear();
68  m_indices_low.clear();
69 }
70 
71 template <typename external_space_point_t>
73  external_space_point_t& SpB, external_space_point_t& SpM,
74  external_space_point_t& SpT, float weight, float zOrigin, bool isQuality) {
75  // Decide in which collection this candidate may be added to according to the
76  // isQuality boolean
77  if (isQuality) {
78  return push(m_indices_high, m_n_high, m_max_size_high, SpB, SpM, SpT,
79  weight, zOrigin, isQuality);
80  }
81  return push(m_indices_low, m_n_low, m_max_size_low, SpB, SpM, SpT, weight,
82  zOrigin, isQuality);
83 }
84 
85 template <typename external_space_point_t>
87  std::vector<std::size_t>& indices, std::size_t& n, const std::size_t n_max,
88  external_space_point_t& SpB, external_space_point_t& SpM,
89  external_space_point_t& SpT, float weight, float zOrigin, bool isQuality) {
90  // If we do not want to store candidates, returns
91  if (n_max == 0) {
92  return false;
93  }
94 
95  // if there is still space, add anything
96  if (n < n_max) {
97  addToCollection(indices, n, n_max,
98  value_type(SpB, SpM, SpT, weight, zOrigin, isQuality));
99  return true;
100  }
101 
102  // if no space, replace one if quality is enough
103  // compare to element with lowest weight
104  const auto& lowest_weight = this->weight(indices, 0);
105  if (weight <= lowest_weight) {
106  return false;
107  }
108 
109  // remove element with lower weight and add this one
110  pop(indices, n);
111  addToCollection(indices, n, n_max,
112  value_type(SpB, SpM, SpT, weight, zOrigin, isQuality));
113  return true;
114 }
115 
116 template <typename external_space_point_t>
118  std::vector<std::size_t>& indices, std::size_t& n, const std::size_t n_max,
119  value_type&& element) {
120  // adds elements to the end of the collection
121  if (indices.size() == n_max) {
122  m_storage[indices[n]] = std::move(element);
123  } else {
124  m_storage.push_back(std::move(element));
125  indices.push_back(m_storage.size() - 1);
126  }
127  // Move the added element up in the tree to its correct position
128  bubbleup(indices, n++);
129 }
130 
131 template <typename external_space_point_t>
133  std::vector<std::size_t>& indices, std::size_t n, std::size_t actual_size) {
134  while (n < actual_size) {
135  // The collection of indexes are sorted as min heap trees
136  // left child : 2 * n + 1
137  // right child: 2 * n + 2
138  float current = weight(indices, n);
139  std::size_t left_child = 2 * n + 1;
140  std::size_t right_child = 2 * n + 2;
141 
142  // We have to move the current node down the tree to its correct position.
143  // This is done by comparing its weight with the weights of its two
144  // children. Few things can happen:
145  // - there are no children
146  // - the current weight is lower than the weight of the children
147  // - at least one of the children has a lower weight
148  // In the first two cases we stop, since we are already in the correct
149  // position
150 
151  // if there is no left child, that also means no right child is present.
152  // We do nothing
153  if (not exists(left_child, actual_size)) {
154  break;
155  }
156 
157  // At least one of the child is present. Left child for sure, right child we
158  // have to check. We take the lowest weight of the children. By default this
159  // is the weight of the left child, and we then check for the right child
160 
161  float weight_left_child = weight(indices, left_child);
162 
163  std::size_t selected_child = left_child;
164  float selected_weight = weight_left_child;
165 
166  // Check which child has the lower weight
167  if (exists(right_child, actual_size)) {
168  float weight_right_child = weight(indices, right_child);
169  if (weight_right_child <= weight_left_child) {
170  selected_child = right_child;
171  selected_weight = weight_right_child;
172  }
173  }
174 
175  // At this point we have the minimum weight of the children
176  // We can compare this to the current weight
177  // If weight of the children is higher we stop
178  if (selected_weight >= current) {
179  break;
180  }
181 
182  // swap and repeat the process
183  std::swap(indices[n], indices[selected_child]);
184  n = selected_child;
185  } // while loop
186 }
187 
188 template <typename external_space_point_t>
190  std::vector<std::size_t>& indices, std::size_t n) {
191  while (n != 0) {
192  // The collection of indexes are sorted as min heap trees
193  // parent: (n - 1) / 2;
194  // this works because it is an integer operation
195  std::size_t parent_idx = (n - 1) / 2;
196 
197  float weight_current = weight(indices, n);
198  float weight_parent = weight(indices, parent_idx);
199 
200  // If weight of the parent is lower than this one, we stop
201  if (weight_parent <= weight_current) {
202  break;
203  }
204 
205  // swap and repeat the process
206  std::swap(indices[n], indices[parent_idx]);
207  n = parent_idx;
208  }
209 }
210 
211 template <typename external_space_point_t>
214  // this will retrieve the entire storage
215  // the resulting vector is already sorted from high to low quality
216  std::vector<value_type> output(m_n_high + m_n_low);
217  std::size_t out_idx = output.size() - 1;
218 
219  // rely on the fact that m_indices_* are both min heap trees
220  // Sorting comes naturally by popping elements one by one and
221  // placing this element at the end of the output vector
222  while (m_n_high != 0 or m_n_low != 0) {
223  // no entries in collection high, we attach the entire low collection
224  if (m_n_high == 0) {
225  std::size_t idx = m_n_low;
226  for (std::size_t i(0); i < idx; i++) {
227  output[out_idx--] = std::move(m_storage[m_indices_low[0]]);
228  pop(m_indices_low, m_n_low);
229  }
230  break;
231  }
232 
233  // no entries in collection low, we attach the entire high collection
234  if (m_n_low == 0) {
235  std::size_t idx = m_n_high;
236  for (std::size_t i(0); i < idx; i++) {
237  output[out_idx--] = std::move(m_storage[m_indices_high[0]]);
238  pop(m_indices_high, m_n_high);
239  }
240  break;
241  }
242 
243  // Both have entries, get the minimum
244  if (descendingByQuality(m_storage[m_indices_low[0]],
245  m_storage[m_indices_high[0]])) {
246  output[out_idx--] = std::move(m_storage[m_indices_high[0]]);
247  pop(m_indices_high, m_n_high);
248  } else {
249  output[out_idx--] = std::move(m_storage[m_indices_low[0]]);
250  pop(m_indices_low, m_n_low);
251  }
252 
253  } // while loop
254 
255  clear();
256  return output;
257 }
258 
259 template <typename external_space_point_t>
261  const value_type& i1, const value_type& i2) {
262  if (i1.weight != i2.weight) {
263  return i1.weight > i2.weight;
264  }
265 
266  // This is for the case when the weights from different seeds
267  // are same. This makes cpu & cuda results same
268 
269  const auto& bottom_l1 = i1.bottom;
270  const auto& middle_l1 = i1.middle;
271  const auto& top_l1 = i1.top;
272 
273  const auto& bottom_l2 = i2.bottom;
274  const auto& middle_l2 = i2.middle;
275  const auto& top_l2 = i2.top;
276 
277  float seed1_sum = 0.;
278  float seed2_sum = 0.;
279 
280  seed1_sum +=
281  bottom_l1->y() * bottom_l1->y() + bottom_l1->z() * bottom_l1->z();
282  seed1_sum +=
283  middle_l1->y() * middle_l1->y() + middle_l1->z() * middle_l1->z();
284  seed1_sum += top_l1->y() * top_l1->y() + top_l1->z() * top_l1->z();
285 
286  seed2_sum +=
287  bottom_l2->y() * bottom_l2->y() + bottom_l2->z() * bottom_l2->z();
288  seed2_sum +=
289  middle_l2->y() * middle_l2->y() + middle_l2->z() * middle_l2->z();
290  seed2_sum += top_l2->y() * top_l2->y() + top_l2->z() * top_l2->z();
291 
292  return seed1_sum > seed2_sum;
293 }
294 
295 template <typename external_space_point_t>
297  const value_type& i1, const value_type& i2) {
298  return not descendingByQuality(i1, i2);
299 }
300 
301 } // namespace Acts