File indexing completed on 2025-01-18 09:12:08
0001
0002
0003 import os
0004 import argparse
0005 import pathlib
0006 import math
0007
0008 import acts
0009 import acts.examples
0010 from acts.examples.simulation import (
0011 addParticleGun,
0012 MomentumConfig,
0013 EtaConfig,
0014 PhiConfig,
0015 ParticleConfig,
0016 ParticleSelectorConfig,
0017 addPythia8,
0018 addFatras,
0019 addGeant4,
0020 ParticleSelectorConfig,
0021 addDigitization,
0022 addParticleSelection,
0023 )
0024 from acts.examples.reconstruction import (
0025 addSeeding,
0026 CkfConfig,
0027 addCKFTracks,
0028 TrackSelectorConfig,
0029 addAmbiguityResolution,
0030 AmbiguityResolutionConfig,
0031 addAmbiguityResolutionML,
0032 AmbiguityResolutionMLConfig,
0033 addScoreBasedAmbiguityResolution,
0034 ScoreBasedAmbiguityResolutionConfig,
0035 addVertexFitting,
0036 VertexFinder,
0037 addSeedFilterML,
0038 SeedFilterMLDBScanConfig,
0039 )
0040 from acts.examples.odd import getOpenDataDetector, getOpenDataDetectorDirectory
0041
0042 u = acts.UnitConstants
0043
0044
0045 parser = argparse.ArgumentParser(description="Full chain with the OpenDataDetector")
0046 parser.add_argument(
0047 "--output",
0048 "-o",
0049 help="Output directory",
0050 type=pathlib.Path,
0051 default=pathlib.Path.cwd() / "odd_output",
0052 )
0053 parser.add_argument("--events", "-n", help="Number of events", type=int, default=100)
0054 parser.add_argument("--skip", "-s", help="Number of events", type=int, default=0)
0055 parser.add_argument("--edm4hep", help="Use edm4hep inputs", type=pathlib.Path)
0056 parser.add_argument(
0057 "--geant4", help="Use Geant4 instead of fatras", action="store_true"
0058 )
0059 parser.add_argument(
0060 "--ttbar",
0061 help="Use Pythia8 (ttbar, pile-up 200) instead of particle gun",
0062 action="store_true",
0063 )
0064 parser.add_argument(
0065 "--ttbar-pu",
0066 help="Number of pile-up events for ttbar",
0067 type=int,
0068 default=200,
0069 )
0070 parser.add_argument(
0071 "--gun-particles",
0072 help="Multiplicity (no. of particles) of the particle gun",
0073 type=int,
0074 default=4,
0075 )
0076 parser.add_argument(
0077 "--gun-multiplicity",
0078 help="Multiplicity (no. of vertices) of the particle gun",
0079 type=int,
0080 default=200,
0081 )
0082 parser.add_argument(
0083 "--gun-eta-range",
0084 nargs=2,
0085 help="Eta range of the particle gun",
0086 type=float,
0087 default=[-3.0, 3.0],
0088 )
0089 parser.add_argument(
0090 "--gun-pt-range",
0091 nargs=2,
0092 help="Pt range of the particle gun (GeV)",
0093 type=float,
0094 default=[1.0 * u.GeV, 10.0 * u.GeV],
0095 )
0096 parser.add_argument(
0097 "--digi-config", help="Digitization configuration file", type=pathlib.Path
0098 )
0099 parser.add_argument(
0100 "--material-config", help="Material map configuration file", type=pathlib.Path
0101 )
0102 parser.add_argument(
0103 "--ambi-solver",
0104 help="Set which ambiguity solver to use, default is the classical one",
0105 type=str,
0106 choices=["greedy", "scoring", "ML"],
0107 default="greedy",
0108 )
0109 parser.add_argument(
0110 "--ambi-config",
0111 help="Set the configuration file for the Score Based ambiguity resolution",
0112 type=pathlib.Path,
0113 default=pathlib.Path.cwd() / "ambi_config.json",
0114 )
0115
0116 parser.add_argument(
0117 "--MLSeedFilter",
0118 help="Use the Ml seed filter to select seed after the seeding step",
0119 action="store_true",
0120 )
0121 parser.add_argument(
0122 "--reco",
0123 help="Switch reco on/off",
0124 default=True,
0125 action=argparse.BooleanOptionalAction,
0126 )
0127 parser.add_argument(
0128 "--output-root",
0129 help="Switch root output on/off",
0130 default=True,
0131 action=argparse.BooleanOptionalAction,
0132 )
0133 parser.add_argument(
0134 "--output-csv",
0135 help="Switch csv output on/off",
0136 default=True,
0137 action=argparse.BooleanOptionalAction,
0138 )
0139 parser.add_argument(
0140 "--output-obj",
0141 help="Switch obj output on/off",
0142 default=True,
0143 action=argparse.BooleanOptionalAction,
0144 )
0145
0146 args = parser.parse_args()
0147
0148 outputDir = args.output
0149 ambi_ML = args.ambi_solver == "ML"
0150 ambi_scoring = args.ambi_solver == "scoring"
0151 ambi_config = args.ambi_config
0152 seedFilter_ML = args.MLSeedFilter
0153 geoDir = getOpenDataDetectorDirectory()
0154
0155
0156 oddMaterialMap = (
0157 args.material_config
0158 if args.material_config
0159 else geoDir / "data/odd-material-maps.root"
0160 )
0161
0162 oddDigiConfig = (
0163 args.digi_config
0164 if args.digi_config
0165 else geoDir / "config/odd-digi-smearing-config.json"
0166 )
0167
0168 oddSeedingSel = geoDir / "config/odd-seeding-config.json"
0169 oddMaterialDeco = acts.IMaterialDecorator.fromFile(oddMaterialMap)
0170
0171 detector = getOpenDataDetector(odd_dir=geoDir, mdecorator=oddMaterialDeco)
0172 trackingGeometry = detector.trackingGeometry()
0173 decorators = detector.contextDecorators()
0174 field = acts.ConstantBField(acts.Vector3(0.0, 0.0, 2.0 * u.T))
0175 rnd = acts.examples.RandomNumbers(seed=42)
0176
0177 s = acts.examples.Sequencer(
0178 events=args.events,
0179 skip=args.skip,
0180 numThreads=1 if args.geant4 else -1,
0181 outputDir=str(outputDir),
0182 )
0183
0184 if args.edm4hep:
0185 import acts.examples.edm4hep
0186
0187 edm4hepReader = acts.examples.edm4hep.EDM4hepReader(
0188 inputPath=str(args.edm4hep),
0189 inputSimHits=[
0190 "PixelBarrelReadout",
0191 "PixelEndcapReadout",
0192 "ShortStripBarrelReadout",
0193 "ShortStripEndcapReadout",
0194 "LongStripBarrelReadout",
0195 "LongStripEndcapReadout",
0196 ],
0197 outputParticlesGenerator="particles_input",
0198 outputParticlesSimulation="particles_simulated",
0199 outputSimHits="simhits",
0200 graphvizOutput="graphviz",
0201 dd4hepDetector=detector,
0202 trackingGeometry=trackingGeometry,
0203 sortSimHitsInTime=True,
0204 level=acts.logging.INFO,
0205 )
0206 s.addReader(edm4hepReader)
0207 s.addWhiteboardAlias("particles", edm4hepReader.config.outputParticlesGenerator)
0208
0209 addParticleSelection(
0210 s,
0211 config=ParticleSelectorConfig(
0212 rho=(0.0, 24 * u.mm),
0213 absZ=(0.0, 1.0 * u.m),
0214 eta=(-3.0, 3.0),
0215 pt=(150 * u.MeV, None),
0216 removeNeutral=True,
0217 ),
0218 inputParticles="particles",
0219 outputParticles="particles_selected",
0220 )
0221 else:
0222 if not args.ttbar:
0223 addParticleGun(
0224 s,
0225 MomentumConfig(
0226 args.gun_pt_range[0] * u.GeV,
0227 args.gun_pt_range[1] * u.GeV,
0228 transverse=True,
0229 ),
0230 EtaConfig(args.gun_eta_range[0], args.gun_eta_range[1]),
0231 PhiConfig(0.0, 360.0 * u.degree),
0232 ParticleConfig(
0233 args.gun_particles, acts.PdgParticle.eMuon, randomizeCharge=True
0234 ),
0235 vtxGen=acts.examples.GaussianVertexGenerator(
0236 mean=acts.Vector4(0, 0, 0, 0),
0237 stddev=acts.Vector4(
0238 0.0125 * u.mm, 0.0125 * u.mm, 55.5 * u.mm, 1.0 * u.ns
0239 ),
0240 ),
0241 multiplicity=args.gun_multiplicity,
0242 rnd=rnd,
0243 )
0244 else:
0245 addPythia8(
0246 s,
0247 hardProcess=["Top:qqbar2ttbar=on"],
0248 npileup=args.ttbar_pu,
0249 vtxGen=acts.examples.GaussianVertexGenerator(
0250 mean=acts.Vector4(0, 0, 0, 0),
0251 stddev=acts.Vector4(
0252 0.0125 * u.mm, 0.0125 * u.mm, 55.5 * u.mm, 5.0 * u.ns
0253 ),
0254 ),
0255 rnd=rnd,
0256 outputDirRoot=outputDir if args.output_root else None,
0257 outputDirCsv=outputDir if args.output_csv else None,
0258 )
0259
0260 if args.geant4:
0261 if s.config.numThreads != 1:
0262 raise ValueError("Geant 4 simulation does not support multi-threading")
0263
0264
0265
0266
0267 addGeant4(
0268 s,
0269 detector,
0270 trackingGeometry,
0271 field,
0272 preSelectParticles=ParticleSelectorConfig(
0273 rho=(0.0, 24 * u.mm),
0274 absZ=(0.0, 1.0 * u.m),
0275 eta=(-3.0, 3.0),
0276 pt=(150 * u.MeV, None),
0277 ),
0278 postSelectParticles=ParticleSelectorConfig(
0279 pt=(1.0 * u.GeV, None),
0280 eta=(-3.0, 3.0),
0281 hits=(9, None),
0282 removeNeutral=True,
0283 ),
0284 outputDirRoot=outputDir if args.output_root else None,
0285 outputDirCsv=outputDir if args.output_csv else None,
0286 outputDirObj=outputDir if args.output_obj else None,
0287 rnd=rnd,
0288 killVolume=trackingGeometry.highestTrackingVolume,
0289 killAfterTime=25 * u.ns,
0290 )
0291 else:
0292 addFatras(
0293 s,
0294 trackingGeometry,
0295 field,
0296 preSelectParticles=(
0297 ParticleSelectorConfig(
0298 rho=(0.0, 24 * u.mm),
0299 absZ=(0.0, 1.0 * u.m),
0300 eta=(-3.0, 3.0),
0301 pt=(150 * u.MeV, None),
0302 )
0303 if args.ttbar
0304 else ParticleSelectorConfig()
0305 ),
0306 postSelectParticles=ParticleSelectorConfig(
0307 pt=(1.0 * u.GeV, None),
0308 eta=(-3.0, 3.0),
0309 hits=(9, None),
0310 removeNeutral=True,
0311 ),
0312 enableInteractions=True,
0313 outputDirRoot=outputDir if args.output_root else None,
0314 outputDirCsv=outputDir if args.output_csv else None,
0315 outputDirObj=outputDir if args.output_obj else None,
0316 rnd=rnd,
0317 )
0318
0319 addDigitization(
0320 s,
0321 trackingGeometry,
0322 field,
0323 digiConfigFile=oddDigiConfig,
0324 outputDirRoot=outputDir if args.output_root else None,
0325 outputDirCsv=outputDir if args.output_csv else None,
0326 rnd=rnd,
0327 )
0328
0329 if args.reco:
0330 addSeeding(
0331 s,
0332 trackingGeometry,
0333 field,
0334 initialSigmas=[
0335 1 * u.mm,
0336 1 * u.mm,
0337 1 * u.degree,
0338 1 * u.degree,
0339 0.1 * u.e / u.GeV,
0340 1 * u.ns,
0341 ],
0342 initialSigmaPtRel=0.1,
0343 initialVarInflation=[1.0] * 6,
0344 geoSelectionConfigFile=oddSeedingSel,
0345 outputDirRoot=outputDir if args.output_root else None,
0346 outputDirCsv=outputDir if args.output_csv else None,
0347 )
0348
0349 if seedFilter_ML:
0350 addSeedFilterML(
0351 s,
0352 SeedFilterMLDBScanConfig(
0353 epsilonDBScan=0.03, minPointsDBScan=2, minSeedScore=0.1
0354 ),
0355 onnxModelFile=os.path.dirname(__file__)
0356 + "/MLAmbiguityResolution/seedDuplicateClassifier.onnx",
0357 outputDirRoot=outputDir if args.output_root else None,
0358 outputDirCsv=outputDir if args.output_csv else None,
0359 )
0360
0361 addCKFTracks(
0362 s,
0363 trackingGeometry,
0364 field,
0365 TrackSelectorConfig(
0366 pt=(1.0 * u.GeV if args.ttbar else 0.0, None),
0367 absEta=(None, 3.0),
0368 loc0=(-4.0 * u.mm, 4.0 * u.mm),
0369 nMeasurementsMin=7,
0370 maxHoles=2,
0371 maxOutliers=2,
0372 ),
0373 CkfConfig(
0374 chi2CutOffMeasurement=15.0,
0375 chi2CutOffOutlier=25.0,
0376 numMeasurementsCutOff=10,
0377 seedDeduplication=True,
0378 stayOnSeed=True,
0379 pixelVolumes=[16, 17, 18],
0380 stripVolumes=[23, 24, 25],
0381 maxPixelHoles=1,
0382 maxStripHoles=2,
0383 constrainToVolumes=[
0384 2,
0385 32,
0386 4,
0387 16,
0388 17,
0389 18,
0390 20,
0391 23,
0392 24,
0393 25,
0394 26,
0395 8,
0396 28,
0397 29,
0398 30,
0399 ],
0400 ),
0401 outputDirRoot=outputDir if args.output_root else None,
0402 outputDirCsv=outputDir if args.output_csv else None,
0403 writeCovMat=True,
0404 )
0405
0406 if ambi_ML:
0407 addAmbiguityResolutionML(
0408 s,
0409 AmbiguityResolutionMLConfig(
0410 maximumSharedHits=3, maximumIterations=1000000, nMeasurementsMin=7
0411 ),
0412 outputDirRoot=outputDir if args.output_root else None,
0413 outputDirCsv=outputDir if args.output_csv else None,
0414 onnxModelFile=os.path.dirname(__file__)
0415 + "/MLAmbiguityResolution/duplicateClassifier.onnx",
0416 )
0417
0418 elif ambi_scoring:
0419 addScoreBasedAmbiguityResolution(
0420 s,
0421 ScoreBasedAmbiguityResolutionConfig(
0422 minScore=0,
0423 minScoreSharedTracks=1,
0424 maxShared=2,
0425 maxSharedTracksPerMeasurement=2,
0426 pTMax=1400,
0427 pTMin=0.5,
0428 phiMax=math.pi,
0429 phiMin=-math.pi,
0430 etaMax=4,
0431 etaMin=-4,
0432 useAmbiguityFunction=False,
0433 ),
0434 outputDirRoot=outputDir if args.output_root else None,
0435 outputDirCsv=outputDir if args.output_csv else None,
0436 ambiVolumeFile=ambi_config,
0437 writeCovMat=True,
0438 )
0439 else:
0440 addAmbiguityResolution(
0441 s,
0442 AmbiguityResolutionConfig(
0443 maximumSharedHits=3, maximumIterations=1000000, nMeasurementsMin=7
0444 ),
0445 outputDirRoot=outputDir if args.output_root else None,
0446 outputDirCsv=outputDir if args.output_csv else None,
0447 writeCovMat=True,
0448 )
0449
0450 addVertexFitting(
0451 s,
0452 field,
0453 vertexFinder=VertexFinder.AMVF,
0454 outputDirRoot=outputDir if args.output_root else None,
0455 )
0456
0457 s.run()