File indexing completed on 2025-01-18 09:12:08
0001
0002
0003 import sys, os, argparse, pathlib
0004
0005
0006 def parse_args():
0007 from acts.examples.reconstruction import SeedingAlgorithm
0008
0009 parser = argparse.ArgumentParser(
0010 description="""
0011 Script to test the full chain ACTS simulation and reconstruction.
0012
0013 This script is provided for interactive developer testing only.
0014 It is not intended (and not supported) for end user use, automated testing,
0015 and certainly should never be called in production. The Python API is the
0016 proper way to access the ActsExamples from scripts. The other Examples/Scripts
0017 are much better examples of how to do that. physmon in the CI is the proper
0018 way to do automated integration tests. This script is only for the case of
0019 interactive testing with one-off configuration specified by command-line options.
0020 """
0021 )
0022 parser.add_argument(
0023 "-G",
0024 "--generic-detector",
0025 action="store_true",
0026 help="Use generic detector geometry and config",
0027 )
0028 parser.add_argument(
0029 "--odd",
0030 default=True,
0031 action=argparse.BooleanOptionalAction,
0032 help="Use Open Data Detector geometry and config (default unless overridden by -G or -A). Requires ACTS_BUILD_ODD.",
0033 )
0034 parser.add_argument(
0035 "-A",
0036 "--itk",
0037 action="store_true",
0038 help="Use ATLAS ITk geometry and config. Requires acts-itk/ in current directory.",
0039 )
0040 parser.add_argument(
0041 "-g",
0042 "--geant4",
0043 action="store_true",
0044 help="Use Geant4 instead of Fatras for detector simulation",
0045 )
0046 parser.add_argument(
0047 "--edm4hep",
0048 type=pathlib.Path,
0049 help="Use edm4hep inputs",
0050 )
0051 parser.add_argument(
0052 "-b",
0053 "--bf-constant",
0054 action="store_true",
0055 help="Use constant 2T B-field also for ITk; and don't include material map",
0056 )
0057 parser.add_argument(
0058 "-j",
0059 "--threads",
0060 type=int,
0061 default=-1,
0062 help="Number of parallel threads, negative for automatic (default).",
0063 )
0064 parser.add_argument(
0065 "-o",
0066 "--output-dir",
0067 "--output",
0068 default=None,
0069 type=pathlib.Path,
0070 help="Directory to write outputs to",
0071 )
0072 parser.add_argument(
0073 "-O",
0074 "--output-detail",
0075 action="count",
0076 default=0,
0077 help="fewer output files. Use -OO for more output files. Use -OOO to disable all output.",
0078 )
0079 parser.add_argument(
0080 "-c",
0081 "--output-csv",
0082 action="count",
0083 default=0,
0084 help="Use CSV output instead of ROOT. Specify -cc to output all formats (ROOT, CSV, and obj).",
0085 )
0086 parser.add_argument(
0087 "--output-obj",
0088 action="store_true",
0089 help="Enable obj output",
0090 )
0091 parser.add_argument(
0092 "-n",
0093 "--events",
0094 type=int,
0095 default=100,
0096 help="The number of events to process (default=%(default)d).",
0097 )
0098 parser.add_argument(
0099 "-s",
0100 "--skip",
0101 type=int,
0102 default=0,
0103 help="Number of events to skip (default=%(default)d)",
0104 )
0105
0106
0107 parser.add_argument(
0108 "-N",
0109 "--gen-nparticles",
0110 "--gun-particles",
0111 type=int,
0112 default=4,
0113 help="Number of generated particles per vertex from the particle gun (default=%(default)d).",
0114 )
0115 parser.add_argument(
0116 "-M",
0117 "--gen-nvertices",
0118 "--gun-multiplicity",
0119 "--ttbar-pu",
0120 type=int,
0121 default=200,
0122 help="Number of vertices per event (multiplicity) from the particle gun; or number of pileup events (default=%(default)d)",
0123 )
0124 parser.add_argument(
0125 "-t",
0126 "--ttbar-pu200",
0127 "--ttbar",
0128 action="store_true",
0129 help="Generate ttbar + mu=200 pile-up using Pythia8",
0130 )
0131 parser.add_argument(
0132 "-p",
0133 "--gen-pt-range",
0134 "--gun-pt-range",
0135 default="1:10",
0136 help="transverse momentum (pT) range (min:max) of the particle gun in GeV (default=%(default)s)",
0137 )
0138 parser.add_argument(
0139 "--gen-eta-range",
0140 "--gun-eta-range",
0141 help="Eta range (min:max) of the particle gun (default -2:2 (Generic), -3:3 (ODD), -4:4 (ITk))",
0142 )
0143 parser.add_argument(
0144 "--gen-cos-theta",
0145 action="store_true",
0146 help="Sample eta as cos(theta) and not uniform",
0147 )
0148 parser.add_argument(
0149 "-r",
0150 "--random-seed",
0151 type=int,
0152 default=42,
0153 help="Random number seed (default=%(default)d)",
0154 )
0155 parser.add_argument(
0156 "-F",
0157 "--disable-fpemon",
0158 action="store_true",
0159 help="sets ACTS_SEQUENCER_DISABLE_FPEMON=1",
0160 )
0161 parser.add_argument(
0162 "-l",
0163 "--loglevel",
0164 type=int,
0165 default=2,
0166 help="The output log level. Please set the wished number (0 = VERBOSE, 1 = DEBUG, 2 = INFO (default), 3 = WARNING, 4 = ERROR, 5 = FATAL).",
0167 )
0168 parser.add_argument(
0169 "-d",
0170 "--dump-args-calls",
0171 action="store_true",
0172 help="Show pybind function call details",
0173 )
0174 parser.add_argument(
0175 "--digi-config",
0176 type=pathlib.Path,
0177 help="Digitization configuration file",
0178 )
0179 parser.add_argument(
0180 "--material-config",
0181 type=pathlib.Path,
0182 help="Material map configuration file",
0183 )
0184 parser.add_argument(
0185 "-S",
0186 "--seeding-algorithm",
0187 action=EnumAction,
0188 enum=SeedingAlgorithm,
0189 default=SeedingAlgorithm.Default,
0190 help="Select the seeding algorithm to use",
0191 )
0192 parser.add_argument(
0193 "--ckf",
0194 default=True,
0195 action=argparse.BooleanOptionalAction,
0196 help="Switch CKF on/off",
0197 )
0198 parser.add_argument(
0199 "--reco",
0200 default=True,
0201 action=argparse.BooleanOptionalAction,
0202 help="Switch reco on/off",
0203 )
0204 parser.add_argument(
0205 "--vertexing",
0206 default=True,
0207 action=argparse.BooleanOptionalAction,
0208 help="Switch vertexing on/off",
0209 )
0210 parser.add_argument(
0211 "--MLSeedFilter",
0212 action="store_true",
0213 help="Use the ML seed filter to select seed after the seeding step",
0214 )
0215 parser.add_argument(
0216 "--ambi-solver",
0217 type=str,
0218 choices=["greedy", "scoring", "ML", "none"],
0219 default="greedy",
0220 help="Set which ambiguity solver to use (default=%(default)s)",
0221 )
0222 parser.add_argument(
0223 "--ambi-config",
0224 type=pathlib.Path,
0225 default=pathlib.Path.cwd() / "ambi_config.json",
0226 help="Set the configuration file for the Score Based ambiguity resolution (default=%(default)s)",
0227 )
0228 return parser.parse_args()
0229
0230
0231 def full_chain(args):
0232 import acts
0233
0234
0235 global detector, trackingGeometry, decorators, field, rnd
0236 global logger
0237
0238 if args.disable_fpemon:
0239 os.environ["ACTS_SEQUENCER_DISABLE_FPEMON"] = "1"
0240
0241 if args.dump_args_calls:
0242 acts.examples.dump_args_calls(locals())
0243
0244 logger = acts.logging.getLogger("full_chain_test")
0245
0246 nDetArgs = [args.generic_detector, args.odd, args.itk].count(True)
0247 if nDetArgs == 0:
0248 args.generic_detector = True
0249 elif nDetArgs == 2:
0250 args.odd = False
0251 nDetArgs = [args.generic_detector, args.odd, args.itk].count(True)
0252 if nDetArgs != 1:
0253 logger.fatal("require exactly one of: --generic-detector --odd --itk")
0254 sys.exit(2)
0255 if args.generic_detector:
0256 detname = "gen"
0257 elif args.itk:
0258 detname = "itk"
0259 elif args.odd:
0260 detname = "odd"
0261
0262 u = acts.UnitConstants
0263
0264 if args.output_detail == 3:
0265 outputDirLess = None
0266 elif args.output_dir is None:
0267 outputDirLess = pathlib.Path.cwd() / f"{detname}_output"
0268 else:
0269 outputDirLess = args.output_dir
0270
0271 outputDir = None if args.output_detail == 1 else outputDirLess
0272 outputDirMore = None if args.output_detail in (0, 1) else outputDirLess
0273
0274 outputDirRoot = outputDir if args.output_csv != 1 else None
0275 outputDirLessRoot = outputDirLess if args.output_csv != 1 else None
0276 outputDirMoreRoot = outputDirMore if args.output_csv != 1 else None
0277 outputDirCsv = outputDir if args.output_csv != 0 else None
0278 outputDirLessCsv = outputDirLess if args.output_csv != 0 else None
0279 outputDirMoreCsv = outputDirMore if args.output_csv != 0 else None
0280 outputDirObj = (
0281 outputDirLess
0282 if args.output_obj
0283 else outputDir if args.output_csv == 2 else None
0284 )
0285
0286
0287 if args.generic_detector:
0288 etaRange = (-2.0, 2.0)
0289 ptMin = 0.5 * u.GeV
0290 rhoMax = 24.0 * u.mm
0291 geo_dir = pathlib.Path(acts.__file__).resolve().parent.parent.parent.parent.parent
0292 if args.loglevel <= 2:
0293 logger.info(f"Load Generic Detector from {geo_dir}")
0294 if args.digi_config is None:
0295 args.digi_config = geo_dir / "Examples/Algorithms/Digitization/share/default-smearing-config-generic.json"
0296 seedingConfigFile = geo_dir / "Examples/Algorithms/TrackFinding/share/geoSelection-genericDetector.json"
0297 args.bf_constant = True
0298 detector = acts.examples.GenericDetector()
0299 trackingGeometry = detector.trackingGeometry()
0300 decorators = detector.contextDecorators()
0301 elif args.odd:
0302 import acts.examples.odd
0303 etaRange = (-3.0, 3.0)
0304 ptMin = 1.0 * u.GeV
0305 rhoMax = 24.0 * u.mm
0306 beamTime = 1.0 * u.ns
0307 geo_dir = acts.examples.odd.getOpenDataDetectorDirectory()
0308 if args.loglevel <= 2:
0309 logger.info(f"Load Open Data Detector from {geo_dir.resolve()}")
0310 if args.digi_config is None:
0311 args.digi_config = geo_dir / "config/odd-digi-smearing-config.json"
0312 seedingConfigFile = geo_dir / "config/odd-seeding-config.json"
0313 if args.material_config is None:
0314 args.material_config = geo_dir / "data/odd-material-maps.root"
0315 args.bf_constant = True
0316 detector = getOpenDataDetector(
0317 odd_dir=geo_dir,
0318 mdecorator=acts.IMaterialDecorator.fromFile(args.material_config),
0319 )
0320 trackingGeometry = detector.trackingGeometry()
0321 decorators = detector.contextDecorators()
0322 elif args.itk:
0323 import acts.examples.itk as itk
0324 etaRange = (-4.0, 4.0)
0325 ptMin = 1.0 * u.GeV
0326 rhoMax = 28.0 * u.mm
0327 beamTime = 5.0 * u.ns
0328 geo_dir = pathlib.Path("acts-itk")
0329 if args.loglevel <= 2:
0330 logger.info(f"Load ATLAS ITk from {geo_dir.resolve()}")
0331 if args.digi_config is None:
0332 args.digi_config = geo_dir / "itk-hgtd/itk-smearing-config.json"
0333 seedingConfigFile = geo_dir / "itk-hgtd/geoSelection-ITk.json"
0334
0335 bFieldFile = geo_dir / "bfield/ATLAS-BField-xyz.root"
0336 detector, trackingGeometry, decorators = itk.buildITkGeometry(
0337 geo_dir,
0338 customMaterialFile=args.material_config,
0339 material=not args.bf_constant,
0340 logLevel=acts.logging.Level(args.loglevel),
0341 )
0342
0343
0344 if args.bf_constant:
0345 field = acts.ConstantBField(acts.Vector3(0.0, 0.0, 2.0 * u.T))
0346 else:
0347 logger.info("Create magnetic field map from %s" % str(bFieldFile))
0348 field = acts.examples.MagneticFieldMapXyz(str(bFieldFile))
0349 rnd = acts.examples.RandomNumbers(seed=42)
0350
0351 from acts.examples.simulation import (
0352 MomentumConfig,
0353 EtaConfig,
0354 PhiConfig,
0355 ParticleConfig,
0356 ParticleSelectorConfig,
0357 addDigitization,
0358 addParticleSelection,
0359 )
0360
0361 s = acts.examples.Sequencer(
0362 events=args.events,
0363 skip=args.skip,
0364 numThreads=args.threads if not (args.geant4 and args.threads == -1) else 1,
0365 logLevel=acts.logging.Level(args.loglevel),
0366 outputDir="" if outputDirLess is None else str(outputDirLess),
0367 )
0368
0369
0370 for d in decorators:
0371 s.addContextDecorator(d)
0372
0373 preSelectParticles = (
0374 ParticleSelectorConfig(
0375 rho=(0.0 * u.mm, rhoMax),
0376 absZ=(0.0 * u.mm, 1.0 * u.m),
0377 eta=etaRange,
0378 pt=(150 * u.MeV, None),
0379 )
0380 if args.edm4hep or args.geant4 or args.ttbar_pu200
0381 else ParticleSelectorConfig()
0382 )
0383
0384 postSelectParticles = ParticleSelectorConfig(
0385 pt=(ptMin, None),
0386 eta=etaRange if not args.generic_detector else (None, None),
0387 hits=(9, None),
0388 removeNeutral=True,
0389 )
0390
0391 if args.edm4hep:
0392 import acts.examples.edm4hep
0393
0394 edm4hepReader = acts.examples.edm4hep.EDM4hepReader(
0395 inputPath=str(args.edm4hep),
0396 inputSimHits=[
0397 "PixelBarrelReadout",
0398 "PixelEndcapReadout",
0399 "ShortStripBarrelReadout",
0400 "ShortStripEndcapReadout",
0401 "LongStripBarrelReadout",
0402 "LongStripEndcapReadout",
0403 ],
0404 outputParticlesGenerator="particles_input",
0405 outputParticlesSimulation="particles_simulated",
0406 outputSimHits="simhits",
0407 graphvizOutput="graphviz",
0408 dd4hepDetector=detector,
0409 trackingGeometry=trackingGeometry,
0410 sortSimHitsInTime=True,
0411 level=acts.logging.INFO,
0412 )
0413 s.addReader(edm4hepReader)
0414 s.addWhiteboardAlias("particles", edm4hepReader.config.outputParticlesGenerator)
0415
0416 addParticleSelection(
0417 s,
0418 config=preSelectParticles,
0419 inputParticles="particles",
0420 outputParticles="particles_selected",
0421 )
0422
0423 else:
0424
0425 if not args.ttbar_pu200:
0426 from acts.examples.simulation import addParticleGun
0427
0428 addParticleGun(
0429 s,
0430 MomentumConfig(
0431 *strToRange(args.gen_pt_range, "--gen-pt-range", u.GeV),
0432 transverse=True,
0433 ),
0434 EtaConfig(
0435 *(
0436 strToRange(args.gen_eta_range, "--gen-eta-range")
0437 if args.gen_eta_range
0438 else etaRange
0439 ),
0440 uniform=(
0441 not args.gen_cos_theta
0442 if args.gen_cos_theta or not args.odd
0443 else None
0444 ),
0445 ),
0446 PhiConfig(0.0, 360.0 * u.degree) if not args.itk else PhiConfig(),
0447 ParticleConfig(
0448 args.gen_nparticles, acts.PdgParticle.eMuon, randomizeCharge=True
0449 ),
0450 vtxGen=(
0451 acts.examples.GaussianVertexGenerator(
0452 mean=acts.Vector4(0, 0, 0, 0),
0453 stddev=acts.Vector4(
0454 0.0125 * u.mm, 0.0125 * u.mm, 55.5 * u.mm, 1.0 * u.ns
0455 ),
0456 )
0457 if args.odd
0458 else None
0459 ),
0460 multiplicity=args.gen_nvertices,
0461 rnd=rnd,
0462 outputDirRoot=outputDirMoreRoot,
0463 outputDirCsv=outputDirMoreCsv,
0464 )
0465 else:
0466 from acts.examples.simulation import addPythia8
0467
0468 addPythia8(
0469 s,
0470 hardProcess=["Top:qqbar2ttbar=on"],
0471 npileup=args.gen_nvertices,
0472 vtxGen=acts.examples.GaussianVertexGenerator(
0473 stddev=acts.Vector4(
0474 0.0125 * u.mm, 0.0125 * u.mm, 55.5 * u.mm, 5.0 * u.ns
0475 ),
0476 mean=acts.Vector4(0, 0, 0, 0),
0477 ),
0478 rnd=rnd,
0479 outputDirRoot=outputDirRoot,
0480 outputDirCsv=outputDirCsv,
0481 )
0482
0483 if not args.geant4:
0484 from acts.examples.simulation import addFatras
0485
0486 addFatras(
0487 s,
0488 trackingGeometry,
0489 field,
0490 rnd=rnd,
0491 preSelectParticles=preSelectParticles,
0492 postSelectParticles=postSelectParticles,
0493 outputDirRoot=outputDirRoot,
0494 outputDirCsv=outputDirCsv,
0495 outputDirObj=outputDirObj,
0496 )
0497 else:
0498 if s.config.numThreads != 1:
0499 logger.fatal(
0500 f"Geant 4 simulation does not support multi-threading (threads={s.config.numThreads})"
0501 )
0502 sys.exit(2)
0503
0504 from acts.examples.simulation import addGeant4
0505
0506
0507
0508
0509 addGeant4(
0510 s,
0511 detector,
0512 trackingGeometry,
0513 field,
0514 rnd=rnd,
0515 preSelectParticles=preSelectParticles,
0516 postSelectParticles=postSelectParticles,
0517 killVolume=trackingGeometry.highestTrackingVolume,
0518 killAfterTime=25 * u.ns,
0519 outputDirRoot=outputDirRoot,
0520 outputDirCsv=outputDirCsv,
0521 outputDirObj=outputDirObj,
0522 )
0523
0524 addDigitization(
0525 s,
0526 trackingGeometry,
0527 field,
0528 digiConfigFile=args.digi_config,
0529 rnd=rnd,
0530 outputDirRoot=outputDirRoot,
0531 outputDirCsv=outputDirCsv,
0532 )
0533
0534 if not args.reco:
0535 return s
0536
0537 from acts.examples.reconstruction import (
0538 addSeeding,
0539 TrackSmearingSigmas,
0540 addCKFTracks,
0541 CkfConfig,
0542 SeedingAlgorithm,
0543 TrackSelectorConfig,
0544 addAmbiguityResolution,
0545 AmbiguityResolutionConfig,
0546 addVertexFitting,
0547 VertexFinder,
0548 )
0549
0550 if args.itk and args.seeding_algorithm == SeedingAlgorithm.Default:
0551 seedingAlgConfig = itk.itkSeedingAlgConfig(
0552 itk.InputSpacePointsType.PixelSpacePoints
0553 )
0554 else:
0555 seedingAlgConfig = []
0556
0557 addSeeding(
0558 s,
0559 trackingGeometry,
0560 field,
0561 *seedingAlgConfig,
0562 seedingAlgorithm=args.seeding_algorithm,
0563 **(
0564 dict(
0565 trackSmearingSigmas=TrackSmearingSigmas(ptRel=0.01),
0566 rnd=rnd,
0567 )
0568 if args.seeding_algorithm == SeedingAlgorithm.TruthSmeared
0569 else {}
0570 ),
0571 initialSigmas=[
0572 1 * u.mm,
0573 1 * u.mm,
0574 1 * u.degree,
0575 1 * u.degree,
0576 0.1 * u.e / u.GeV,
0577 1 * u.ns,
0578 ],
0579 initialSigmaPtRel=0.1,
0580 initialVarInflation=[1.0] * 6,
0581 geoSelectionConfigFile=seedingConfigFile,
0582 outputDirRoot=outputDirLessRoot,
0583 outputDirCsv=outputDirLessCsv,
0584 )
0585
0586 if args.MLSeedFilter:
0587 from acts.examples.reconstruction import (
0588 addSeedFilterML,
0589 SeedFilterMLDBScanConfig,
0590 )
0591
0592 addSeedFilterML(
0593 s,
0594 SeedFilterMLDBScanConfig(
0595 epsilonDBScan=0.03, minPointsDBScan=2, minSeedScore=0.1
0596 ),
0597 onnxModelFile=str(
0598 geo_dir
0599 / "Examples/Scripts/Python/MLAmbiguityResolution/seedDuplicateClassifier.onnx"
0600 ),
0601 outputDirRoot=outputDirLessRoot,
0602 outputDirCsv=outputDirLessCsv,
0603 )
0604
0605 if not args.ckf:
0606 return s
0607
0608 if args.seeding_algorithm != SeedingAlgorithm.TruthSmeared:
0609 ckfConfig = CkfConfig(
0610 seedDeduplication=True,
0611 stayOnSeed=True,
0612 )
0613 else:
0614 ckfConfig = CkfConfig()
0615
0616 if not args.itk:
0617 trackSelectorConfig = TrackSelectorConfig(
0618 pt=(ptMin if args.ttbar_pu200 else 0.0, None),
0619 absEta=(None, 3.0),
0620 loc0=(-4.0 * u.mm, 4.0 * u.mm),
0621 nMeasurementsMin=7,
0622 maxHoles=2,
0623 maxOutliers=2,
0624 )
0625 ckfConfig = ckfConfig._replace(
0626 chi2CutOffMeasurement=15.0,
0627 chi2CutOffOutlier=25.0,
0628 numMeasurementsCutOff=10,
0629 )
0630 else:
0631
0632 trackSelectorConfig = (
0633 TrackSelectorConfig(absEta=(None, 2.0), pt=(0.9 * u.GeV, None), nMeasurementsMin=9, maxHoles=2, maxOutliers=2, maxSharedHits=2),
0634 TrackSelectorConfig(absEta=(None, 2.6), pt=(0.4 * u.GeV, None), nMeasurementsMin=8, maxHoles=2, maxOutliers=2, maxSharedHits=2),
0635 TrackSelectorConfig(absEta=(None, 4.0), pt=(0.4 * u.GeV, None), nMeasurementsMin=7, maxHoles=2, maxOutliers=2, maxSharedHits=2),
0636 )
0637
0638
0639 if args.odd:
0640 ckfConfig = ckfConfig._replace(
0641 pixelVolumes=[16, 17, 18],
0642 stripVolumes=[23, 24, 25],
0643 maxPixelHoles=1,
0644 maxStripHoles=2,
0645 constrainToVolumes=[
0646 2,
0647 32,
0648 4,
0649 16,
0650 17,
0651 18,
0652 20,
0653 23,
0654 24,
0655 25,
0656 26,
0657 8,
0658 28,
0659 29,
0660 30,
0661 ],
0662 )
0663 elif args.itk:
0664 ckfConfig = ckfConfig._replace(
0665
0666 pixelVolumes=[8, 9, 10, 13, 14, 15, 16, 18, 19, 20],
0667 stripVolumes=[22, 23, 24],
0668 maxPixelHoles=1,
0669 maxStripHoles=2,
0670 )
0671
0672 if args.output_detail == 1:
0673 writeDetail = dict(writeTrackSummary=False)
0674 elif args.output_detail == 2:
0675 writeDetail = dict(writeTrackStates=True)
0676 else:
0677 writeDetail = {}
0678
0679 if args.odd and args.output_detail != 1:
0680 writeCovMat = dict(writeCovMat=True)
0681 else:
0682 writeCovMat = {}
0683
0684 addCKFTracks(
0685 s,
0686 trackingGeometry,
0687 field,
0688 trackSelectorConfig=trackSelectorConfig,
0689 ckfConfig=ckfConfig,
0690 **writeDetail,
0691 **writeCovMat,
0692 outputDirRoot=outputDirLessRoot,
0693 outputDirCsv=outputDirLessCsv,
0694 )
0695
0696 if args.ambi_solver == "ML":
0697
0698 from acts.examples.reconstruction import (
0699 addAmbiguityResolutionML,
0700 AmbiguityResolutionMLConfig,
0701 )
0702
0703 addAmbiguityResolutionML(
0704 s,
0705 AmbiguityResolutionMLConfig(
0706 maximumSharedHits=3, maximumIterations=1000000, nMeasurementsMin=7
0707 ),
0708 onnxModelFile=str(
0709 geo_dir
0710 / "Examples/Scripts/Python/MLAmbiguityResolution/duplicateClassifier.onnx"
0711 ),
0712 outputDirRoot=outputDirLessRoot,
0713 outputDirCsv=outputDirLessCsv,
0714 )
0715
0716 elif args.ambi_solver == "scoring":
0717
0718 from acts.examples.reconstruction import (
0719 addScoreBasedAmbiguityResolution,
0720 ScoreBasedAmbiguityResolutionConfig,
0721 )
0722 import math
0723
0724 addScoreBasedAmbiguityResolution(
0725 s,
0726 ScoreBasedAmbiguityResolutionConfig(
0727 minScore=0,
0728 minScoreSharedTracks=1,
0729 maxShared=2,
0730 maxSharedTracksPerMeasurement=2,
0731 pTMax=1400,
0732 pTMin=0.5,
0733 phiMax=math.pi,
0734 phiMin=-math.pi,
0735 etaMax=4,
0736 etaMin=-4,
0737 useAmbiguityFunction=False,
0738 ),
0739 ambiVolumeFile=args.ambi_config,
0740 **writeCovMat,
0741 outputDirRoot=outputDirLessRoot,
0742 outputDirCsv=outputDirLessCsv,
0743 )
0744
0745 elif args.ambi_solver == "greedy":
0746
0747 addAmbiguityResolution(
0748 s,
0749 AmbiguityResolutionConfig(
0750 maximumSharedHits=3,
0751 maximumIterations=10000 if args.itk else 1000000,
0752 nMeasurementsMin=6 if args.itk else 7,
0753 ),
0754 **writeDetail,
0755 **writeCovMat,
0756 outputDirRoot=outputDirLessRoot,
0757 outputDirCsv=outputDirLessCsv,
0758 )
0759
0760 if args.vertexing:
0761 addVertexFitting(
0762 s,
0763 field,
0764 vertexFinder=VertexFinder.AMVF,
0765 outputDirRoot=outputDirLessRoot,
0766 )
0767
0768 return s
0769
0770
0771 def strToRange(s: str, optName: str, unit: float = 1.0):
0772 global logger
0773 try:
0774 range = [float(e) * unit if e != "" else None for e in s.split(":")]
0775 except ValueError:
0776 range = []
0777 if len(range) == 1:
0778 range.append(range[0])
0779 if len(range) != 2:
0780 logger.fatal(f"bad option value: {optName} {s}")
0781 sys.exit(2)
0782 return range
0783
0784
0785
0786 class EnumAction(argparse.Action):
0787 """
0788 Argparse action for handling Enums
0789 """
0790
0791 def __init__(self, **kwargs):
0792 import enum
0793
0794
0795 enum_type = kwargs.pop("enum", None)
0796
0797
0798 if enum_type is None:
0799 raise ValueError("type must be assigned an Enum when using EnumAction")
0800 if not issubclass(enum_type, enum.Enum):
0801 raise TypeError("type must be an Enum when using EnumAction")
0802
0803
0804 kwargs.setdefault("choices", tuple(e.name for e in enum_type))
0805
0806 super(EnumAction, self).__init__(**kwargs)
0807
0808 self._enum = enum_type
0809
0810 def __call__(self, parser, namespace, values, option_string=None):
0811 for e in self._enum:
0812 if e.name == values:
0813 setattr(namespace, self.dest, e)
0814 break
0815 else:
0816 raise ValueError("%s is not a validly enumerated algorithm." % values)
0817
0818
0819
0820 full_chain(parse_args()).run()