Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-13 07:50:39

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include "Acts/Seeding2/detail/CandidatesForMiddleSp2.hpp"
0010 
0011 #include <limits>
0012 
0013 namespace Acts::Experimental {
0014 
0015 void CandidatesForMiddleSp2::setMaxElements(Size nLow, Size nHigh) {
0016   m_maxSizeHigh = nHigh;
0017   m_maxSizeLow = nLow;
0018 
0019   // protection against default numbers
0020   // it may cause std::bad_alloc if we don't protect
0021   if (nHigh == std::numeric_limits<Size>::max() ||
0022       nLow == std::numeric_limits<Size>::max()) {
0023     return;
0024   }
0025 
0026   // Reserve enough memory for all collections
0027   m_storage.reserve(nLow + nHigh);
0028   m_indicesHigh.reserve(nHigh);
0029   m_indicesLow.reserve(nLow);
0030 }
0031 
0032 void CandidatesForMiddleSp2::pop(std::vector<Index>& indices,
0033                                  Size& currentSize) {
0034   // Remove the candidate with the lowest weight in the collection
0035   // By construction, this element is always the first element in the
0036   // collection.
0037   // The removal works this way: the first element of the collection
0038   // is overwritten with the last element of the collection.
0039   // The number of stored elements (currentSize) is lowered by 1
0040   // The new first element is moved down in the tree to its correct position
0041   std::swap(indices[0], indices[currentSize - 1]);
0042   bubbledw(indices, 0, --currentSize);
0043 }
0044 
0045 float CandidatesForMiddleSp2::weight(const std::vector<Index>& indices,
0046                                      const Index n) const {
0047   // Get the weight of the n-th element
0048   return m_storage[indices[n]].weight;
0049 }
0050 
0051 void CandidatesForMiddleSp2::clear() {
0052   // do not clear max size, this is set only once
0053   // reset to 0 the number of stored elements
0054   m_nHigh = 0;
0055   m_nLow = 0;
0056   // Reset all values to default
0057   m_storage.clear();
0058   m_indicesHigh.clear();
0059   m_indicesLow.clear();
0060 }
0061 
0062 bool CandidatesForMiddleSp2::push(SpacePointIndex2 spB, SpacePointIndex2 spM,
0063                                   SpacePointIndex2 spT, float weight,
0064                                   float zOrigin, bool isQuality) {
0065   // Decide in which collection this candidate may be added to according to the
0066   // isQuality boolean
0067   if (isQuality) {
0068     return push(m_indicesHigh, m_nHigh, m_maxSizeHigh, spB, spM, spT, weight,
0069                 zOrigin, isQuality);
0070   }
0071   return push(m_indicesLow, m_nLow, m_maxSizeLow, spB, spM, spT, weight,
0072               zOrigin, isQuality);
0073 }
0074 
0075 bool CandidatesForMiddleSp2::push(std::vector<Index>& indices, Index& n,
0076                                   const Size nMax, const Index spB,
0077                                   const Index spM, const Index spT,
0078                                   const float weight, const float zOrigin,
0079                                   const bool isQuality) {
0080   // If we do not want to store candidates, returns
0081   if (nMax == 0) {
0082     return false;
0083   }
0084 
0085   // if there is still space, add anything
0086   if (n < nMax) {
0087     addToCollection(
0088         indices, n, nMax,
0089         TripletCandidate2(spB, spM, spT, weight, zOrigin, isQuality));
0090     return true;
0091   }
0092 
0093   // if no space, replace one if quality is enough
0094   // compare to element with lowest weight
0095   if (float lowestWeight = this->weight(indices, 0); weight <= lowestWeight) {
0096     return false;
0097   }
0098 
0099   // remove element with lower weight and add this one
0100   pop(indices, n);
0101   addToCollection(indices, n, nMax,
0102                   TripletCandidate2(spB, spM, spT, weight, zOrigin, isQuality));
0103   return true;
0104 }
0105 
0106 void CandidatesForMiddleSp2::addToCollection(std::vector<Index>& indices,
0107                                              Index& n, const Size nMax,
0108                                              const TripletCandidate2& element) {
0109   // adds elements to the end of the collection
0110   if (indices.size() == nMax) {
0111     m_storage[indices[n]] = element;
0112   } else {
0113     m_storage.push_back(element);
0114     indices.push_back(m_storage.size() - 1);
0115   }
0116   // Move the added element up in the tree to its correct position
0117   bubbleup(indices, n++);
0118 }
0119 
0120 void CandidatesForMiddleSp2::bubbledw(std::vector<Index>& indices, Index n,
0121                                       const Size actualSize) {
0122   while (n < actualSize) {
0123     // The collection of indexes are sorted as min heap trees
0124     // left child : 2 * n + 1
0125     // right child: 2 * n + 2
0126     const float current = weight(indices, n);
0127     const Index leftChild = 2 * n + 1;
0128     const Index rightChild = 2 * n + 2;
0129 
0130     // We have to move the current node down the tree to its correct position.
0131     // This is done by comparing its weight with the weights of its two
0132     // children. Few things can happen:
0133     //   - there are no children
0134     //   - the current weight is lower than the weight of the children
0135     //   - at least one of the children has a lower weight
0136     // In the first two cases we stop, since we are already in the correct
0137     // position
0138 
0139     // if there is no left child, that also means no right child is present.
0140     // We do nothing
0141     if (!exists(leftChild, actualSize)) {
0142       break;
0143     }
0144 
0145     // At least one of the children is present. Left child for sure, right child
0146     // we have to check. We take the lowest weight of the children. By default
0147     // this is the weight of the left child, and we then check for the right
0148     // child
0149 
0150     const float weightLeftChild = weight(indices, leftChild);
0151 
0152     Index selectedChild = leftChild;
0153     float selectedWeight = weightLeftChild;
0154 
0155     // Check which child has the lower weight
0156     if (exists(rightChild, actualSize)) {
0157       float weightRightChild = weight(indices, rightChild);
0158       if (weightRightChild <= weightLeftChild) {
0159         selectedChild = rightChild;
0160         selectedWeight = weightRightChild;
0161       }
0162     }
0163 
0164     // At this point we have the minimum weight of the children
0165     // We can compare this to the current weight
0166     // If weight of the children is higher we stop
0167     if (selectedWeight >= current) {
0168       break;
0169     }
0170 
0171     // swap and repeat the process
0172     std::swap(indices[n], indices[selectedChild]);
0173     n = selectedChild;
0174   }  // while loop
0175 }
0176 
0177 void CandidatesForMiddleSp2::bubbleup(std::vector<Index>& indices, Index n) {
0178   while (n != 0) {
0179     // The collection of indexes are sorted as min heap trees
0180     // parent: (n - 1) / 2;
0181     // this works because it is an integer operation
0182     const Index parentIdx = (n - 1) / 2;
0183 
0184     const float weightCurrent = weight(indices, n);
0185     // If weight of the parent is lower than this one, we stop
0186     if (float weightParent = weight(indices, parentIdx);
0187         weightParent <= weightCurrent) {
0188       break;
0189     }
0190 
0191     // swap and repeat the process
0192     std::swap(indices[n], indices[parentIdx]);
0193     n = parentIdx;
0194   }
0195 }
0196 
0197 void CandidatesForMiddleSp2::toSortedCandidates(
0198     const SpacePointContainer2& spacePoints,
0199     std::vector<TripletCandidate2>& output) {
0200   // this will retrieve the entire storage
0201   // the resulting vector is already sorted from high to low quality
0202   output.resize(m_nHigh + m_nLow);
0203   Index outIdx = output.size() - 1;
0204 
0205   // rely on the fact that m_indices* are both min heap trees
0206   // Sorting comes naturally by popping elements one by one and
0207   // placing this element at the end of the output vector
0208   while (m_nHigh != 0 || m_nLow != 0) {
0209     // no entries in collection high, we attach the entire low collection
0210     if (m_nHigh == 0) {
0211       Index idx = m_nLow;
0212       for (Index i = 0; i < idx; i++) {
0213         output[outIdx] = m_storage[m_indicesLow[0]];
0214         pop(m_indicesLow, m_nLow);
0215         outIdx--;
0216       }
0217       break;
0218     }
0219 
0220     // no entries in collection low, we attach the entire high collection
0221     if (m_nLow == 0) {
0222       Index idx = m_nHigh;
0223       for (Index i = 0; i < idx; i++) {
0224         output[outIdx] = m_storage[m_indicesHigh[0]];
0225         pop(m_indicesHigh, m_nHigh);
0226         outIdx--;
0227       }
0228       break;
0229     }
0230 
0231     // Both have entries, get the minimum
0232     if (descendingByQuality(spacePoints, m_storage[m_indicesLow[0]],
0233                             m_storage[m_indicesHigh[0]])) {
0234       output[outIdx--] = m_storage[m_indicesHigh[0]];
0235       pop(m_indicesHigh, m_nHigh);
0236     } else {
0237       output[outIdx--] = m_storage[m_indicesLow[0]];
0238       pop(m_indicesLow, m_nLow);
0239     }
0240   }  // while loop
0241 
0242   clear();
0243 }
0244 
0245 bool CandidatesForMiddleSp2::descendingByQuality(
0246     const SpacePointContainer2& spacePoints, const TripletCandidate2& i1,
0247     const TripletCandidate2& i2) {
0248   if (i1.weight != i2.weight) {
0249     return i1.weight > i2.weight;
0250   }
0251 
0252   // This is for the case when the weights from different seeds
0253   // are same. This makes cpu & cuda results same
0254 
0255   const auto bottomL1 = spacePoints[i1.bottom];
0256   const auto middleL1 = spacePoints[i1.middle];
0257   const auto topL1 = spacePoints[i1.top];
0258 
0259   const auto bottomL2 = spacePoints[i2.bottom];
0260   const auto middleL2 = spacePoints[i2.middle];
0261   const auto topL2 = spacePoints[i2.top];
0262 
0263   float seed1_sum = 0.;
0264   float seed2_sum = 0.;
0265 
0266   seed1_sum += bottomL1.y() * bottomL1.y() + bottomL1.z() * bottomL1.z();
0267   seed1_sum += middleL1.y() * middleL1.y() + middleL1.z() * middleL1.z();
0268   seed1_sum += topL1.y() * topL1.y() + topL1.z() * topL1.z();
0269 
0270   seed2_sum += bottomL2.y() * bottomL2.y() + bottomL2.z() * bottomL2.z();
0271   seed2_sum += middleL2.y() * middleL2.y() + middleL2.z() * middleL2.z();
0272   seed2_sum += topL2.y() * topL2.y() + topL2.z() * topL2.z();
0273 
0274   return seed1_sum > seed2_sum;
0275 }
0276 
0277 bool CandidatesForMiddleSp2::ascendingByQuality(
0278     const SpacePointContainer2& spacePoints, const TripletCandidate2& i1,
0279     const TripletCandidate2& i2) {
0280   return !descendingByQuality(spacePoints, i1, i2);
0281 }
0282 
0283 }  // namespace Acts::Experimental