Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
reconstruction.py
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file reconstruction.py
1 from pathlib import Path
2 from typing import Optional, Union, List
3 from enum import Enum
4 from collections import namedtuple
5 import warnings
6 
7 import acts
8 import acts.examples
9 
10 u = acts.UnitConstants
11 
12 SeedingAlgorithm = Enum(
13  "SeedingAlgorithm",
14  "Default TruthSmeared TruthEstimated Orthogonal HoughTransform FTF",
15 )
16 
17 TruthSeedRanges = namedtuple(
18  "TruthSeedRanges",
19  ["rho", "z", "phi", "eta", "absEta", "pt", "nHits"],
20  defaults=[(None, None)] * 7,
21 )
22 
23 ParticleSmearingSigmas = namedtuple(
24  "ParticleSmearingSigmas",
25  ["d0", "d0PtA", "d0PtB", "z0", "z0PtA", "z0PtB", "t0", "phi", "theta", "pRel"],
26  defaults=[None] * 10,
27 )
28 
29 SeedFinderConfigArg = namedtuple(
30  "SeedFinderConfig",
31  [
32  "maxSeedsPerSpM",
33  "cotThetaMax",
34  "sigmaScattering",
35  "radLengthPerSeed",
36  "minPt",
37  "impactMax",
38  "deltaPhiMax",
39  "interactionPointCut",
40  "deltaZMax",
41  "maxPtScattering",
42  "zBinEdges",
43  "zBinsCustomLooping",
44  "skipZMiddleBinSearch",
45  "rRangeMiddleSP",
46  "useVariableMiddleSPRange",
47  "binSizeR",
48  "seedConfirmation",
49  "centralSeedConfirmationRange",
50  "forwardSeedConfirmationRange",
51  "deltaR", # (min,max)
52  "deltaRBottomSP", # (min,max)
53  "deltaRTopSP", # (min,max)
54  "deltaRMiddleSPRange", # (min,max)
55  "collisionRegion", # (min,max)
56  "r", # (min,max)
57  "z", # (min,max)
58  "zOutermostLayers", # (min,max)
59  ],
60  defaults=[None] * 19 + [(None, None)] * 8,
61 )
62 SeedFinderOptionsArg = namedtuple(
63  "SeedFinderOptions", ["beamPos", "bFieldInZ"], defaults=[(None, None), None]
64 )
65 
66 SeedFilterConfigArg = namedtuple(
67  "SeedFilterConfig",
68  [
69  "impactWeightFactor",
70  "zOriginWeightFactor",
71  "compatSeedWeight",
72  "compatSeedLimit",
73  "numSeedIncrement",
74  "seedWeightIncrement",
75  "seedConfirmation",
76  "maxSeedsPerSpMConf",
77  "maxQualitySeedsPerSpMConf",
78  "useDeltaRorTopRadius",
79  "deltaRMin",
80  ],
81  defaults=[None] * 11,
82 )
83 
84 SpacePointGridConfigArg = namedtuple(
85  "SeedGridConfig",
86  [
87  "rMax",
88  "zBinEdges",
89  "phiBinDeflectionCoverage",
90  "impactMax",
91  "deltaRMax",
92  "maxPhiBins",
93  "phi", # (min,max)
94  ],
95  defaults=[None] * 6 + [(None, None)] * 1,
96 )
97 
98 SeedingAlgorithmConfigArg = namedtuple(
99  "SeedingAlgorithmConfig",
100  [
101  "allowSeparateRMax",
102  "zBinNeighborsTop",
103  "zBinNeighborsBottom",
104  "numPhiNeighbors",
105  ],
106  defaults=[None] * 4,
107 )
108 
109 TruthEstimatedSeedingAlgorithmConfigArg = namedtuple(
110  "TruthSeederConfig",
111  [
112  "deltaR", # (min,max)
113  ],
114  defaults=[(None, None)],
115 )
116 
117 TrackSelectorConfig = namedtuple(
118  "TrackSelectorConfig",
119  ["loc0", "loc1", "time", "eta", "absEta", "pt", "phi", "nMeasurementsMin"],
120  defaults=[(None, None)] * 7 + [None],
121 )
122 
123 CkfConfig = namedtuple(
124  "CkfConfig",
125  ["chi2CutOff", "numMeasurementsCutOff", "maxSteps"],
126  defaults=[15.0, 10, None],
127 )
128 
129 AmbiguityResolutionConfig = namedtuple(
130  "AmbiguityResolutionConfig",
131  ["maximumSharedHits", "nMeasurementsMin", "maximumIterations"],
132  defaults=[None] * 3,
133 )
134 
135 AmbiguityResolutionMLConfig = namedtuple(
136  "AmbiguityResolutionMLConfig",
137  ["maximumSharedHits", "nMeasurementsMin", "maximumIterations"],
138  defaults=[None] * 3,
139 )
140 
141 AmbiguityResolutionMLDBScanConfig = namedtuple(
142  "AmbiguityResolutionMLDBScanConfig",
143  ["nMeasurementsMin", "epsilonDBScan", "minPointsDBScan"],
144  defaults=[None] * 3,
145 )
146 
147 
148 class VertexFinder(Enum):
149  Truth = (1,)
150  AMVF = (2,)
151  Iterative = (3,)
152 
153 
155  seedingAlgorithm=SeedingAlgorithm,
156  truthSeedRanges=TruthSeedRanges,
157  particleSmearingSigmas=ParticleSmearingSigmas,
158  seedFinderConfigArg=SeedFinderConfigArg,
159  seedFinderOptionsArg=SeedFinderOptionsArg,
160  seedFilterConfigArg=SeedFilterConfigArg,
161  spacePointGridConfigArg=SpacePointGridConfigArg,
162  seedingAlgorithmConfigArg=SeedingAlgorithmConfigArg,
163  truthEstimatedSeedingAlgorithmConfigArg=TruthEstimatedSeedingAlgorithmConfigArg,
164  logLevel=acts.logging.Level,
165 )
166 def addSeeding(
168  trackingGeometry: acts.TrackingGeometry,
169  field: acts.MagneticFieldProvider,
170  geoSelectionConfigFile: Optional[Union[Path, str]] = None,
171  layerMappingConfigFile: Optional[Union[Path, str]] = None,
172  fastrack_inputConfigFile: Optional[Union[Path, str]] = None,
173  seedingAlgorithm: SeedingAlgorithm = SeedingAlgorithm.Default,
174  truthSeedRanges: Optional[TruthSeedRanges] = TruthSeedRanges(),
175  particleSmearingSigmas: ParticleSmearingSigmas = ParticleSmearingSigmas(),
176  initialSigmas: Optional[list] = None,
177  initialVarInflation: Optional[list] = None,
178  seedFinderConfigArg: SeedFinderConfigArg = SeedFinderConfigArg(),
179  seedFinderOptionsArg: SeedFinderOptionsArg = SeedFinderOptionsArg(),
180  seedFilterConfigArg: SeedFilterConfigArg = SeedFilterConfigArg(),
181  spacePointGridConfigArg: SpacePointGridConfigArg = SpacePointGridConfigArg(),
182  seedingAlgorithmConfigArg: SeedingAlgorithmConfigArg = SeedingAlgorithmConfigArg(),
183  houghTransformConfig: acts.examples.HoughTransformSeeder.Config = acts.examples.HoughTransformSeeder.Config(),
184  truthEstimatedSeedingAlgorithmConfigArg: TruthEstimatedSeedingAlgorithmConfigArg = TruthEstimatedSeedingAlgorithmConfigArg(),
185  particleHypothesis: Optional[
186  acts.ParticleHypothesis
187  ] = acts.ParticleHypothesis.pion,
188  inputParticles: str = "particles",
189  outputDirRoot: Optional[Union[Path, str]] = None,
190  logLevel: Optional[acts.logging.Level] = None,
191  rnd: Optional[acts.examples.RandomNumbers] = None,
192 ) -> None:
193  """This function steers the seeding
194  Parameters
195  ----------
196  s: Sequencer
197  the sequencer module to which we add the Seeding steps (returned from addSeeding)
198  trackingGeometry : tracking geometry
199  field : magnetic field
200  geoSelectionConfigFile : Path|str, path, None
201  Json file for space point geometry selection. Not required for SeedingAlgorithm.TruthSmeared.
202  seedingAlgorithm : SeedingAlgorithm, Default
203  seeding algorithm to use: one of Default (no truth information used), TruthSmeared, TruthEstimated
204  truthSeedRanges : TruthSeedRanges(rho, z, phi, eta, absEta, pt, nHits)
205  TruthSeedSelector configuration. Each range is specified as a tuple of (min,max).
206  Defaults of no cuts specified in Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TruthSeedSelector.hpp
207  If specified as None, don't run ParticleSmearing at all (and use addCKFTracks(selectedParticles="particles"))
208  particleSmearingSigmas : ParticleSmearingSigmas(d0, d0PtA, d0PtB, z0, z0PtA, z0PtB, t0, phi, theta, pRel)
209  ParticleSmearing configuration.
210  Defaults specified in Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.hpp
211  initialSigmas : list
212  Sets the initial covariance matrix diagonal. This is ignored in case of TruthSmearing.
213  Defaults specified in Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/TrackParamsEstimationAlgorithm.hpp
214  initialVarInflation : list
215  List of 6 scale factors to inflate the initial covariance matrix
216  Defaults (all 1) specified in Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.hpp
217  seedFinderConfigArg : SeedFinderConfigArg(maxSeedsPerSpM, cotThetaMax, sigmaScattering, radLengthPerSeed, minPt, impactMax, deltaPhiMax, interactionPointCut, deltaZMax, maxPtScattering, zBinEdges, zBinsCustomLooping, rRangeMiddleSP, useVariableMiddleSPRange, binSizeR, seedConfirmation, centralSeedConfirmationRange, forwardSeedConfirmationRange, deltaR, deltaRBottomSP, deltaRTopSP, deltaRMiddleSPRange, collisionRegion, r, z, zOutermostLayers)
218  Defaults specified in Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/TrackParamsEstimationAlgorithm.hpp
219  seedFinderConfigArg : SeedFinderConfigArg(maxSeedsPerSpM, cotThetaMax, sigmaScattering, radLengthPerSeed, minPt, impactMax, deltaPhiMax, interactionPointCut, deltaZMax, maxPtScattering, zBinEdges, zBinsCustomLooping, skipZMiddleBinSearch, rRangeMiddleSP, useVariableMiddleSPRange, binSizeR, seedConfirmation, centralSeedConfirmationRange, forwardSeedConfirmationRange, deltaR, deltaRBottomSP, deltaRTopSP, deltaRMiddleSPRange, collisionRegion, r, z, zOutermostLayers)
220  SeedFinderConfig settings. deltaR, deltaRBottomSP, deltaRTopSP, deltaRMiddleSPRange, collisionRegion, r, z, zOutermostLayers are ranges specified as a tuple of (min,max). beamPos is specified as (x,y).
221  Defaults specified in Core/include/Acts/Seeding/SeedFinderConfig.hpp
222  seedFinderOptionsArg : SeedFinderOptionsArg(bFieldInZ, beamPos)
223  Defaults specified in Core/include/Acts/Seeding/SeedFinderConfig.hpp
224  seedFilterConfigArg : SeedFilterConfigArg(compatSeedWeight, compatSeedLimit, numSeedIncrement, seedWeightIncrement, seedConfirmation, maxSeedsPerSpMConf, maxQualitySeedsPerSpMConf, useDeltaRorTopRadius)
225  Defaults specified in Core/include/Acts/Seeding/SeedFilterConfig.hpp
226  spacePointGridConfigArg : SpacePointGridConfigArg(rMax, zBinEdges, phiBinDeflectionCoverage, phi, maxPhiBins, impactMax)
227  SpacePointGridConfigArg settings. phi is specified as a tuple of (min,max).
228  Defaults specified in Core/include/Acts/Seeding/SpacePointGrid.hpp
229  seedingAlgorithmConfigArg : SeedingAlgorithmConfigArg(allowSeparateRMax, zBinNeighborsTop, zBinNeighborsBottom, numPhiNeighbors)
230  Defaults specified in Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/SeedingAlgorithm.hpp
231  truthEstimatedSeedingAlgorithmConfigArg : TruthEstimatedSeedingAlgorithmConfigArg(deltaR)
232  Currently only deltaR=(min,max) range specified here.
233  particleHypothesis : Optional[acts.ParticleHypothesis]
234  The hypothesis used for track finding. Defaults to pion.
235  inputParticles : str, "particles"
236  input particles name in the WhiteBoard
237  outputDirRoot : Path|str, path, None
238  the output folder for the Root output, None triggers no output
239  logLevel : acts.logging.Level, None
240  logging level to override setting given in `s`
241  rnd : RandomNumbers, None
242  random number generator. Only used by SeedingAlgorithm.TruthSmeared.
243  """
244 
245  logLevel = acts.examples.defaultLogging(s, logLevel)()
246  logger = acts.logging.getLogger("addSeeding")
247  logger.setLevel(logLevel)
248 
249  if truthSeedRanges is not None:
250  selectedParticles = "truth_seeds_selected"
252  s,
253  inputParticles,
254  selectedParticles,
255  truthSeedRanges,
256  logLevel,
257  )
258  else:
259  selectedParticles = inputParticles
260 
261  # Create starting parameters from either particle smearing or combined seed
262  # finding and track parameters estimation
263  if seedingAlgorithm == SeedingAlgorithm.TruthSmeared:
264  logger.info("Using smeared truth particles for seeding")
266  s,
267  rnd,
268  selectedParticles,
269  particleSmearingSigmas,
270  initialSigmas,
271  initialVarInflation,
272  particleHypothesis,
273  logLevel,
274  )
275  else:
276  spacePoints = addSpacePointsMaking(
277  s, trackingGeometry, geoSelectionConfigFile, logLevel
278  )
279  # Run either: truth track finding or seeding
280  if seedingAlgorithm == SeedingAlgorithm.TruthEstimated:
281  logger.info("Using truth track finding from space points for seeding")
282  seeds = addTruthEstimatedSeeding(
283  s,
284  spacePoints,
285  selectedParticles,
286  truthEstimatedSeedingAlgorithmConfigArg,
287  logLevel,
288  )
289  elif seedingAlgorithm == SeedingAlgorithm.Default:
290  logger.info("Using default seeding")
291  seeds = addStandardSeeding(
292  s,
293  spacePoints,
294  seedingAlgorithmConfigArg,
295  seedFinderConfigArg,
296  seedFinderOptionsArg,
297  seedFilterConfigArg,
298  spacePointGridConfigArg,
299  logLevel,
300  )
301  elif seedingAlgorithm == SeedingAlgorithm.Orthogonal:
302  logger.info("Using orthogonal seeding")
303  seeds = addOrthogonalSeeding(
304  s,
305  spacePoints,
306  seedFinderConfigArg,
307  seedFinderOptionsArg,
308  seedFilterConfigArg,
309  logLevel,
310  )
311  elif seedingAlgorithm == SeedingAlgorithm.HoughTransform:
312  logger.info("Using Hough Transform seeding")
313  houghTransformConfig.inputSpacePoints = [spacePoints]
314  houghTransformConfig.inputMeasurements = "measurements"
315  houghTransformConfig.inputSourceLinks = "sourcelinks"
316  houghTransformConfig.outputProtoTracks = "prototracks"
317  houghTransformConfig.outputSeeds = "seeds"
318  houghTransformConfig.trackingGeometry = trackingGeometry
319  seeds = addHoughTransformSeeding(s, houghTransformConfig, logLevel)
320  elif seedingAlgorithm == SeedingAlgorithm.FTF:
321  logger.info("Using FTF seeding")
322  # output of algs changed, only one output now
323  seeds = addFTFSeeding(
324  s,
325  spacePoints,
326  seedFinderConfigArg,
327  seedFinderOptionsArg,
328  seedFilterConfigArg,
329  trackingGeometry,
330  logLevel,
331  layerMappingConfigFile,
332  geoSelectionConfigFile,
333  fastrack_inputConfigFile,
334  )
335  else:
336  logger.fatal("unknown seedingAlgorithm %s", seedingAlgorithm)
337 
338  parEstimateAlg = acts.examples.TrackParamsEstimationAlgorithm(
339  level=logLevel,
340  inputSeeds=seeds,
341  outputTrackParameters="estimatedparameters",
342  trackingGeometry=trackingGeometry,
343  magneticField=field,
345  initialSigmas=initialSigmas,
346  initialVarInflation=initialVarInflation,
347  particleHypothesis=particleHypothesis,
348  ),
349  )
350  s.addAlgorithm(parEstimateAlg)
351 
352  prototracks = "seed-prototracks"
353  s.addAlgorithm(
354  acts.examples.SeedsToPrototracks(
355  level=logLevel,
356  inputSeeds=seeds,
357  outputProtoTracks=prototracks,
358  )
359  )
360 
361  if outputDirRoot is not None:
363  s,
364  outputDirRoot,
365  seeds,
366  prototracks,
367  selectedParticles,
368  inputParticles,
369  parEstimateAlg.config.outputTrackParameters,
370  logLevel,
371  )
372 
373  return s
374 
375 
378  inputParticles: str,
379  outputParticles: str,
380  truthSeedRanges: TruthSeedRanges,
381  logLevel: acts.logging.Level = None,
382 ):
383  """adds truth particles filtering before filtering
384  For parameters description see addSeeding
385  """
386  selAlg = acts.examples.TruthSeedSelector(
388  ptMin=truthSeedRanges.pt[0],
389  ptMax=truthSeedRanges.pt[1],
390  etaMin=truthSeedRanges.eta[0],
391  etaMax=truthSeedRanges.eta[1],
392  nHitsMin=truthSeedRanges.nHits[0],
393  nHitsMax=truthSeedRanges.nHits[1],
394  rhoMin=truthSeedRanges.rho[0],
395  rhoMax=truthSeedRanges.rho[1],
396  zMin=truthSeedRanges.z[0],
397  zMax=truthSeedRanges.z[1],
398  phiMin=truthSeedRanges.phi[0],
399  phiMax=truthSeedRanges.phi[1],
400  absEtaMin=truthSeedRanges.absEta[0],
401  absEtaMax=truthSeedRanges.absEta[1],
402  ),
403  level=logLevel,
404  inputParticles=inputParticles,
405  inputMeasurementParticlesMap="measurement_particles_map",
406  outputParticles=outputParticles,
407  )
408  s.addAlgorithm(selAlg)
409 
410 
413  rnd: Optional[acts.examples.RandomNumbers],
414  selectedParticles: str,
415  particleSmearingSigmas: ParticleSmearingSigmas,
416  initialSigmas: Optional[List[float]],
417  initialVarInflation: List[float],
418  particleHypothesis: Optional[acts.ParticleHypothesis],
419  logLevel: acts.logging.Level = None,
420 ):
421  """adds algorithm that would mimic detector response uncertainties for truth seeding
422  For parameters description see addSeeding
423  """
424 
425  rnd = rnd or acts.examples.RandomNumbers(seed=42)
426  # Run particle smearing
427  ptclSmear = acts.examples.ParticleSmearing(
428  level=logLevel,
429  inputParticles=selectedParticles,
430  outputTrackParameters="estimatedparameters",
431  randomNumbers=rnd,
432  # gaussian sigmas to smear particle parameters
434  sigmaD0=particleSmearingSigmas.d0,
435  sigmaD0PtA=particleSmearingSigmas.d0PtA,
436  sigmaD0PtB=particleSmearingSigmas.d0PtB,
437  sigmaZ0=particleSmearingSigmas.z0,
438  sigmaZ0PtA=particleSmearingSigmas.z0PtA,
439  sigmaZ0PtB=particleSmearingSigmas.z0PtB,
440  sigmaT0=particleSmearingSigmas.t0,
441  sigmaPhi=particleSmearingSigmas.phi,
442  sigmaTheta=particleSmearingSigmas.theta,
443  sigmaPRel=particleSmearingSigmas.pRel,
444  initialSigmas=initialSigmas,
445  initialVarInflation=initialVarInflation,
446  particleHypothesis=particleHypothesis,
447  ),
448  )
449  sequence.addAlgorithm(ptclSmear)
450 
451  truthTrkFndAlg = acts.examples.TruthTrackFinder(
452  level=logLevel,
453  inputParticles=selectedParticles,
454  inputMeasurementParticlesMap="measurement_particles_map",
455  outputProtoTracks="truth_particle_tracks",
456  )
457  sequence.addAlgorithm(truthTrkFndAlg)
458 
459 
462  spacePoints: str,
463  inputParticles: str,
464  TruthEstimatedSeedingAlgorithmConfigArg: TruthEstimatedSeedingAlgorithmConfigArg,
465  logLevel: acts.logging.Level = None,
466 ):
467  """adds truth seeding
468  For parameters description see addSeeding
469  """
470  logLevel = acts.examples.defaultLogging(sequence, logLevel)()
471 
472  truthSeeding = acts.examples.TruthSeedingAlgorithm(
473  level=logLevel,
474  inputParticles=inputParticles,
475  inputMeasurementParticlesMap="measurement_particles_map",
476  inputSpacePoints=[spacePoints],
477  outputParticles="truth_seeded_particles",
478  outputProtoTracks="truth_particle_tracks",
479  outputSeeds="seeds",
481  deltaRMin=TruthEstimatedSeedingAlgorithmConfigArg.deltaR[0],
482  deltaRMax=TruthEstimatedSeedingAlgorithmConfigArg.deltaR[1],
483  ),
484  )
485  sequence.addAlgorithm(truthSeeding)
486 
487  return truthSeeding.config.outputSeeds
488 
489 
492  trackingGeometry: acts.TrackingGeometry,
493  geoSelectionConfigFile: Union[Path, str],
494  logLevel: acts.logging.Level = None,
495 ):
496  """adds space points making
497  For parameters description see addSeeding
498  """
499  logLevel = acts.examples.defaultLogging(sequence, logLevel)()
500  spAlg = acts.examples.SpacePointMaker(
501  level=logLevel,
502  inputSourceLinks="sourcelinks",
503  inputMeasurements="measurements",
504  outputSpacePoints="spacepoints",
505  trackingGeometry=trackingGeometry,
506  geometrySelection=acts.examples.readJsonGeometryList(
507  str(geoSelectionConfigFile)
508  ),
509  )
510  sequence.addAlgorithm(spAlg)
511  return spAlg.config.outputSpacePoints
512 
513 
516  spacePoints: str,
517  seedingAlgorithmConfigArg: SeedingAlgorithmConfigArg,
518  seedFinderConfigArg: SeedFinderConfigArg,
519  seedFinderOptionsArg: SeedFinderOptionsArg,
520  seedFilterConfigArg: SeedFilterConfigArg,
521  spacePointGridConfigArg: SpacePointGridConfigArg,
522  logLevel: acts.logging.Level = None,
523 ):
524  """adds standard seeding
525  For parameters description see addSeeding
526  """
527  logLevel = acts.examples.defaultLogging(sequence, logLevel)()
528 
529  seedFinderConfig = acts.SeedFinderConfig(
531  rMin=seedFinderConfigArg.r[0],
532  rMax=seedFinderConfigArg.r[1],
533  deltaRMin=seedFinderConfigArg.deltaR[0],
534  deltaRMax=seedFinderConfigArg.deltaR[1],
535  deltaRMinTopSP=(
536  seedFinderConfigArg.deltaR[0]
537  if seedFinderConfigArg.deltaRTopSP[0] is None
538  else seedFinderConfigArg.deltaRTopSP[0]
539  ),
540  deltaRMaxTopSP=(
541  seedFinderConfigArg.deltaR[1]
542  if seedFinderConfigArg.deltaRTopSP[1] is None
543  else seedFinderConfigArg.deltaRTopSP[1]
544  ),
545  deltaRMinBottomSP=(
546  seedFinderConfigArg.deltaR[0]
547  if seedFinderConfigArg.deltaRBottomSP[0] is None
548  else seedFinderConfigArg.deltaRBottomSP[0]
549  ),
550  deltaRMaxBottomSP=(
551  seedFinderConfigArg.deltaR[1]
552  if seedFinderConfigArg.deltaRBottomSP[1] is None
553  else seedFinderConfigArg.deltaRBottomSP[1]
554  ),
555  deltaRMiddleMinSPRange=seedFinderConfigArg.deltaRMiddleSPRange[0],
556  deltaRMiddleMaxSPRange=seedFinderConfigArg.deltaRMiddleSPRange[1],
557  collisionRegionMin=seedFinderConfigArg.collisionRegion[0],
558  collisionRegionMax=seedFinderConfigArg.collisionRegion[1],
559  zMin=seedFinderConfigArg.z[0],
560  zMax=seedFinderConfigArg.z[1],
561  zOutermostLayers=(
562  seedFinderConfigArg.zOutermostLayers[0]
563  if seedFinderConfigArg.zOutermostLayers[0] is not None
564  else seedFinderConfigArg.z[0],
565  seedFinderConfigArg.zOutermostLayers[1]
566  if seedFinderConfigArg.zOutermostLayers[1] is not None
567  else seedFinderConfigArg.z[1],
568  ),
569  maxSeedsPerSpM=seedFinderConfigArg.maxSeedsPerSpM,
570  cotThetaMax=seedFinderConfigArg.cotThetaMax,
571  sigmaScattering=seedFinderConfigArg.sigmaScattering,
572  radLengthPerSeed=seedFinderConfigArg.radLengthPerSeed,
573  minPt=seedFinderConfigArg.minPt,
574  impactMax=seedFinderConfigArg.impactMax,
575  interactionPointCut=seedFinderConfigArg.interactionPointCut,
576  deltaZMax=seedFinderConfigArg.deltaZMax,
577  maxPtScattering=seedFinderConfigArg.maxPtScattering,
578  zBinEdges=seedFinderConfigArg.zBinEdges,
579  zBinsCustomLooping=seedFinderConfigArg.zBinsCustomLooping,
580  skipZMiddleBinSearch=seedFinderConfigArg.skipZMiddleBinSearch,
581  rRangeMiddleSP=seedFinderConfigArg.rRangeMiddleSP,
582  useVariableMiddleSPRange=seedFinderConfigArg.useVariableMiddleSPRange,
583  binSizeR=seedFinderConfigArg.binSizeR,
584  seedConfirmation=seedFinderConfigArg.seedConfirmation,
585  centralSeedConfirmationRange=seedFinderConfigArg.centralSeedConfirmationRange,
586  forwardSeedConfirmationRange=seedFinderConfigArg.forwardSeedConfirmationRange,
587  ),
588  )
589  seedFinderOptions = acts.SeedFinderOptions(
591  beamPos=acts.Vector2(0.0, 0.0)
592  if seedFinderOptionsArg.beamPos == (None, None)
593  else acts.Vector2(
594  seedFinderOptionsArg.beamPos[0], seedFinderOptionsArg.beamPos[1]
595  ),
596  bFieldInZ=seedFinderOptionsArg.bFieldInZ,
597  )
598  )
599  seedFilterConfig = acts.SeedFilterConfig(
601  maxSeedsPerSpM=seedFinderConfig.maxSeedsPerSpM,
602  deltaRMin=(
603  seedFinderConfig.deltaRMin
604  if seedFilterConfigArg.deltaRMin is None
605  else seedFilterConfigArg.deltaRMin
606  ),
607  impactWeightFactor=seedFilterConfigArg.impactWeightFactor,
608  zOriginWeightFactor=seedFilterConfigArg.zOriginWeightFactor,
609  compatSeedWeight=seedFilterConfigArg.compatSeedWeight,
610  compatSeedLimit=seedFilterConfigArg.compatSeedLimit,
611  numSeedIncrement=seedFilterConfigArg.numSeedIncrement,
612  seedWeightIncrement=seedFilterConfigArg.seedWeightIncrement,
613  seedConfirmation=seedFilterConfigArg.seedConfirmation,
614  centralSeedConfirmationRange=seedFinderConfig.centralSeedConfirmationRange,
615  forwardSeedConfirmationRange=seedFinderConfig.forwardSeedConfirmationRange,
616  maxSeedsPerSpMConf=seedFilterConfigArg.maxSeedsPerSpMConf,
617  maxQualitySeedsPerSpMConf=seedFilterConfigArg.maxQualitySeedsPerSpMConf,
618  useDeltaRorTopRadius=seedFilterConfigArg.useDeltaRorTopRadius,
619  )
620  )
621 
622  gridConfig = acts.SpacePointGridConfig(
624  minPt=seedFinderConfig.minPt,
625  rMax=(
626  seedFinderConfig.rMax
627  if spacePointGridConfigArg.rMax is None
628  else spacePointGridConfigArg.rMax
629  ),
630  zMax=seedFinderConfig.zMax,
631  zMin=seedFinderConfig.zMin,
632  deltaRMax=(
633  seedFinderConfig.deltaRMax
634  if spacePointGridConfigArg.deltaRMax is None
635  else spacePointGridConfigArg.deltaRMax
636  ),
637  cotThetaMax=seedFinderConfig.cotThetaMax,
638  phiMin=spacePointGridConfigArg.phi[0],
639  phiMax=spacePointGridConfigArg.phi[1],
640  maxPhiBins=spacePointGridConfigArg.maxPhiBins,
641  impactMax=spacePointGridConfigArg.impactMax,
642  zBinEdges=spacePointGridConfigArg.zBinEdges,
643  phiBinDeflectionCoverage=spacePointGridConfigArg.phiBinDeflectionCoverage,
644  )
645  )
646 
647  gridOptions = acts.SpacePointGridOptions(
649  bFieldInZ=seedFinderOptions.bFieldInZ,
650  )
651  )
652 
653  seedingAlg = acts.examples.SeedingAlgorithm(
654  level=logLevel,
655  inputSpacePoints=[spacePoints],
656  outputSeeds="seeds",
658  allowSeparateRMax=seedingAlgorithmConfigArg.allowSeparateRMax,
659  zBinNeighborsTop=seedingAlgorithmConfigArg.zBinNeighborsTop,
660  zBinNeighborsBottom=seedingAlgorithmConfigArg.zBinNeighborsBottom,
661  numPhiNeighbors=seedingAlgorithmConfigArg.numPhiNeighbors,
662  ),
663  gridConfig=gridConfig,
664  gridOptions=gridOptions,
665  seedFilterConfig=seedFilterConfig,
666  seedFinderConfig=seedFinderConfig,
667  seedFinderOptions=seedFinderOptions,
668  )
669  sequence.addAlgorithm(seedingAlg)
670 
671  return seedingAlg.config.outputSeeds
672 
673 
676  spacePoints: str,
677  seedFinderConfigArg: SeedFinderConfigArg,
678  seedFinderOptionsArg: SeedFinderOptionsArg,
679  seedFilterConfigArg: SeedFilterConfigArg,
680  logLevel: acts.logging.Level = None,
681 ):
682  """adds orthogonal seeding algorithm
683  For parameters description see addSeeding
684  """
685  logLevel = acts.examples.defaultLogging(sequence, logLevel)()
686  seedFinderConfig = acts.SeedFinderOrthogonalConfig(
688  rMin=seedFinderConfigArg.r[0],
689  rMax=seedFinderConfigArg.r[1],
690  deltaRMinTopSP=(
691  seedFinderConfigArg.deltaR[0]
692  if seedFinderConfigArg.deltaRTopSP[0] is None
693  else seedFinderConfigArg.deltaRTopSP[0]
694  ),
695  deltaRMaxTopSP=(
696  seedFinderConfigArg.deltaR[1]
697  if seedFinderConfigArg.deltaRTopSP[1] is None
698  else seedFinderConfigArg.deltaRTopSP[1]
699  ),
700  deltaRMinBottomSP=(
701  seedFinderConfigArg.deltaR[0]
702  if seedFinderConfigArg.deltaRBottomSP[0] is None
703  else seedFinderConfigArg.deltaRBottomSP[0]
704  ),
705  deltaRMaxBottomSP=(
706  seedFinderConfigArg.deltaR[1]
707  if seedFinderConfigArg.deltaRBottomSP[1] is None
708  else seedFinderConfigArg.deltaRBottomSP[1]
709  ),
710  collisionRegionMin=seedFinderConfigArg.collisionRegion[0],
711  collisionRegionMax=seedFinderConfigArg.collisionRegion[1],
712  zMin=seedFinderConfigArg.z[0],
713  zMax=seedFinderConfigArg.z[1],
714  zOutermostLayers=(
715  seedFinderConfigArg.zOutermostLayers[0]
716  if seedFinderConfigArg.zOutermostLayers[0] is not None
717  else seedFinderConfigArg.z[0],
718  seedFinderConfigArg.zOutermostLayers[1]
719  if seedFinderConfigArg.zOutermostLayers[1] is not None
720  else seedFinderConfigArg.z[1],
721  ),
722  maxSeedsPerSpM=seedFinderConfigArg.maxSeedsPerSpM,
723  cotThetaMax=seedFinderConfigArg.cotThetaMax,
724  sigmaScattering=seedFinderConfigArg.sigmaScattering,
725  radLengthPerSeed=seedFinderConfigArg.radLengthPerSeed,
726  minPt=seedFinderConfigArg.minPt,
727  impactMax=seedFinderConfigArg.impactMax,
728  deltaPhiMax=seedFinderConfigArg.deltaPhiMax,
729  interactionPointCut=seedFinderConfigArg.interactionPointCut,
730  deltaZMax=seedFinderConfigArg.deltaZMax,
731  maxPtScattering=seedFinderConfigArg.maxPtScattering,
732  rRangeMiddleSP=seedFinderConfigArg.rRangeMiddleSP,
733  useVariableMiddleSPRange=seedFinderConfigArg.useVariableMiddleSPRange,
734  seedConfirmation=seedFinderConfigArg.seedConfirmation,
735  centralSeedConfirmationRange=seedFinderConfigArg.centralSeedConfirmationRange,
736  forwardSeedConfirmationRange=seedFinderConfigArg.forwardSeedConfirmationRange,
737  ),
738  )
739  seedFinderOptions = acts.SeedFinderOptions(
741  beamPos=acts.Vector2(0.0, 0.0)
742  if seedFinderOptionsArg.beamPos == (None, None)
743  else acts.Vector2(
744  seedFinderOptionsArg.beamPos[0], seedFinderOptionsArg.beamPos[1]
745  ),
746  bFieldInZ=seedFinderOptionsArg.bFieldInZ,
747  )
748  )
749  seedFilterConfig = acts.SeedFilterConfig(
751  maxSeedsPerSpM=seedFinderConfig.maxSeedsPerSpM,
752  deltaRMin=(
753  seedFinderConfigArg.deltaR[0]
754  if seedFilterConfigArg.deltaRMin is None
755  else seedFilterConfigArg.deltaRMin
756  ),
757  impactWeightFactor=seedFilterConfigArg.impactWeightFactor,
758  zOriginWeightFactor=seedFilterConfigArg.zOriginWeightFactor,
759  compatSeedWeight=seedFilterConfigArg.compatSeedWeight,
760  compatSeedLimit=seedFilterConfigArg.compatSeedLimit,
761  numSeedIncrement=seedFilterConfigArg.numSeedIncrement,
762  seedWeightIncrement=seedFilterConfigArg.seedWeightIncrement,
763  seedConfirmation=seedFilterConfigArg.seedConfirmation,
764  maxSeedsPerSpMConf=seedFilterConfigArg.maxSeedsPerSpMConf,
765  maxQualitySeedsPerSpMConf=seedFilterConfigArg.maxQualitySeedsPerSpMConf,
766  useDeltaRorTopRadius=seedFilterConfigArg.useDeltaRorTopRadius,
767  )
768  )
769  seedingAlg = acts.examples.SeedingOrthogonalAlgorithm(
770  level=logLevel,
771  inputSpacePoints=[spacePoints],
772  outputSeeds="seeds",
773  seedFilterConfig=seedFilterConfig,
774  seedFinderConfig=seedFinderConfig,
775  seedFinderOptions=seedFinderOptions,
776  )
777  sequence.addAlgorithm(seedingAlg)
778 
779  return seedingAlg.config.outputSeeds
780 
781 
784  config: acts.examples.HoughTransformSeeder.Config,
785  logLevel: acts.logging.Level = None,
786 ):
787  """
788  Configures HoughTransform (HT) for seeding, instead of extra proxy config objects it takes
789  directly the HT example algorithm config.
790  """
791  logLevel = acts.examples.defaultLogging(sequence, logLevel)()
792  ht = acts.examples.HoughTransformSeeder(config=config, level=logLevel)
793  sequence.addAlgorithm(ht)
794  # potentially HT can be extended to also produce seeds, but it is not implemented yet
795  # configuration option (outputSeeds) exists
796  return ht.config.outputSeeds
797 
798 
799 def addFTFSeeding(
801  spacePoints: str,
802  seedFinderConfigArg: SeedFinderConfigArg,
803  seedFinderOptionsArg: SeedFinderOptionsArg,
804  seedFilterConfigArg: SeedFilterConfigArg,
805  trackingGeometry: acts.TrackingGeometry,
806  logLevel: acts.logging.Level = None,
807  layerMappingConfigFile: Union[Path, str] = None,
808  geoSelectionConfigFile: Union[Path, str] = None,
809  fastrack_inputConfigFile: Union[Path, str] = None,
810 ):
811  """FTF seeding"""
812 
813  logLevel = acts.examples.defaultLogging(sequence, logLevel)()
814  layerMappingFile = str(layerMappingConfigFile) # turn path into string
815  fastrack_inputFile = str(fastrack_inputConfigFile)
816  seedFinderConfig = acts.SeedFinderFTFConfig(
818  sigmaScattering=seedFinderConfigArg.sigmaScattering,
819  maxSeedsPerSpM=seedFinderConfigArg.maxSeedsPerSpM,
820  minPt=seedFinderConfigArg.minPt,
821  fastrack_input_file=fastrack_inputFile,
822  m_useClusterWidth=False,
823  ),
824  )
825  seedFinderOptions = acts.SeedFinderOptions(
827  beamPos=acts.Vector2(0.0, 0.0)
828  if seedFinderOptionsArg.beamPos == (None, None)
829  else acts.Vector2(
830  seedFinderOptionsArg.beamPos[0], seedFinderOptionsArg.beamPos[1]
831  ),
832  bFieldInZ=seedFinderOptionsArg.bFieldInZ,
833  )
834  )
835  seedFilterConfig = acts.SeedFilterConfig(
837  maxSeedsPerSpM=seedFinderConfig.maxSeedsPerSpM,
838  deltaRMin=(
839  seedFinderConfigArg.deltaR[0]
840  if seedFilterConfigArg.deltaRMin is None
841  else seedFilterConfigArg.deltaRMin
842  ),
843  impactWeightFactor=seedFilterConfigArg.impactWeightFactor,
844  zOriginWeightFactor=seedFilterConfigArg.zOriginWeightFactor,
845  compatSeedWeight=seedFilterConfigArg.compatSeedWeight,
846  compatSeedLimit=seedFilterConfigArg.compatSeedLimit,
847  numSeedIncrement=seedFilterConfigArg.numSeedIncrement,
848  seedWeightIncrement=seedFilterConfigArg.seedWeightIncrement,
849  seedConfirmation=seedFilterConfigArg.seedConfirmation,
850  # curvatureSortingInFilter=seedFilterConfigArg.curvatureSortingInFilter,
851  maxSeedsPerSpMConf=seedFilterConfigArg.maxSeedsPerSpMConf,
852  maxQualitySeedsPerSpMConf=seedFilterConfigArg.maxQualitySeedsPerSpMConf,
853  useDeltaRorTopRadius=seedFilterConfigArg.useDeltaRorTopRadius,
854  )
855  )
856 
857  seedingAlg = acts.examples.SeedingFTFAlgorithm(
858  level=logLevel,
859  inputSpacePoints=[spacePoints],
860  outputSeeds="seeds",
861  seedFilterConfig=seedFilterConfig,
862  seedFinderConfig=seedFinderConfig,
863  seedFinderOptions=seedFinderOptions,
864  layerMappingFile=layerMappingFile,
865  geometrySelection=acts.examples.readJsonGeometryList(
866  str(geoSelectionConfigFile)
867  ),
868  inputSourceLinks="sourcelinks",
869  trackingGeometry=trackingGeometry,
870  fill_module_csv=False,
871  )
872 
873  sequence.addAlgorithm(seedingAlg)
874  return seedingAlg.config.outputSeeds
875 
876 
879  outputDirRoot: Union[Path, str],
880  seeds: str,
881  prototracks: str,
882  selectedParticles: str,
883  inputParticles: str,
884  outputTrackParameters: str,
885  logLevel: acts.logging.Level = None,
886 ):
887  """Writes seeding related performance output"""
888  customLogLevel = acts.examples.defaultLogging(sequence, logLevel)
889  outputDirRoot = Path(outputDirRoot)
890  if not outputDirRoot.exists():
891  outputDirRoot.mkdir()
892 
893  sequence.addWriter(
894  acts.examples.SeedingPerformanceWriter(
895  level=customLogLevel(minLevel=acts.logging.DEBUG),
896  inputSeeds=seeds,
897  inputParticles=selectedParticles,
898  inputMeasurementParticlesMap="measurement_particles_map",
899  filePath=str(outputDirRoot / "performance_seeding.root"),
900  )
901  )
902 
903  sequence.addWriter(
904  acts.examples.RootTrackParameterWriter(
905  level=customLogLevel(),
906  inputTrackParameters=outputTrackParameters,
907  inputProtoTracks=prototracks,
908  inputParticles=inputParticles,
909  inputSimHits="simhits",
910  inputMeasurementParticlesMap="measurement_particles_map",
911  inputMeasurementSimHitsMap="measurement_simhits_map",
912  filePath=str(outputDirRoot / "estimatedparams.root"),
913  treeName="estimatedparams",
914  )
915  )
916 
917 
918 def addKalmanTracks(
920  trackingGeometry: acts.TrackingGeometry,
921  field: acts.MagneticFieldProvider,
922  directNavigation: bool = False,
923  reverseFilteringMomThreshold: float = 0 * u.GeV,
924  inputProtoTracks: str = "truth_particle_tracks",
925  multipleScattering: bool = True,
926  energyLoss: bool = True,
927  clusters: str = None,
928  calibrator: acts.examples.MeasurementCalibrator = acts.examples.makePassThroughCalibrator(),
929  logLevel: Optional[acts.logging.Level] = None,
930 ) -> None:
931  customLogLevel = acts.examples.defaultLogging(s, logLevel)
932 
933  if directNavigation:
934  srfSortAlg = acts.examples.SurfaceSortingAlgorithm(
935  level=customLogLevel(),
936  inputProtoTracks=inputProtoTracks,
937  inputSimHits="simhits",
938  inputMeasurementSimHitsMap="measurement_simhits_map",
939  outputProtoTracks="sorted_truth_particle_tracks",
940  )
941  s.addAlgorithm(srfSortAlg)
942  inputProtoTracks = srfSortAlg.config.outputProtoTracks
943 
944  kalmanOptions = {
945  "multipleScattering": multipleScattering,
946  "energyLoss": energyLoss,
947  "reverseFilteringMomThreshold": reverseFilteringMomThreshold,
948  "freeToBoundCorrection": acts.examples.FreeToBoundCorrection(False),
949  "level": customLogLevel(),
950  }
951 
952  fitAlg = acts.examples.TrackFittingAlgorithm(
953  level=customLogLevel(),
954  inputMeasurements="measurements",
955  inputSourceLinks="sourcelinks",
956  inputProtoTracks=inputProtoTracks,
957  inputInitialTrackParameters="estimatedparameters",
958  inputClusters=clusters if clusters is not None else "",
959  outputTracks="kfTracks",
960  pickTrack=-1,
961  fit=acts.examples.makeKalmanFitterFunction(
962  trackingGeometry, field, **kalmanOptions
963  ),
964  calibrator=calibrator,
965  )
966  s.addAlgorithm(fitAlg)
967  s.addWhiteboardAlias("tracks", fitAlg.config.outputTracks)
968 
969  trackConverter = acts.examples.TracksToTrajectories(
970  level=customLogLevel(),
971  inputTracks=fitAlg.config.outputTracks,
972  outputTrajectories="kfTrajectories",
973  )
974  s.addAlgorithm(trackConverter)
975  s.addWhiteboardAlias("trajectories", trackConverter.config.outputTrajectories)
976 
977  return s
978 
979 
982  trackingGeometry: acts.TrackingGeometry,
983  field: acts.MagneticFieldProvider,
984  inputProtoTracks: str = "truth_particle_tracks",
985  logLevel: Optional[acts.logging.Level] = None,
986 ) -> None:
987  customLogLevel = acts.examples.defaultLogging(s, logLevel)
988 
989  gsfOptions = {
990  "betheHeitlerApprox": acts.examples.AtlasBetheHeitlerApprox.makeDefault(),
991  "maxComponents": 12,
992  "abortOnError": False,
993  "disableAllMaterialHandling": False,
994  "finalReductionMethod": acts.examples.FinalReductionMethod.maxWeight,
995  "weightCutoff": 1.0e-4,
996  "level": customLogLevel(),
997  }
998 
999  gsfAlg = acts.examples.TrackFittingAlgorithm(
1000  level=customLogLevel(),
1001  inputMeasurements="measurements",
1002  inputSourceLinks="sourcelinks",
1003  inputProtoTracks=inputProtoTracks,
1004  inputInitialTrackParameters="estimatedparameters",
1005  outputTracks="gsf_tracks",
1006  pickTrack=-1,
1007  fit=acts.examples.makeGsfFitterFunction(trackingGeometry, field, **gsfOptions),
1008  calibrator=acts.examples.makePassThroughCalibrator(),
1009  )
1010  s.addAlgorithm(gsfAlg)
1011  s.addWhiteboardAlias("tracks", gsfAlg.config.outputTracks)
1012 
1013  trackConverter = acts.examples.TracksToTrajectories(
1014  level=customLogLevel(),
1015  inputTracks=gsfAlg.config.outputTracks,
1016  outputTrajectories="gsf_trajectories",
1017  )
1018  s.addAlgorithm(trackConverter)
1019 
1020  return s
1021 
1022 
1024  trackSelectorConfig=TrackSelectorConfig,
1025  ckfConfig=CkfConfig,
1026 )
1027 def addCKFTracks(
1029  trackingGeometry: acts.TrackingGeometry,
1030  field: acts.MagneticFieldProvider,
1031  trackSelectorConfig: Optional[TrackSelectorConfig] = None,
1032  ckfConfig: CkfConfig = CkfConfig(),
1033  outputDirCsv: Optional[Union[Path, str]] = None,
1034  outputDirRoot: Optional[Union[Path, str]] = None,
1035  writeTrajectories: bool = True,
1036  logLevel: Optional[acts.logging.Level] = None,
1037  writeCovMat=False,
1038 ) -> None:
1039  """This function steers the seeding
1040 
1041  Parameters
1042  ----------
1043  s: Sequencer
1044  the sequencer module to which we add the Seeding steps (returned from addSeeding)
1045  trackingGeometry : tracking geometry
1046  field : magnetic field
1047  outputDirCsv : Path|str, path, None
1048  the output folder for the Csv output, None triggers no output
1049  outputDirRoot : Path|str, path, None
1050  the output folder for the Root output, None triggers no output
1051  trackSelectorConfig : TrackSelectorConfig(loc0, loc1, time, eta, absEta, pt, phi, minMeasurements)
1052  TrackSelector configuration. Each range is specified as a tuple of (min,max).
1053  Defaults of no cuts specified in Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TrackSelector.hpp
1054  writeTrajectories : bool, True
1055  write trackstates_ckf.root and tracksummary_ckf.root ntuples? These can be quite large.
1056  """
1057 
1058  customLogLevel = acts.examples.defaultLogging(s, logLevel)
1059 
1060  # Setup the track finding algorithm with CKF
1061  # It takes all the source links created from truth hit smearing, seeds from
1062  # truth particle smearing and source link selection config
1063  trackFinder = acts.examples.TrackFindingAlgorithm(
1064  level=customLogLevel(),
1065  measurementSelectorCfg=acts.MeasurementSelector.Config(
1066  [
1067  (
1068  acts.GeometryIdentifier(),
1069  (
1070  [],
1071  [ckfConfig.chi2CutOff],
1072  [ckfConfig.numMeasurementsCutOff],
1073  ),
1074  )
1075  ]
1076  ),
1077  trackSelectorCfg=acts.TrackSelector.Config(
1079  loc0Min=trackSelectorConfig.loc0[0],
1080  loc0Max=trackSelectorConfig.loc0[1],
1081  loc1Min=trackSelectorConfig.loc1[0],
1082  loc1Max=trackSelectorConfig.loc1[1],
1083  timeMin=trackSelectorConfig.time[0],
1084  timeMax=trackSelectorConfig.time[1],
1085  phiMin=trackSelectorConfig.phi[0],
1086  phiMax=trackSelectorConfig.phi[1],
1087  etaMin=trackSelectorConfig.eta[0],
1088  etaMax=trackSelectorConfig.eta[1],
1089  absEtaMin=trackSelectorConfig.absEta[0],
1090  absEtaMax=trackSelectorConfig.absEta[1],
1091  ptMin=trackSelectorConfig.pt[0],
1092  ptMax=trackSelectorConfig.pt[1],
1093  minMeasurements=trackSelectorConfig.nMeasurementsMin,
1094  )
1095  )
1096  if trackSelectorConfig is not None
1097  else None,
1098  inputMeasurements="measurements",
1099  inputSourceLinks="sourcelinks",
1100  inputInitialTrackParameters="estimatedparameters",
1101  outputTracks="ckfTracks",
1102  findTracks=acts.examples.TrackFindingAlgorithm.makeTrackFinderFunction(
1103  trackingGeometry, field, customLogLevel()
1104  ),
1106  maxSteps=ckfConfig.maxSteps,
1107  ),
1108  )
1109  s.addAlgorithm(trackFinder)
1110  s.addWhiteboardAlias("tracks", trackFinder.config.outputTracks)
1111 
1112  trackConverter = acts.examples.TracksToTrajectories(
1113  level=customLogLevel(),
1114  inputTracks=trackFinder.config.outputTracks,
1115  outputTrajectories="trajectories-from-tracks",
1116  )
1117  s.addAlgorithm(trackConverter)
1118  s.addWhiteboardAlias("trajectories", trackConverter.config.outputTrajectories)
1119 
1121  s,
1122  name="ckf",
1123  trajectories="trajectories",
1124  outputDirCsv=outputDirCsv,
1125  outputDirRoot=outputDirRoot,
1126  writeStates=writeTrajectories,
1127  writeSummary=writeTrajectories,
1128  writeCKFperformance=True,
1129  writeFinderPerformance=False,
1130  writeFitterPerformance=False,
1131  logLevel=logLevel,
1132  writeCovMat=writeCovMat,
1133  )
1134 
1135  return s
1136 
1137 
1138 def addGx2fTracks(
1140  trackingGeometry: acts.TrackingGeometry,
1141  field: acts.MagneticFieldProvider,
1142  # directNavigation: bool = False,
1143  inputProtoTracks: str = "truth_particle_tracks",
1144  multipleScattering: bool = False,
1145  energyLoss: bool = False,
1146  clusters: str = None,
1147  calibrator: acts.examples.MeasurementCalibrator = acts.examples.makePassThroughCalibrator(),
1148  logLevel: Optional[acts.logging.Level] = None,
1149 ) -> None:
1150  customLogLevel = acts.examples.defaultLogging(s, logLevel)
1151 
1152  gx2fOptions = {
1153  "multipleScattering": multipleScattering,
1154  "energyLoss": energyLoss,
1155  "freeToBoundCorrection": acts.examples.FreeToBoundCorrection(False),
1156  "level": customLogLevel(),
1157  }
1158 
1159  fitAlg = acts.examples.TrackFittingAlgorithm(
1160  level=customLogLevel(),
1161  inputMeasurements="measurements",
1162  inputSourceLinks="sourcelinks",
1163  inputProtoTracks=inputProtoTracks,
1164  inputInitialTrackParameters="estimatedparameters",
1165  inputClusters=clusters if clusters is not None else "",
1166  outputTracks="gx2fTracks",
1167  pickTrack=-1,
1168  fit=acts.examples.makeGlobalChiSquareFitterFunction(
1169  trackingGeometry, field, **gx2fOptions
1170  ),
1171  calibrator=calibrator,
1172  )
1173  s.addAlgorithm(fitAlg)
1174  s.addWhiteboardAlias("tracks", fitAlg.config.outputTracks)
1175 
1176  trackConverter = acts.examples.TracksToTrajectories(
1177  level=customLogLevel(),
1178  inputTracks=fitAlg.config.outputTracks,
1179  outputTrajectories="gx2fTrajectories",
1180  )
1181  s.addAlgorithm(trackConverter)
1182  s.addWhiteboardAlias("trajectories", trackConverter.config.outputTrajectories)
1183 
1184  return s
1185 
1186 
1189  name: str,
1190  trajectories: str = "trajectories",
1191  outputDirCsv: Optional[Union[Path, str]] = None,
1192  outputDirRoot: Optional[Union[Path, str]] = None,
1193  writeStates: bool = True,
1194  writeSummary: bool = True,
1195  writeCKFperformance: bool = True,
1196  writeFinderPerformance: bool = True,
1197  writeFitterPerformance: bool = True,
1198  logLevel: Optional[acts.logging.Level] = None,
1199  writeCovMat=False,
1200 ):
1201  customLogLevel = acts.examples.defaultLogging(s, logLevel)
1202 
1203  if outputDirRoot is not None:
1204  outputDirRoot = Path(outputDirRoot)
1205  if not outputDirRoot.exists():
1206  outputDirRoot.mkdir()
1207 
1208  if writeStates:
1209  # write track states from CKF
1210  trackStatesWriter = acts.examples.RootTrajectoryStatesWriter(
1211  level=customLogLevel(),
1212  inputTrajectories=trajectories,
1213  # @note The full particles collection is used here to avoid lots of warnings
1214  # since the unselected CKF track might have a majority particle not in the
1215  # filtered particle collection. This could be avoided when a separate track
1216  # selection algorithm is used.
1217  inputParticles="particles_selected",
1218  inputSimHits="simhits",
1219  inputMeasurementParticlesMap="measurement_particles_map",
1220  inputMeasurementSimHitsMap="measurement_simhits_map",
1221  filePath=str(outputDirRoot / f"trackstates_{name}.root"),
1222  treeName="trackstates",
1223  )
1224  s.addWriter(trackStatesWriter)
1225 
1226  if writeSummary:
1227  # write track summary from CKF
1228  trackSummaryWriter = acts.examples.RootTrajectorySummaryWriter(
1229  level=customLogLevel(),
1230  inputTrajectories=trajectories,
1231  # @note The full particles collection is used here to avoid lots of warnings
1232  # since the unselected CKF track might have a majority particle not in the
1233  # filtered particle collection. This could be avoided when a separate track
1234  # selection algorithm is used.
1235  inputParticles="particles_selected",
1236  inputMeasurementParticlesMap="measurement_particles_map",
1237  filePath=str(outputDirRoot / f"tracksummary_{name}.root"),
1238  treeName="tracksummary",
1239  writeCovMat=writeCovMat,
1240  )
1241  s.addWriter(trackSummaryWriter)
1242 
1243  if writeCKFperformance:
1244  # Write CKF performance data
1245  ckfPerfWriter = acts.examples.CKFPerformanceWriter(
1246  level=customLogLevel(),
1247  inputParticles="truth_seeds_selected",
1248  inputTrajectories=trajectories,
1249  inputMeasurementParticlesMap="measurement_particles_map",
1250  filePath=str(outputDirRoot / f"performance_{name}.root"),
1251  )
1252  s.addWriter(ckfPerfWriter)
1253 
1254  if writeFinderPerformance:
1255  s.addWriter(
1256  acts.examples.TrackFinderPerformanceWriter(
1257  level=acts.logging.INFO,
1258  inputProtoTracks="prototracks",
1259  inputParticles="truth_seeds_selected",
1260  inputMeasurementParticlesMap="measurement_particles_map",
1261  filePath=str(
1262  outputDirRoot / f"performance_track_finder_{name}.root"
1263  ),
1264  )
1265  )
1266 
1267  if writeFitterPerformance:
1268  s.addWriter(
1269  acts.examples.TrackFitterPerformanceWriter(
1270  level=acts.logging.INFO,
1271  inputParticles="truth_seeds_selected",
1272  inputTrajectories="trajectories",
1273  inputMeasurementParticlesMap="measurement_particles_map",
1274  filePath=str(
1275  outputDirRoot / f"performance_track_fitter_{name}.root"
1276  ),
1277  )
1278  )
1279 
1280  if outputDirCsv is not None:
1281  outputDirCsv = Path(outputDirCsv)
1282  if not outputDirCsv.exists():
1283  outputDirCsv.mkdir()
1284 
1285  if writeSummary:
1286  csvMTJWriter = acts.examples.CsvMultiTrajectoryWriter(
1287  level=customLogLevel(),
1288  inputTrajectories=trajectories,
1289  inputMeasurementParticlesMap="measurement_particles_map",
1290  outputDir=str(outputDirCsv),
1291  fileName=str(f"tracks_{name}.csv"),
1292  )
1293  s.addWriter(csvMTJWriter)
1294 
1295 
1297  trackSelectorConfig=TrackSelectorConfig,
1298 )
1299 def addTrackSelection(
1301  trackSelectorConfig: TrackSelectorConfig,
1302  inputTracks: str,
1303  outputTracks: str,
1304  logLevel: Optional[acts.logging.Level] = None,
1305 ) -> acts.examples.TrackSelectorAlgorithm:
1306  customLogLevel = acts.examples.defaultLogging(s, logLevel)
1307 
1308  # single cut config for implicit single bin eta configuration
1309  selectorConfig = acts.TrackSelector.Config(
1311  loc0Min=trackSelectorConfig.loc0[0],
1312  loc0Max=trackSelectorConfig.loc0[1],
1313  loc1Min=trackSelectorConfig.loc1[0],
1314  loc1Max=trackSelectorConfig.loc1[1],
1315  timeMin=trackSelectorConfig.time[0],
1316  timeMax=trackSelectorConfig.time[1],
1317  phiMin=trackSelectorConfig.phi[0],
1318  phiMax=trackSelectorConfig.phi[1],
1319  etaMin=trackSelectorConfig.eta[0],
1320  etaMax=trackSelectorConfig.eta[1],
1321  absEtaMin=trackSelectorConfig.absEta[0],
1322  absEtaMax=trackSelectorConfig.absEta[1],
1323  ptMin=trackSelectorConfig.pt[0],
1324  ptMax=trackSelectorConfig.pt[1],
1325  minMeasurements=trackSelectorConfig.nMeasurementsMin,
1326  )
1327  )
1328 
1329  trackSelector = acts.examples.TrackSelectorAlgorithm(
1330  level=customLogLevel(),
1331  inputTracks=inputTracks,
1332  outputTracks=outputTracks,
1333  selectorConfig=selectorConfig,
1334  )
1335 
1336  s.addAlgorithm(trackSelector)
1337 
1338  return trackSelector
1339 
1340 
1341 ExaTrkXBackend = Enum("ExaTrkXBackend", "Torch Onnx")
1342 
1343 
1344 def addExaTrkX(
1346  trackingGeometry: acts.TrackingGeometry,
1347  geometrySelection: Union[Path, str],
1348  modelDir: Union[Path, str],
1349  outputDirRoot: Optional[Union[Path, str]] = None,
1350  backend: Optional[ExaTrkXBackend] = ExaTrkXBackend.Torch,
1351  logLevel: Optional[acts.logging.Level] = None,
1352 ) -> None:
1353  customLogLevel = acts.examples.defaultLogging(s, logLevel)
1354 
1355  # Run the particle selection
1356  # The pre-selection will select truth particles satisfying provided criteria
1357  # from all particles read in by particle reader for further processing. It
1358  # has no impact on the truth hits themselves
1359  s.addAlgorithm(
1360  acts.examples.TruthSeedSelector(
1361  level=customLogLevel(),
1362  ptMin=500 * u.MeV,
1363  nHitsMin=9,
1364  inputParticles="particles_initial",
1365  inputMeasurementParticlesMap="measurement_particles_map",
1366  outputParticles="particles_seed_selected",
1367  )
1368  )
1369 
1370  # Create space points
1371  s.addAlgorithm(
1372  acts.examples.SpacePointMaker(
1373  level=customLogLevel(),
1374  inputSourceLinks="sourcelinks",
1375  inputMeasurements="measurements",
1376  outputSpacePoints="spacepoints",
1377  trackingGeometry=trackingGeometry,
1378  geometrySelection=acts.examples.readJsonGeometryList(
1379  str(geometrySelection)
1380  ),
1381  )
1382  )
1383 
1384  metricLearningConfig = {
1385  "level": customLogLevel(),
1386  "embeddingDim": 8,
1387  "rVal": 1.6,
1388  "knnVal": 100,
1389  }
1390 
1391  filterConfig = {
1392  "level": customLogLevel(),
1393  "cut": 0.01,
1394  }
1395 
1396  gnnConfig = {
1397  "level": customLogLevel(),
1398  "cut": 0.5,
1399  }
1400 
1401  if backend == ExaTrkXBackend.Torch:
1402  metricLearningConfig["modelPath"] = str(modelDir / "embed.pt")
1403  metricLearningConfig["numFeatures"] = 3
1404  filterConfig["modelPath"] = str(modelDir / "filter.pt")
1405  filterConfig["nChunks"] = 10
1406  filterConfig["numFeatures"] = 3
1407  gnnConfig["modelPath"] = str(modelDir / "gnn.pt")
1408  gnnConfig["undirected"] = True
1409  gnnConfig["numFeatures"] = 3
1410 
1411  graphConstructor = acts.examples.TorchMetricLearning(**metricLearningConfig)
1412  edgeClassifiers = [
1413  acts.examples.TorchEdgeClassifier(**filterConfig),
1414  acts.examples.TorchEdgeClassifier(**gnnConfig),
1415  ]
1416  trackBuilder = acts.examples.BoostTrackBuilding(customLogLevel())
1417  elif backend == ExaTrkXBackend.Onnx:
1418  metricLearningConfig["modelPath"] = str(modelDir / "embedding.onnx")
1419  metricLearningConfig["spacepointFeatures"] = 3
1420  filterConfig["modelPath"] = str(modelDir / "filtering.onnx")
1421  gnnConfig["modelPath"] = str(modelDir / "gnn.onnx")
1422 
1423  graphConstructor = acts.examples.OnnxMetricLearning(**metricLearningConfig)
1424  edgeClassifiers = [
1425  acts.examples.OnnxEdgeClassifier(**filterConfig),
1426  acts.examples.OnnxEdgeClassifier(**gnnConfig),
1427  ]
1428  trackBuilder = acts.examples.CugraphTrackBuilding(customLogLevel())
1429 
1430  s.addAlgorithm(
1431  acts.examples.TrackFindingAlgorithmExaTrkX(
1432  level=customLogLevel(),
1433  inputSpacePoints="spacepoints",
1434  outputProtoTracks="protoTracks",
1435  graphConstructor=graphConstructor,
1436  edgeClassifiers=edgeClassifiers,
1437  trackBuilder=trackBuilder,
1438  )
1439  )
1440 
1441  # Write truth track finding / seeding performance
1442  if outputDirRoot is not None:
1443  s.addWriter(
1444  acts.examples.TrackFinderPerformanceWriter(
1445  level=customLogLevel(),
1446  inputProtoTracks="protoTracks",
1447  inputParticles="particles_initial", # the original selected particles after digitization
1448  inputMeasurementParticlesMap="measurement_particles_map",
1449  filePath=str(Path(outputDirRoot) / "performance_track_finding.root"),
1450  )
1451  )
1452 
1453  return s
1454 
1455 
1457  config=AmbiguityResolutionConfig,
1458 )
1460  s,
1461  config: AmbiguityResolutionConfig = AmbiguityResolutionConfig(),
1462  outputDirCsv: Optional[Union[Path, str]] = None,
1463  outputDirRoot: Optional[Union[Path, str]] = None,
1464  writeTrajectories: bool = True,
1465  logLevel: Optional[acts.logging.Level] = None,
1466  writeCovMat=False,
1467 ) -> None:
1468  from acts.examples import GreedyAmbiguityResolutionAlgorithm
1469 
1470  customLogLevel = acts.examples.defaultLogging(s, logLevel)
1471 
1472  alg = GreedyAmbiguityResolutionAlgorithm(
1473  level=customLogLevel(),
1474  inputTracks="tracks",
1475  outputTracks="ambiTracks",
1477  maximumSharedHits=config.maximumSharedHits,
1478  nMeasurementsMin=config.nMeasurementsMin,
1479  maximumIterations=config.maximumIterations,
1480  ),
1481  )
1482  s.addAlgorithm(alg)
1483 
1484  trackConverter = acts.examples.TracksToTrajectories(
1485  level=customLogLevel(),
1486  inputTracks=alg.config.outputTracks,
1487  outputTrajectories="ambiTrajectories",
1488  )
1489  s.addAlgorithm(trackConverter)
1490  s.addWhiteboardAlias("trajectories", trackConverter.config.outputTrajectories)
1491 
1493  s,
1494  name="ambi",
1495  trajectories="trajectories",
1496  outputDirCsv=outputDirCsv,
1497  outputDirRoot=outputDirRoot,
1498  writeStates=writeTrajectories,
1499  writeSummary=writeTrajectories,
1500  writeCKFperformance=True,
1501  writeFinderPerformance=False,
1502  writeFitterPerformance=False,
1503  logLevel=logLevel,
1504  writeCovMat=writeCovMat,
1505  )
1506 
1507  return s
1508 
1509 
1511  config=AmbiguityResolutionMLConfig,
1512 )
1514  s,
1515  config: AmbiguityResolutionMLConfig = AmbiguityResolutionMLConfig(),
1516  onnxModelFile: Optional[Union[Path, str]] = None,
1517  outputDirCsv: Optional[Union[Path, str]] = None,
1518  outputDirRoot: Optional[Union[Path, str]] = None,
1519  writeTrajectories: bool = True,
1520  logLevel: Optional[acts.logging.Level] = None,
1521 ) -> None:
1522  from acts.examples.onnx import AmbiguityResolutionMLAlgorithm
1523  from acts.examples import GreedyAmbiguityResolutionAlgorithm
1524 
1525  customLogLevel = acts.examples.defaultLogging(s, logLevel)
1526 
1527  algML = AmbiguityResolutionMLAlgorithm(
1528  level=customLogLevel(),
1529  inputTracks="tracks",
1530  inputDuplicateNN=onnxModelFile,
1531  outputTracks="ambiTracksML",
1533  nMeasurementsMin=config.nMeasurementsMin,
1534  ),
1535  )
1536 
1537  algGreedy = GreedyAmbiguityResolutionAlgorithm(
1538  level=customLogLevel(),
1539  inputTracks=algML.config.outputTracks,
1540  outputTracks="ambiTracksMLGreedy",
1542  maximumSharedHits=config.maximumSharedHits,
1543  nMeasurementsMin=config.nMeasurementsMin,
1544  maximumIterations=config.maximumIterations,
1545  ),
1546  )
1547 
1548  s.addAlgorithm(algML)
1549  s.addAlgorithm(algGreedy)
1550 
1551  trackConverter = acts.examples.TracksToTrajectories(
1552  level=customLogLevel(),
1553  inputTracks=algGreedy.config.outputTracks,
1554  outputTrajectories="ambiTrajectories",
1555  )
1556  s.addAlgorithm(trackConverter)
1557  s.addWhiteboardAlias("trajectories", trackConverter.config.outputTrajectories)
1558 
1560  s,
1561  name="ambiML",
1562  trajectories="trajectories",
1563  outputDirCsv=outputDirCsv,
1564  outputDirRoot=outputDirRoot,
1565  writeStates=writeTrajectories,
1566  writeSummary=writeTrajectories,
1567  writeCKFperformance=True,
1568  writeFinderPerformance=False,
1569  writeFitterPerformance=False,
1570  logLevel=logLevel,
1571  )
1572 
1573  return s
1574 
1575 
1577  config=AmbiguityResolutionMLDBScanConfig,
1578 )
1580  s,
1581  config: AmbiguityResolutionMLDBScanConfig = AmbiguityResolutionMLDBScanConfig(),
1582  onnxModelFile: Optional[Union[Path, str]] = None,
1583  outputDirCsv: Optional[Union[Path, str]] = None,
1584  outputDirRoot: Optional[Union[Path, str]] = None,
1585  writeTrajectories: bool = True,
1586  logLevel: Optional[acts.logging.Level] = None,
1587 ) -> None:
1588  from acts.examples import AmbiguityResolutionMLDBScanAlgorithm
1589 
1590  customLogLevel = acts.examples.defaultLogging(s, logLevel)
1591 
1592  alg = AmbiguityResolutionMLDBScanAlgorithm(
1593  level=customLogLevel(),
1594  inputTracks="tracks",
1595  inputDuplicateNN=onnxModelFile,
1596  outputTracks="ambiTracksMLDBScan",
1598  nMeasurementsMin=config.nMeasurementsMin,
1599  epsilonDBScan=config.epsilonDBScan,
1600  minPointsDBScan=config.minPointsDBScan,
1601  ),
1602  )
1603  s.addAlgorithm(alg)
1604 
1605  trackConverter = acts.examples.TracksToTrajectories(
1606  level=customLogLevel(),
1607  inputTracks=alg.config.outputTracks,
1608  outputTrajectories="ambiTrajectories",
1609  )
1610  s.addAlgorithm(trackConverter)
1611  s.addWhiteboardAlias("trajectories", trackConverter.config.outputTrajectories)
1612 
1614  s,
1615  name="ambiMLDBScan",
1616  trajectories="trajectories",
1617  outputDirCsv=outputDirCsv,
1618  outputDirRoot=outputDirRoot,
1619  writeStates=writeTrajectories,
1620  writeSummary=writeTrajectories,
1621  writeCKFperformance=True,
1622  writeFinderPerformance=False,
1623  writeFitterPerformance=False,
1624  logLevel=logLevel,
1625  )
1626 
1627  return s
1628 
1629 
1631  trackSelectorConfig=TrackSelectorConfig,
1632 )
1633 def addVertexFitting(
1634  s,
1635  field,
1636  seeder: Optional[acts.VertexSeedFinder] = acts.VertexSeedFinder.GaussianSeeder,
1637  trajectories: Optional[str] = "trajectories",
1638  trackParameters: Optional[str] = None,
1639  associatedParticles: Optional[str] = None,
1640  outputProtoVertices: str = "protovertices",
1641  outputVertices: str = "fittedVertices",
1642  vertexFinder: VertexFinder = VertexFinder.Truth,
1643  trackSelectorConfig: Optional[TrackSelectorConfig] = None,
1644  outputDirRoot: Optional[Union[Path, str]] = None,
1645  logLevel: Optional[acts.logging.Level] = None,
1646 ) -> None:
1647  """This function steers the vertex fitting
1648 
1649  Parameters
1650  ----------
1651  s: Sequencer
1652  the sequencer module to which we add the Seeding steps (returned from addVertexFitting)
1653  field : magnetic field
1654  seeder : enum member
1655  determines vertex seeder, can be acts.seeder.GaussianSeeder or acts.seeder.AdaptiveGridSeeder
1656  outputDirRoot : Path|str, path, None
1657  the output folder for the Root output, None triggers no output
1658  associatedParticles : str, "associatedTruthParticles"
1659  VertexPerformanceWriter.inputAssociatedTruthParticles
1660  vertexFinder : VertexFinder, Truth
1661  vertexFinder algorithm: one of Truth, AMVF, Iterative
1662  logLevel : acts.logging.Level, None
1663  logging level to override setting given in `s`
1664  """
1665  from acts.examples import (
1666  TruthVertexFinder,
1667  VertexFitterAlgorithm,
1668  IterativeVertexFinderAlgorithm,
1669  AdaptiveMultiVertexFinderAlgorithm,
1670  VertexPerformanceWriter,
1671  )
1672 
1673  trajectories = trajectories if trajectories is not None else ""
1674  trackParameters = trackParameters if trackParameters is not None else ""
1675  associatedParticles = associatedParticles if associatedParticles is not None else ""
1676 
1677  customLogLevel = acts.examples.defaultLogging(s, logLevel)
1678 
1679  if trackSelectorConfig is not None:
1680  trackSelector = addTrackSelection(
1681  s,
1682  trackSelectorConfig,
1683  inputTrackParameters=trackParameters,
1684  inputTrajectories=trajectories,
1685  outputTrackParameters="selectedTrackParametersVertexing",
1686  outputTrajectories="selectedTrajectoriesVertexing",
1687  logLevel=customLogLevel(),
1688  )
1689 
1690  trajectories = trackSelector.config.outputTrajectories if trajectories else ""
1691  trackParameters = (
1692  trackSelector.config.outputTrackParameters if trackParameters else ""
1693  )
1694 
1695  inputParticles = "particles_input"
1696  selectedParticles = "particles_selected"
1697 
1698  if vertexFinder == VertexFinder.Truth:
1699  findVertices = TruthVertexFinder(
1700  level=customLogLevel(),
1701  inputParticles=selectedParticles,
1702  outputProtoVertices=outputProtoVertices,
1703  excludeSecondaries=True,
1704  )
1705  s.addAlgorithm(findVertices)
1706  fitVertices = VertexFitterAlgorithm(
1707  level=customLogLevel(),
1708  bField=field,
1709  inputTrajectories=trajectories,
1710  inputTrackParameters=trackParameters,
1711  inputProtoVertices=findVertices.config.outputProtoVertices,
1712  outputVertices=outputVertices,
1713  )
1714  s.addAlgorithm(fitVertices)
1715  elif vertexFinder == VertexFinder.Iterative:
1716  findVertices = IterativeVertexFinderAlgorithm(
1717  level=customLogLevel(),
1718  bField=field,
1719  inputTrajectories=trajectories,
1720  inputTrackParameters=trackParameters,
1721  outputProtoVertices=outputProtoVertices,
1722  outputVertices=outputVertices,
1723  )
1724  s.addAlgorithm(findVertices)
1725  elif vertexFinder == VertexFinder.AMVF:
1726  findVertices = AdaptiveMultiVertexFinderAlgorithm(
1727  level=customLogLevel(),
1728  seedFinder=seeder,
1729  bField=field,
1730  inputTrajectories=trajectories,
1731  inputTrackParameters=trackParameters,
1732  outputProtoVertices=outputProtoVertices,
1733  outputVertices=outputVertices,
1734  )
1735  s.addAlgorithm(findVertices)
1736  else:
1737  raise RuntimeError("Invalid finder argument")
1738 
1739  if outputDirRoot is not None:
1740  outputDirRoot = Path(outputDirRoot)
1741  if not outputDirRoot.exists():
1742  outputDirRoot.mkdir()
1743  if associatedParticles == selectedParticles:
1744  warnings.warn(
1745  "Using VertexPerformanceWriter with smeared particles is not necessarily supported. "
1746  "Please get in touch with us"
1747  )
1748  s.addWriter(
1749  VertexPerformanceWriter(
1750  level=customLogLevel(),
1751  inputAllTruthParticles=inputParticles,
1752  inputSelectedTruthParticles=selectedParticles,
1753  inputMeasurementParticlesMap="measurement_particles_map",
1754  inputTrajectories=trajectories,
1755  inputTrackParameters=trackParameters,
1756  inputAssociatedTruthParticles=associatedParticles,
1757  inputVertices=outputVertices,
1758  bField=field,
1759  minTrackVtxMatchFraction=0.5 if associatedParticles else 0.0,
1760  treeName="vertexing",
1761  filePath=str(outputDirRoot / "performance_vertexing.root"),
1762  )
1763  )
1764 
1765  return s
1766 
1767 
1769  s,
1770  outputDirRoot: Optional[Union[Path, str]] = None,
1771  logLevel: Optional[acts.logging.Level] = None,
1772  inputSpacePoints: Optional[str] = "spacepoints",
1773  outputVertices: Optional[str] = "fittedSeedVertices",
1774 ) -> None:
1775  from acts.examples import (
1776  SingleSeedVertexFinderAlgorithm,
1777  VertexPerformanceWriter,
1778  )
1779 
1780  customLogLevel = acts.examples.defaultLogging(s, logLevel)
1781 
1782  findSingleSeedVertex = SingleSeedVertexFinderAlgorithm(
1783  level=customLogLevel(),
1784  inputSpacepoints=inputSpacePoints,
1785  outputVertices=outputVertices,
1786  )
1787  s.addAlgorithm(findSingleSeedVertex)
1788 
1789  inputParticles = "particles_input"
1790  selectedParticles = "particles_selected"
1791 
1792  if outputDirRoot is not None:
1793  outputDirRoot = Path(outputDirRoot)
1794  if not outputDirRoot.exists():
1795  outputDirRoot.mkdir()
1796 
1797  s.addWriter(
1798  VertexPerformanceWriter(
1799  level=customLogLevel(),
1800  inputAllTruthParticles=inputParticles,
1801  inputSelectedTruthParticles=selectedParticles,
1802  useTracks=False,
1803  inputVertices=outputVertices,
1804  treeName="seedvertexing",
1805  filePath=str(outputDirRoot / "performance_seedvertexing.root"),
1806  )
1807  )
1808 
1809  return s