1 from typing
import Optional, Union, Any, List
2 from pathlib
import Path
3 from collections
import namedtuple
4 from collections.abc
import Iterable
10 FixedMultiplicityGenerator,
18 MomentumConfig = namedtuple(
20 [
"min",
"max",
"transverse"],
21 defaults=[
None,
None,
None],
23 EtaConfig = namedtuple(
24 "EtaConfig", [
"min",
"max",
"uniform"], defaults=[
None,
None,
None]
26 PhiConfig = namedtuple(
"PhiConfig", [
"min",
"max"], defaults=[
None,
None])
27 ParticleConfig = namedtuple(
29 [
"num",
"pdg",
"randomizeCharge",
"charge",
"mass"],
30 defaults=[
None,
None,
None,
None,
None],
32 ParticleSelectorConfig = namedtuple(
33 "ParticleSelectorConfig",
48 defaults=[(
None,
None)] * 9 + [
None] * 3,
53 momentumConfig=MomentumConfig,
56 particleConfig=ParticleConfig,
60 outputDirCsv: Optional[Union[Path, str]] =
None,
61 outputDirRoot: Optional[Union[Path, str]] =
None,
66 multiplicity: int = 1,
67 vtxGen: Optional[EventGenerator.VertexGenerator] =
None,
68 printParticles: bool =
False,
69 rnd: Optional[RandomNumbers] =
None,
70 logLevel: Optional[acts.logging.Level] =
None,
72 """This function steers the particle generation using the particle gun
77 the sequencer module to which we add the particle gun steps (returned from addParticleGun)
78 outputDirCsv : Path|str, path, None
79 the output folder for the Csv output, None triggers no output
80 outputDirRoot : Path|str, path, None
81 the output folder for the Root output, None triggers no output
82 momentumConfig : MomentumConfig(min, max, transverse)
83 momentum configuration: minimum momentum, maximum momentum, transverse
84 etaConfig : EtaConfig(min, max, uniform)
85 pseudorapidity configuration: eta min, eta max, uniform
86 phiConfig : PhiConfig(min, max)
87 azimuthal angle configuration: phi min, phi max
88 particleConfig : ParticleConfig(num, pdg, randomizeCharge, charge, mass)
89 particle configuration: number of particles, particle type, charge flip
91 number of generated vertices
92 vtxGen : VertexGenerator, None
93 vertex generator module
94 printParticles : bool, False
95 print generated particles
96 rnd : RandomNumbers, None
97 random number generator
103 rnd = rnd
or RandomNumbers(seed=228)
106 evGen = EventGenerator(
107 level=customLogLevel(),
109 EventGenerator.Generator(
110 multiplicity=FixedMultiplicityGenerator(n=multiplicity),
112 or acts.examples.GaussianVertexGenerator(
113 mean=acts.Vector4(0, 0, 0, 0),
114 stddev=acts.Vector4(0, 0, 0, 0),
116 particles=acts.examples.ParametricParticleGenerator(
118 p=(momentumConfig.min, momentumConfig.max),
119 pTransverse=momentumConfig.transverse,
120 eta=(etaConfig.min, etaConfig.max),
121 phi=(phiConfig.min, phiConfig.max),
122 etaUniform=etaConfig.uniform,
123 numParticles=particleConfig.num,
124 pdg=particleConfig.pdg,
125 randomizeCharge=particleConfig.randomizeCharge,
126 charge=particleConfig.charge,
127 mass=particleConfig.mass,
132 outputParticles=
"particles_input",
138 s.addWhiteboardAlias(
"particles", evGen.config.outputParticles)
143 level=customLogLevel(),
144 inputParticles=evGen.config.outputParticles,
148 if outputDirCsv
is not None:
149 outputDirCsv = Path(outputDirCsv)
150 if not outputDirCsv.exists():
155 level=customLogLevel(),
156 inputParticles=evGen.config.outputParticles,
157 outputDir=
str(outputDirCsv),
158 outputStem=
"particles",
162 if outputDirRoot
is not None:
163 outputDirRoot = Path(outputDirRoot)
164 if not outputDirRoot.exists():
165 outputDirRoot.mkdir()
169 level=customLogLevel(),
170 inputParticles=evGen.config.outputParticles,
171 filePath=
str(outputDirRoot /
"particles.root"),
180 rnd: Optional[acts.examples.RandomNumbers] =
None,
184 Union[acts.PdgParticle, Iterable]
186 cmsEnergy: Optional[float] =
None,
187 hardProcess: Optional[Iterable] =
None,
188 pileupProcess: Iterable = [
"SoftQCD:all = on"],
189 vtxGen: Optional[acts.examples.EventGenerator.VertexGenerator] =
None,
190 outputDirCsv: Optional[Union[Path, str]] =
None,
191 outputDirRoot: Optional[Union[Path, str]] =
None,
192 printParticles: bool =
False,
193 printPythiaEventListing: Optional[Union[
None, str]] =
None,
194 logLevel: Optional[acts.logging.Level] =
None,
196 """This function steers the particle generation using Pythia8
201 the sequencer module to which we add the particle gun steps (returned from addParticleGun)
202 rnd : RandomNumbers, None
203 random number generator
204 nhard, npileup : int, 1, 200
205 Number of hard-scatter and pileup vertices
206 beam : PdgParticle|[PdgParticle,PdgParticle], eProton
208 cmsEnergy : float, 14 TeV
210 hardProcess, pileupProcess : [str], ["HardQCD:all = on"], ["SoftQCD:all = on"]
211 hard and pileup processes
212 vtxGen : VertexGenerator, None
213 vertex generator module
214 outputDirCsv : Path|str, path, None
215 the output folder for the Csv output, None triggers no output
216 outputDirRoot : Path|str, path, None
217 the output folder for the Root output, None triggers no output
218 printParticles : bool, False
219 print generated particles
220 printPythiaEventListing
221 None or "short" or "long"
227 rnd = rnd
or acts.examples.RandomNumbers()
228 vtxGen = vtxGen
or acts.examples.GaussianVertexGenerator(
229 stddev=acts.Vector4(0, 0, 0, 0), mean=acts.Vector4(0, 0, 0, 0)
231 if not isinstance(beam, Iterable):
234 if printPythiaEventListing
is None:
235 printShortEventListing =
False
236 printLongEventListing =
False
237 elif printPythiaEventListing ==
"short":
238 printShortEventListing =
True
239 printLongEventListing =
False
240 elif printPythiaEventListing ==
"long":
241 printShortEventListing =
False
242 printLongEventListing =
True
244 raise RuntimeError(
"Invalid pythia config")
247 if nhard
is not None and nhard > 0:
249 acts.examples.EventGenerator.Generator(
250 multiplicity=acts.examples.FixedMultiplicityGenerator(n=nhard),
252 particles=acts.examples.pythia8.Pythia8Generator(
253 level=customLogLevel(),
258 settings=hardProcess,
259 printLongEventListing=printLongEventListing,
260 printShortEventListing=printShortEventListing,
267 acts.examples.EventGenerator.Generator(
268 multiplicity=acts.examples.FixedMultiplicityGenerator(n=npileup),
270 particles=acts.examples.pythia8.Pythia8Generator(
271 level=customLogLevel(),
276 settings=pileupProcess,
283 evGen = acts.examples.EventGenerator(
284 level=customLogLevel(),
285 generators=generators,
286 outputParticles=
"particles_input",
292 s.addWhiteboardAlias(
"particles", evGen.config.outputParticles)
296 acts.examples.ParticlesPrinter(
297 level=customLogLevel(),
298 inputParticles=evGen.config.outputParticles,
302 if outputDirCsv
is not None:
303 outputDirCsv = Path(outputDirCsv)
304 if not outputDirCsv.exists():
308 acts.examples.CsvParticleWriter(
309 level=customLogLevel(),
310 inputParticles=evGen.config.outputParticles,
311 outputDir=
str(outputDirCsv),
312 outputStem=
"particles",
316 if outputDirRoot
is not None:
317 outputDirRoot = Path(outputDirRoot)
318 if not outputDirRoot.exists():
319 outputDirRoot.mkdir()
322 acts.examples.RootParticleWriter(
323 level=customLogLevel(),
324 inputParticles=evGen.config.outputParticles,
325 filePath=
str(outputDirRoot /
"pythia8_particles.root"),
334 config: ParticleSelectorConfig,
336 outputParticles: str,
337 inputMeasurementParticlesMap: str =
"",
338 logLevel: Optional[acts.logging.Level] =
None,
341 This function steers the particle selection.
346 the sequencer module to which we add the ParticleSelector
347 preselectedParticles: ParticleSelectorConfig
348 the particle selection configuration
350 the identifier for the input particles to be selected
352 the identifier for the final selected particle collection
357 acts.examples.ParticleSelector(
359 rhoMin=config.rho[0],
360 rhoMax=config.rho[1],
361 absZMin=config.absZ[0],
362 absZMax=config.absZ[1],
363 timeMin=config.time[0],
364 timeMax=config.time[1],
365 phiMin=config.phi[0],
366 phiMax=config.phi[1],
367 etaMin=config.eta[0],
368 etaMax=config.eta[1],
369 absEtaMin=config.absEta[0],
370 absEtaMax=config.absEta[1],
375 measurementsMin=config.measurements[0],
376 measurementsMax=config.measurements[1],
377 removeCharged=config.removeCharged,
378 removeNeutral=config.removeNeutral,
379 removeSecondaries=config.removeSecondaries,
381 level=customLogLevel(),
382 inputParticles=inputParticles,
383 outputParticles=outputParticles,
384 inputMeasurementParticlesMap=inputMeasurementParticlesMap,
391 trackingGeometry: acts.TrackingGeometry,
392 field: acts.MagneticFieldProvider,
393 rnd: acts.examples.RandomNumbers,
395 postSelectParticles: Optional[ParticleSelectorConfig] =
None,
396 enableInteractions: bool =
True,
397 pMin: Optional[float] =
None,
398 inputParticles: str =
"particles_input",
399 outputParticlesInitial: str =
"particles_initial",
400 outputParticlesFinal: str =
"particles_final",
401 outputSimHits: str =
"simhits",
402 outputDirCsv: Optional[Union[Path, str]] =
None,
403 outputDirRoot: Optional[Union[Path, str]] =
None,
404 logLevel: Optional[acts.logging.Level] =
None,
406 """This function steers the detector simulation using Fatras
411 the sequencer module to which we add the Fatras steps (returned from addFatras)
412 trackingGeometry : tracking geometry
413 field : magnetic field
415 random number generator
416 preSelectParticles : ParticleSelectorConfig(rho, absZ, time, phi, eta, absEta, pt, removeCharged, removeNeutral), None
417 ParticleSelector configuration to select particles as input to Fatras. Each range is specified as a tuple of (min,max).
418 Default of no selections specified in Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.hpp
419 Specify preSelectParticles=None to inhibit ParticleSelector altogether.
420 postSelectParticles : ParticleSelectorConfig(rho, absZ, time, phi, eta, absEta, pt, removeCharged, removeNeutral), None
421 Similar to preSelectParticles but applied after simulation to "particles_initial", therefore also filters secondaries.
422 enableInteractions : Enable the particle interactions in the simulation
423 pMin : Minimum monmentum of particles simulated by FATRAS
424 outputDirCsv : Path|str, path, None
425 the output folder for the Csv output, None triggers no output
426 outputDirRoot : Path|str, path, None
427 the output folder for the Root output, None triggers no output
433 if preSelectParticles
is not None:
434 particles_selected =
"particles_selected"
438 inputParticles=inputParticles,
439 outputParticles=particles_selected,
442 particles_selected = inputParticles
445 alg = acts.examples.FatrasSimulation(
447 level=customLogLevel(),
448 inputParticles=particles_selected,
449 outputParticlesInitial=outputParticlesInitial,
450 outputParticlesFinal=outputParticlesFinal,
451 outputSimHits=outputSimHits,
453 trackingGeometry=trackingGeometry,
455 generateHitsOnSensitive=
True,
456 emScattering=enableInteractions,
457 emEnergyLossIonisation=enableInteractions,
458 emEnergyLossRadiation=enableInteractions,
459 emPhotonConversion=enableInteractions,
468 if postSelectParticles
is not None:
469 particlesInitial =
"fatras_particles_initial_selected"
473 inputParticles=alg.config.outputParticlesInitial,
474 outputParticles=particlesInitial,
477 particlesFinal =
"fatras_particles_final_selected"
481 inputParticles=alg.config.outputParticlesFinal,
482 outputParticles=particlesFinal,
485 particlesInitial = alg.config.outputParticlesInitial
486 particlesFinal = alg.config.outputParticlesFinal
489 s.addWhiteboardAlias(
"particles", particlesInitial)
494 alg.config.outputSimHits,
498 particlesInitial=particlesInitial,
499 particlesFinal=particlesFinal,
507 inputSimHits: Optional[str] =
None,
508 outputDirCsv: Optional[Union[Path, str]] =
None,
509 outputDirRoot: Optional[Union[Path, str]] =
None,
510 logLevel: Optional[acts.logging.Level] =
None,
511 particlesInitial=
"particles_initial",
512 particlesFinal=
"particles_final",
516 if outputDirCsv
is not None:
517 outputDirCsv = Path(outputDirCsv)
518 if not outputDirCsv.exists():
521 acts.examples.CsvParticleWriter(
522 level=customLogLevel(),
523 outputDir=
str(outputDirCsv),
524 inputParticles=particlesInitial,
525 outputStem=
"particles_initial",
529 acts.examples.CsvParticleWriter(
530 level=customLogLevel(),
531 outputDir=
str(outputDirCsv),
532 inputParticles=particlesFinal,
533 outputStem=
"particles_final",
537 acts.examples.CsvSimHitWriter(
538 level=customLogLevel(),
539 inputSimHits=inputSimHits,
540 outputDir=
str(outputDirCsv),
545 if outputDirRoot
is not None:
546 outputDirRoot = Path(outputDirRoot)
547 if not outputDirRoot.exists():
548 outputDirRoot.mkdir()
550 acts.examples.RootParticleWriter(
551 level=customLogLevel(),
552 inputParticles=particlesInitial,
553 filePath=
str(outputDirRoot /
"particles_initial.root"),
557 acts.examples.RootParticleWriter(
558 level=customLogLevel(),
559 inputParticles=particlesFinal,
560 filePath=
str(outputDirRoot /
"particles_final.root"),
564 acts.examples.RootSimHitWriter(
565 level=customLogLevel(),
566 inputSimHits=inputSimHits,
567 filePath=
str(outputDirRoot /
"hits.root"),
579 if type(detector)
is TelescopeDetector:
580 return TelescopeG4DetectorConstructionFactory(detector)
581 except Exception
as e:
588 if type(detector)
is DD4hepDetector:
589 return DDG4DetectorConstructionFactory(detector)
590 except Exception
as e:
593 raise AttributeError(f
"cannot find a suitable detector construction for {detector}")
597 __geant4Handle =
None
602 detector: Optional[Any],
603 trackingGeometry: acts.TrackingGeometry,
604 field: acts.MagneticFieldProvider,
605 rnd: acts.examples.RandomNumbers,
606 g4DetectorConstructionFactory: Optional[Any] =
None,
607 volumeMappings: List[str] = [],
608 materialMappings: List[str] = [],
609 inputParticles: str =
"particles_input",
610 outputParticlesInitial: str =
"particles_initial",
611 outputParticlesFinal: str =
"particles_final",
612 outputSimHits: str =
"simhits",
614 postSelectParticles: Optional[ParticleSelectorConfig] =
None,
615 recordHitsOfSecondaries=
True,
616 keepParticlesWithoutHits=
True,
617 outputDirCsv: Optional[Union[Path, str]] =
None,
618 outputDirRoot: Optional[Union[Path, str]] =
None,
619 logLevel: Optional[acts.logging.Level] =
None,
620 killVolume: Optional[acts.Volume] =
None,
621 killAfterTime: float = float(
"inf"),
622 killSecondaries: bool =
False,
623 physicsList: str =
"FTFP_BERT",
625 """This function steers the detector simulation using Geant4
630 the sequencer module to which we add the Geant4 steps (returned from addGeant4)
631 trackingGeometry : tracking geometry
632 field : magnetic field
633 rnd : RandomNumbers, None
634 random number generator
635 preSelectParticles : ParticleSelectorConfig(rho, absZ, time, phi, eta, absEta, pt, removeCharged, removeNeutral), None
636 ParticleSelector configuration to select particles as input to Geant4. Each range is specified as a tuple of (min,max).
637 Default of no selections specified in Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.hpp
638 Specify preSelectParticles=None to inhibit ParticleSelector altogether.
639 postSelectParticles : ParticleSelectorConfig(rho, absZ, time, phi, eta, absEta, pt, removeCharged, removeNeutral), None
640 Similar to preSelectParticles but applied after simulation to "particles_initial", therefore also filters secondaries.
641 outputDirCsv : Path|str, path, None
642 the output folder for the Csv output, None triggers no output
643 outputDirRoot : Path|str, path, None
644 the output folder for the Root output, None triggers no output
645 killVolume: acts.Volume, None
646 if given, particles are killed when going outside this volume.
648 if given, particle are killed after the global time since event creation exceeds the given value
649 killSecondaries: bool
650 if given, secondary particles are removed from simulation
658 if preSelectParticles
is not None:
659 particles_selected =
"particles_selected"
663 inputParticles=inputParticles,
664 outputParticles=particles_selected,
667 particles_selected = inputParticles
669 if g4DetectorConstructionFactory
is None:
671 raise AttributeError(
"detector not given")
674 global __geant4Handle
677 alg = Geant4Simulation(
678 level=customLogLevel(),
679 geant4Handle=__geant4Handle,
680 detectorConstructionFactory=g4DetectorConstructionFactory,
682 inputParticles=particles_selected,
683 outputSimHits=outputSimHits,
684 outputParticlesInitial=outputParticlesInitial,
685 outputParticlesFinal=outputParticlesFinal,
686 trackingGeometry=trackingGeometry,
688 physicsList=physicsList,
689 volumeMappings=volumeMappings,
690 materialMappings=materialMappings,
691 killVolume=killVolume,
692 killAfterTime=killAfterTime,
693 killSecondaries=killSecondaries,
694 recordHitsOfSecondaries=recordHitsOfSecondaries,
695 keepParticlesWithoutHits=keepParticlesWithoutHits,
698 __geant4Handle = alg.geant4Handle
704 if postSelectParticles
is not None:
705 particlesInitial =
"geant4_particles_initial_selected"
709 inputParticles=alg.config.outputParticlesInitial,
710 outputParticles=particlesInitial,
713 particlesFinal =
"geant4_particles_final_selected"
717 inputParticles=alg.config.outputParticlesFinal,
718 outputParticles=particlesFinal,
721 particlesInitial = alg.config.outputParticlesInitial
722 particlesFinal = alg.config.outputParticlesFinal
725 s.addWhiteboardAlias(
"particles", particlesInitial)
730 alg.config.outputSimHits,
734 particlesInitial=particlesInitial,
735 particlesFinal=particlesFinal,
743 trackingGeometry: acts.TrackingGeometry,
744 field: acts.MagneticFieldProvider,
745 digiConfigFile: Union[Path, str],
746 outputDirCsv: Optional[Union[Path, str]] =
None,
747 outputDirRoot: Optional[Union[Path, str]] =
None,
748 rnd: Optional[acts.examples.RandomNumbers] =
None,
749 doMerge: Optional[bool] =
None,
750 minEnergyDeposit: Optional[float] =
None,
751 logLevel: Optional[acts.logging.Level] =
None,
753 """This function steers the digitization step
758 the sequencer module to which we add the Digitization steps (returned from addDigitization)
759 trackingGeometry : tracking geometry
760 field : magnetic field
761 digiConfigFile : Path|str, path
762 Configuration (.json) file for digitization or smearing description
763 outputDirCsv : Path|str, path, None
764 the output folder for the Csv output, None triggers no output
765 outputDirRoot : Path|str, path, None
766 the output folder for the Root output, None triggers no output
767 rnd : RandomNumbers, None
768 random number generator
774 rnd = rnd
or acts.examples.RandomNumbers()
777 digiCfg = acts.examples.DigitizationConfig(
778 acts.examples.readDigiConfigFromJson(
781 trackingGeometry=trackingGeometry,
783 inputSimHits=
"simhits",
784 outputSourceLinks=
"sourcelinks",
785 outputMeasurements=
"measurements",
786 outputMeasurementParticlesMap=
"measurement_particles_map",
787 outputMeasurementSimHitsMap=
"measurement_simhits_map",
792 if minEnergyDeposit
is not None:
793 digiCfg.minEnergyDeposit = minEnergyDeposit
795 digiAlg = acts.examples.DigitizationAlgorithm(digiCfg, customLogLevel())
797 s.addAlgorithm(digiAlg)
799 if outputDirRoot
is not None:
800 outputDirRoot = Path(outputDirRoot)
801 if not outputDirRoot.exists():
802 outputDirRoot.mkdir()
803 rmwConfig = acts.examples.RootMeasurementWriter.Config(
804 inputMeasurements=digiAlg.config.outputMeasurements,
805 inputClusters=digiAlg.config.outputClusters,
806 inputSimHits=digiAlg.config.inputSimHits,
807 inputMeasurementSimHitsMap=digiAlg.config.outputMeasurementSimHitsMap,
808 filePath=
str(outputDirRoot / f
"{digiAlg.config.outputMeasurements}.root"),
809 trackingGeometry=trackingGeometry,
811 rmwConfig.addBoundIndicesFromDigiConfig(digiAlg.config)
812 s.addWriter(acts.examples.RootMeasurementWriter(rmwConfig, customLogLevel()))
814 if outputDirCsv
is not None:
815 outputDirCsv = Path(outputDirCsv)
816 if not outputDirCsv.exists():
819 acts.examples.CsvMeasurementWriter(
820 level=customLogLevel(),
821 inputMeasurements=digiAlg.config.outputMeasurements,
822 inputClusters=digiAlg.config.outputClusters,
823 inputMeasurementSimHitsMap=digiAlg.config.outputMeasurementSimHitsMap,
824 outputDir=
str(outputDirCsv),