Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-06-30 07:52:48

0001 #!/usr/bin/env python3
0002 
0003 import os
0004 import argparse
0005 import pathlib
0006 
0007 import acts
0008 import acts.examples
0009 from acts.examples.simulation import (
0010     MomentumConfig,
0011     EtaConfig,
0012     PhiConfig,
0013     ParticleConfig,
0014     ParticleSelectorConfig,
0015     addParticleGun,
0016     addPythia8,
0017     addGenParticleSelection,
0018     addFatras,
0019     addGeant4,
0020     addSimParticleSelection,
0021     addDigitization,
0022     addDigiParticleSelection,
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 actsDir = pathlib.Path(__file__).parent.parent.parent.parent
0155 # acts.examples.dump_args_calls(locals())  # show python binding calls
0156 
0157 oddMaterialMap = (
0158     args.material_config
0159     if args.material_config
0160     else geoDir / "data/odd-material-maps.root"
0161 )
0162 
0163 oddDigiConfig = (
0164     args.digi_config
0165     if args.digi_config
0166     else actsDir / "Examples/Configs/odd-digi-smearing-config.json"
0167 )
0168 
0169 oddSeedingSel = actsDir / "Examples/Configs/odd-seeding-config.json"
0170 oddMaterialDeco = acts.IMaterialDecorator.fromFile(oddMaterialMap)
0171 
0172 detector = getOpenDataDetector(odd_dir=geoDir, materialDecorator=oddMaterialDeco)
0173 trackingGeometry = detector.trackingGeometry()
0174 decorators = detector.contextDecorators()
0175 field = acts.ConstantBField(acts.Vector3(0.0, 0.0, 2.0 * u.T))
0176 rnd = acts.examples.RandomNumbers(seed=42)
0177 
0178 s = acts.examples.Sequencer(
0179     events=args.events,
0180     skip=args.skip,
0181     numThreads=1 if args.geant4 else -1,
0182     outputDir=str(outputDir),
0183 )
0184 
0185 if args.edm4hep:
0186     import acts.examples.edm4hep
0187 
0188     edm4hepReader = acts.examples.edm4hep.EDM4hepSimReader(
0189         inputPath=str(args.edm4hep),
0190         inputSimHits=[
0191             "PixelBarrelReadout",
0192             "PixelEndcapReadout",
0193             "ShortStripBarrelReadout",
0194             "ShortStripEndcapReadout",
0195             "LongStripBarrelReadout",
0196             "LongStripEndcapReadout",
0197         ],
0198         outputParticlesGenerator="particles_generated",
0199         outputParticlesSimulation="particles_simulated",
0200         outputSimHits="simhits",
0201         graphvizOutput="graphviz",
0202         dd4hepDetector=detector,
0203         trackingGeometry=trackingGeometry,
0204         sortSimHitsInTime=True,
0205         level=acts.logging.INFO,
0206     )
0207     s.addReader(edm4hepReader)
0208 
0209     s.addWhiteboardAlias("particles", edm4hepReader.config.outputParticlesGenerator)
0210 
0211     addSimParticleSelection(
0212         s,
0213         ParticleSelectorConfig(
0214             rho=(0.0, 24 * u.mm),
0215             absZ=(0.0, 1.0 * u.m),
0216             eta=(-3.0, 3.0),
0217             pt=(150 * u.MeV, None),
0218             removeNeutral=True,
0219         ),
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         addGenParticleSelection(
0261             s,
0262             ParticleSelectorConfig(
0263                 rho=(0.0, 24 * u.mm),
0264                 absZ=(0.0, 1.0 * u.m),
0265                 eta=(-3.0, 3.0),
0266                 pt=(150 * u.MeV, None),
0267             ),
0268         )
0269 
0270     if args.geant4:
0271         if s.config.numThreads != 1:
0272             raise ValueError("Geant 4 simulation does not support multi-threading")
0273 
0274         # Pythia can sometime simulate particles outside the world volume, a cut on the Z of the track help mitigate this effect
0275         # Older version of G4 might not work, this as has been tested on version `geant4-11-00-patch-03`
0276         # For more detail see issue #1578
0277         addGeant4(
0278             s,
0279             detector,
0280             trackingGeometry,
0281             field,
0282             outputDirRoot=outputDir if args.output_root else None,
0283             outputDirCsv=outputDir if args.output_csv else None,
0284             outputDirObj=outputDir if args.output_obj else None,
0285             rnd=rnd,
0286             killVolume=trackingGeometry.highestTrackingVolume,
0287             killAfterTime=25 * u.ns,
0288         )
0289     else:
0290         addFatras(
0291             s,
0292             trackingGeometry,
0293             field,
0294             enableInteractions=True,
0295             outputDirRoot=outputDir if args.output_root else None,
0296             outputDirCsv=outputDir if args.output_csv else None,
0297             outputDirObj=outputDir if args.output_obj else None,
0298             rnd=rnd,
0299         )
0300 
0301 addDigitization(
0302     s,
0303     trackingGeometry,
0304     field,
0305     digiConfigFile=oddDigiConfig,
0306     outputDirRoot=outputDir if args.output_root else None,
0307     outputDirCsv=outputDir if args.output_csv else None,
0308     rnd=rnd,
0309 )
0310 
0311 addDigiParticleSelection(
0312     s,
0313     ParticleSelectorConfig(
0314         pt=(1.0 * u.GeV, None),
0315         eta=(-3.0, 3.0),
0316         measurements=(9, None),
0317         removeNeutral=True,
0318     ),
0319 )
0320 
0321 if args.reco:
0322     addSeeding(
0323         s,
0324         trackingGeometry,
0325         field,
0326         initialSigmas=[
0327             1 * u.mm,
0328             1 * u.mm,
0329             1 * u.degree,
0330             1 * u.degree,
0331             0 * u.e / u.GeV,
0332             1 * u.ns,
0333         ],
0334         initialSigmaQoverPt=0.1 * u.e / u.GeV,
0335         initialSigmaPtRel=0.1,
0336         initialVarInflation=[1.0] * 6,
0337         geoSelectionConfigFile=oddSeedingSel,
0338         outputDirRoot=outputDir if args.output_root else None,
0339         outputDirCsv=outputDir if args.output_csv else None,
0340     )
0341 
0342     if seedFilter_ML:
0343         addSeedFilterML(
0344             s,
0345             SeedFilterMLDBScanConfig(
0346                 epsilonDBScan=0.03, minPointsDBScan=2, minSeedScore=0.1
0347             ),
0348             onnxModelFile=os.path.dirname(__file__)
0349             + "/MLAmbiguityResolution/seedDuplicateClassifier.onnx",
0350             outputDirRoot=outputDir if args.output_root else None,
0351             outputDirCsv=outputDir if args.output_csv else None,
0352         )
0353 
0354     addCKFTracks(
0355         s,
0356         trackingGeometry,
0357         field,
0358         TrackSelectorConfig(
0359             pt=(1.0 * u.GeV if args.ttbar else 0.0, None),
0360             absEta=(None, 3.0),
0361             loc0=(-4.0 * u.mm, 4.0 * u.mm),
0362             nMeasurementsMin=7,
0363             maxHoles=2,
0364             maxOutliers=2,
0365         ),
0366         CkfConfig(
0367             chi2CutOffMeasurement=15.0,
0368             chi2CutOffOutlier=25.0,
0369             numMeasurementsCutOff=10,
0370             seedDeduplication=True,
0371             stayOnSeed=True,
0372             pixelVolumes=[16, 17, 18],
0373             stripVolumes=[23, 24, 25],
0374             maxPixelHoles=1,
0375             maxStripHoles=2,
0376             constrainToVolumes=[
0377                 2,  # beam pipe
0378                 32,
0379                 4,  # beam pip gap
0380                 16,
0381                 17,
0382                 18,  # pixel
0383                 20,  # PST
0384                 23,
0385                 24,
0386                 25,  # short strip
0387                 26,
0388                 8,  # long strip gap
0389                 28,
0390                 29,
0391                 30,  # long strip
0392             ],
0393         ),
0394         outputDirRoot=outputDir if args.output_root else None,
0395         outputDirCsv=outputDir if args.output_csv else None,
0396         writeCovMat=True,
0397     )
0398 
0399     if ambi_ML:
0400         addAmbiguityResolutionML(
0401             s,
0402             AmbiguityResolutionMLConfig(
0403                 maximumSharedHits=3, maximumIterations=1000000, nMeasurementsMin=7
0404             ),
0405             outputDirRoot=outputDir if args.output_root else None,
0406             outputDirCsv=outputDir if args.output_csv else None,
0407             onnxModelFile=os.path.dirname(__file__)
0408             + "/MLAmbiguityResolution/duplicateClassifier.onnx",
0409         )
0410 
0411     elif ambi_scoring:
0412         addScoreBasedAmbiguityResolution(
0413             s,
0414             ScoreBasedAmbiguityResolutionConfig(
0415                 minScore=0,
0416                 minScoreSharedTracks=1,
0417                 maxShared=2,
0418                 minUnshared=3,
0419                 maxSharedTracksPerMeasurement=2,
0420                 useAmbiguityScoring=False,
0421             ),
0422             outputDirRoot=outputDir if args.output_root else None,
0423             outputDirCsv=outputDir if args.output_csv else None,
0424             ambiVolumeFile=ambi_config,
0425             writeCovMat=True,
0426         )
0427     else:
0428         addAmbiguityResolution(
0429             s,
0430             AmbiguityResolutionConfig(
0431                 maximumSharedHits=3, maximumIterations=1000000, nMeasurementsMin=7
0432             ),
0433             outputDirRoot=outputDir if args.output_root else None,
0434             outputDirCsv=outputDir if args.output_csv else None,
0435             writeCovMat=True,
0436         )
0437 
0438     addVertexFitting(
0439         s,
0440         field,
0441         vertexFinder=VertexFinder.AMVF,
0442         outputDirRoot=outputDir if args.output_root else None,
0443     )
0444 
0445 s.run()