Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SeedFilter.ipp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file SeedFilter.ipp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2023 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 #include <algorithm>
10 #include <numeric>
11 #include <utility>
12 
13 namespace Acts {
14 // constructor
15 template <typename external_spacepoint_t>
19  : m_cfg(config), m_experimentCuts(expCuts) {
20  if (not config.isInInternalUnits) {
21  throw std::runtime_error(
22  "SeedFilterConfig not in ACTS internal units in SeedFilter");
23  }
24 }
25 // function to filter seeds based on all seeds with same bottom- and
26 // middle-spacepoint.
27 // return vector must contain weight of each seed
28 template <typename external_spacepoint_t>
30  Acts::SpacePointData& spacePointData,
33  const std::vector<const InternalSpacePoint<external_spacepoint_t>*>&
34  topSpVec,
35  const std::vector<float>& invHelixDiameterVec,
36  const std::vector<float>& impactParametersVec,
37  SeedFilterState& seedFilterState,
39  candidates_collector) const {
40  // seed confirmation
41  SeedConfirmationRangeConfig seedConfRange;
42  if (m_cfg.seedConfirmation) {
43  // check if bottom SP is in the central or forward region
44  seedConfRange =
45  (bottomSP.z() > m_cfg.centralSeedConfirmationRange.zMaxSeedConf ||
46  bottomSP.z() < m_cfg.centralSeedConfirmationRange.zMinSeedConf)
47  ? m_cfg.forwardSeedConfirmationRange
48  : m_cfg.centralSeedConfirmationRange;
49  // set the minimum number of top SP depending on whether the bottom SP is
50  // in the central or forward region
51  seedFilterState.nTopSeedConf =
52  bottomSP.radius() > seedConfRange.rMaxSeedConf
53  ? seedConfRange.nTopForLargeR
54  : seedConfRange.nTopForSmallR;
55  }
56 
57  size_t maxWeightSeedIndex = 0;
58  bool maxWeightSeed = false;
59  float weightMax = std::numeric_limits<float>::lowest();
60  float zOrigin = seedFilterState.zOrigin;
61 
62  // initialize original index locations
63  std::vector<size_t> topSPIndexVec(topSpVec.size());
64  for (std::size_t i(0); i < topSPIndexVec.size(); ++i) {
65  topSPIndexVec[i] = i;
66  }
67 
68  if (topSpVec.size() > 2) {
69  // sort indexes based on comparing values in invHelixDiameterVec
70  std::sort(topSPIndexVec.begin(), topSPIndexVec.end(),
71  [&invHelixDiameterVec](const size_t i1, const size_t i2) {
72  return invHelixDiameterVec[i1] < invHelixDiameterVec[i2];
73  });
74  }
75 
76  // vector containing the radius of all compatible seeds
77  std::vector<float> compatibleSeedR;
78  compatibleSeedR.reserve(m_cfg.compatSeedLimit);
79 
80  size_t beginCompTopIndex = 0;
81  // loop over top SPs and other compatible top SP candidates
82  for (const std::size_t topSPIndex : topSPIndexVec) {
83  // if two compatible seeds with high distance in r are found, compatible
84  // seeds span 5 layers
85  compatibleSeedR.clear();
86 
87  float invHelixDiameter = invHelixDiameterVec[topSPIndex];
88  float lowerLimitCurv = invHelixDiameter - m_cfg.deltaInvHelixDiameter;
89  float upperLimitCurv = invHelixDiameter + m_cfg.deltaInvHelixDiameter;
90  // use deltaR instead of top radius
91  float currentTopR =
92  m_cfg.useDeltaRorTopRadius
93  ? spacePointData.deltaR(topSpVec[topSPIndex]->index())
94  : topSpVec[topSPIndex]->radius();
95  float impact = impactParametersVec[topSPIndex];
96 
97  float weight = -(impact * m_cfg.impactWeightFactor);
98 
99  // loop over compatible top SP candidates
100  for (size_t variableCompTopIndex = beginCompTopIndex;
101  variableCompTopIndex < topSPIndexVec.size(); variableCompTopIndex++) {
102  size_t compatibleTopSPIndex = topSPIndexVec[variableCompTopIndex];
103  if (compatibleTopSPIndex == topSPIndex) {
104  continue;
105  }
106 
107  float otherTopR =
108  m_cfg.useDeltaRorTopRadius
109  ? spacePointData.deltaR(topSpVec[compatibleTopSPIndex]->index())
110  : topSpVec[compatibleTopSPIndex]->radius();
111 
112  // curvature difference within limits?
113  if (invHelixDiameterVec[compatibleTopSPIndex] < lowerLimitCurv) {
114  // the SPs are sorted in curvature so we skip unnecessary iterations
115  beginCompTopIndex = variableCompTopIndex + 1;
116  continue;
117  }
118  if (invHelixDiameterVec[compatibleTopSPIndex] > upperLimitCurv) {
119  // the SPs are sorted in curvature so we skip unnecessary iterations
120  break;
121  }
122  // compared top SP should have at least deltaRMin distance
123  float deltaR = currentTopR - otherTopR;
124  if (std::abs(deltaR) < m_cfg.deltaRMin) {
125  continue;
126  }
127  bool newCompSeed = true;
128  for (const float previousDiameter : compatibleSeedR) {
129  // original ATLAS code uses higher min distance for 2nd found compatible
130  // seed (20mm instead of 5mm)
131  // add new compatible seed only if distance larger than rmin to all
132  // other compatible seeds
133  if (std::abs(previousDiameter - otherTopR) < m_cfg.deltaRMin) {
134  newCompSeed = false;
135  break;
136  }
137  }
138  if (newCompSeed) {
139  compatibleSeedR.push_back(otherTopR);
140  weight += m_cfg.compatSeedWeight;
141  }
142  if (compatibleSeedR.size() >= m_cfg.compatSeedLimit) {
143  break;
144  }
145  }
146 
147  if (m_experimentCuts != nullptr) {
148  // add detector specific considerations on the seed weight
149  weight += m_experimentCuts->seedWeight(bottomSP, middleSP,
150  *topSpVec[topSPIndex]);
151  // discard seeds according to detector specific cuts (e.g.: weight)
152  if (!m_experimentCuts->singleSeedCut(weight, bottomSP, middleSP,
153  *topSpVec[topSPIndex])) {
154  continue;
155  }
156  }
157 
158  // increment in seed weight if number of compatible seeds is larger than
159  // numSeedIncrement
160  if (compatibleSeedR.size() > m_cfg.numSeedIncrement) {
161  weight += m_cfg.seedWeightIncrement;
162  }
163 
164  if (m_cfg.seedConfirmation) {
165  // seed confirmation cuts - keep seeds if they have specific values of
166  // impact parameter, z-origin and number of compatible seeds inside a
167  // pre-defined range that also depends on the region of the detector (i.e.
168  // forward or central region) defined by SeedConfirmationRange
169  int deltaSeedConf =
170  compatibleSeedR.size() + 1 - seedFilterState.nTopSeedConf;
171  if (deltaSeedConf < 0 ||
172  (seedFilterState.numQualitySeeds != 0 and deltaSeedConf == 0)) {
173  continue;
174  }
175  bool seedRangeCuts =
176  bottomSP.radius() < seedConfRange.seedConfMinBottomRadius ||
177  std::abs(zOrigin) > seedConfRange.seedConfMaxZOrigin;
178  if (seedRangeCuts and deltaSeedConf == 0 and
179  impact > seedConfRange.minImpactSeedConf) {
180  continue;
181  }
182 
183  // term on the weight that depends on the value of zOrigin
184  weight += -(std::abs(zOrigin) * m_cfg.zOriginWeightFactor) +
185  m_cfg.compatSeedWeight;
186 
187  // skip a bad quality seed if any of its constituents has a weight larger
188  // than the seed weight
189  if (weight < spacePointData.quality(bottomSP.index()) and
190  weight < spacePointData.quality(middleSP.index()) and
191  weight < spacePointData.quality(topSpVec[topSPIndex]->index())) {
192  continue;
193  }
194 
195  if (deltaSeedConf > 0) {
196  // if we have not yet reached our max number of quality seeds we add the
197  // new seed to outCont
198 
199  // Internally, "push" will also check the max number of quality seeds
200  // for a middle sp.
201  // If this is reached, we remove the seed with the lowest weight.
202  candidates_collector.push(bottomSP, middleSP, *topSpVec[topSPIndex],
203  weight, zOrigin, true);
204  if (seedFilterState.numQualitySeeds < m_cfg.maxQualitySeedsPerSpMConf) {
205  // fill high quality seed
206  seedFilterState.numQualitySeeds++;
207  }
208 
209  } else if (weight > weightMax) {
210  // store weight and index of the best "lower quality" seed
211  weightMax = weight;
212  maxWeightSeedIndex = topSPIndex;
213  maxWeightSeed = true;
214  }
215  } else {
216  // keep the normal behavior without seed quality confirmation
217  // if we have not yet reached our max number of seeds we add the new seed
218  // to outCont
219 
220  candidates_collector.push(bottomSP, middleSP, *topSpVec[topSPIndex],
221  weight, zOrigin, false);
222  if (seedFilterState.numSeeds < m_cfg.maxSeedsPerSpMConf) {
223  // fill seed
224  seedFilterState.numSeeds++;
225  }
226  }
227  } // loop on tops
228  // if no high quality seed was found for a certain middle+bottom SP pair,
229  // lower quality seeds can be accepted
230  if (m_cfg.seedConfirmation and maxWeightSeed and
231  seedFilterState.numQualitySeeds == 0) {
232  // if we have not yet reached our max number of seeds we add the new seed to
233  // outCont
234 
235  candidates_collector.push(bottomSP, middleSP, *topSpVec[maxWeightSeedIndex],
236  weightMax, zOrigin, false);
237  if (seedFilterState.numSeeds < m_cfg.maxSeedsPerSpMConf) {
238  // fill seed
239  seedFilterState.numSeeds++;
240  }
241  }
242 }
243 
244 // after creating all seeds with a common middle space point, filter again
245 
246 template <typename external_spacepoint_t>
248  Acts::SpacePointData& spacePointData,
250  candidates_collector,
251  const std::size_t numQualitySeeds,
252  std::back_insert_iterator<std::vector<Seed<external_spacepoint_t>>> outIt)
253  const {
254  // retrieve all candidates
255  // this collection is already sorted
256  // higher weights first
257  auto extended_collection = candidates_collector.storage();
258  filterSeeds_1SpFixed(spacePointData, extended_collection, numQualitySeeds,
259  outIt);
260 }
261 
262 template <typename external_spacepoint_t>
264  Acts::SpacePointData& spacePointData,
265  std::vector<typename CandidatesForMiddleSp<
267  candidates,
268  const std::size_t numQualitySeeds,
269  std::back_insert_iterator<std::vector<Seed<external_spacepoint_t>>> outIt)
270  const {
271  if (m_experimentCuts != nullptr) {
272  candidates = m_experimentCuts->cutPerMiddleSP(std::move(candidates));
273  }
274 
275  unsigned int maxSeeds = candidates.size();
276 
277  if (maxSeeds > m_cfg.maxSeedsPerSpM) {
278  maxSeeds = m_cfg.maxSeedsPerSpM + 1;
279  }
280 
281  // default filter removes the last seeds if maximum amount exceeded
282  // ordering by weight by filterSeeds_2SpFixed means these are the lowest
283  // weight seeds
284  unsigned int numTotalSeeds = 0;
285  for (const auto& [bottom, medium, top, bestSeedQuality, zOrigin,
286  qualitySeed] : candidates) {
287  // stop if we reach the maximum number of seeds
288  if (numTotalSeeds >= maxSeeds) {
289  break;
290  }
291 
292  if (m_cfg.seedConfirmation) {
293  // continue if higher-quality seeds were found
294  if (numQualitySeeds > 0 and not qualitySeed) {
295  continue;
296  }
297  if (bestSeedQuality < spacePointData.quality(bottom->index()) and
298  bestSeedQuality < spacePointData.quality(medium->index()) and
299  bestSeedQuality < spacePointData.quality(top->index())) {
300  continue;
301  }
302  }
303 
304  // set quality of seed components
305  spacePointData.setQuality(bottom->index(), bestSeedQuality);
306  spacePointData.setQuality(medium->index(), bestSeedQuality);
307  spacePointData.setQuality(top->index(), bestSeedQuality);
308 
309  outIt = Seed<external_spacepoint_t>{bottom->sp(), medium->sp(), top->sp(),
310  zOrigin, bestSeedQuality};
311  ++numTotalSeeds;
312  }
313 }
314 
315 } // namespace Acts