File indexing completed on 2026-03-28 07:46:23
0001 import pytest
0002 import acts
0003 import acts.examples
0004
0005 u = acts.UnitConstants
0006
0007 hepmc3 = pytest.importorskip("acts.examples.hepmc3")
0008
0009
0010
0011
0012
0013
0014
0015 class _Noop(acts.examples.IAlgorithm):
0016 """Minimal algorithm whose only purpose is to serve as a handle parent."""
0017
0018 def __init__(self):
0019 acts.examples.IAlgorithm.__init__(self, "_Noop", acts.logging.WARNING)
0020
0021 def execute(self, context):
0022 return acts.examples.ProcessCode.SUCCESS
0023
0024
0025 def _make_sequencer(events=3):
0026 """Sequencer with a particle-gun → HepMC3-converter chain."""
0027 rng = acts.examples.RandomNumbers(seed=42)
0028 s = acts.examples.Sequencer(events=events, numThreads=1, logLevel=acts.logging.INFO)
0029
0030 evGen = acts.examples.EventGenerator(
0031 level=acts.logging.WARNING,
0032 generators=[
0033 acts.examples.EventGenerator.Generator(
0034 multiplicity=acts.examples.FixedMultiplicityGenerator(n=1),
0035 vertex=acts.examples.GaussianVertexGenerator(
0036 stddev=acts.Vector4(0, 0, 0, 0),
0037 mean=acts.Vector4(0, 0, 0, 0),
0038 ),
0039 particles=acts.examples.ParametricParticleGenerator(
0040 p=(1 * u.GeV, 10 * u.GeV),
0041 eta=(-2, 2),
0042 numParticles=4,
0043 ),
0044 )
0045 ],
0046 outputEvent="particle_gun_event",
0047 randomNumbers=rng,
0048 )
0049 s.addReader(evGen)
0050
0051 converter = hepmc3.HepMC3InputConverter(
0052 level=acts.logging.WARNING,
0053 inputEvent="particle_gun_event",
0054 outputParticles="particles_generated",
0055 outputVertices="vertices_generated",
0056 mergePrimaries=False,
0057 )
0058 s.addAlgorithm(converter)
0059
0060 return s
0061
0062
0063
0064
0065
0066
0067
0068 def test_unregistered_type_raises():
0069 """Constructing a handle for a type without a whiteboard registration fails."""
0070 dummy = _Noop()
0071 with pytest.raises(TypeError, match="not registered"):
0072 acts.examples.ReadDataHandle(dummy, acts.examples.IAlgorithm, "test")
0073
0074
0075 def test_not_initialized_raises():
0076 """Calling a handle before initialize() raises RuntimeError."""
0077 dummy = _Noop()
0078 handle = acts.examples.ReadDataHandle(
0079 dummy, acts.examples.SimParticleContainer, "InputParticles"
0080 )
0081 wb = acts.examples.WhiteBoard(acts.logging.WARNING)
0082 with pytest.raises(RuntimeError, match="not initialized"):
0083 handle(wb)
0084
0085
0086 def test_wrong_key_raises():
0087 class WrongKeyInspector(acts.examples.IAlgorithm):
0088 def __init__(self):
0089 super().__init__(name="WrongKeyInspector", level=acts.logging.INFO)
0090 self.particles = acts.examples.ReadDataHandle(
0091 self, acts.examples.SimParticleContainer, "InputParticles"
0092 )
0093 self.particles.initialize("wrong_key")
0094
0095 def execute(self, context):
0096 return acts.examples.ProcessCode.SUCCESS
0097
0098 s = _make_sequencer(events=3)
0099 inspector = WrongKeyInspector()
0100 with pytest.raises(KeyError, match="does not exist"):
0101 wb = acts.examples.WhiteBoard(acts.logging.WARNING)
0102 inspector.particles(wb)
0103
0104 with acts.logging.ScopedFailureThreshold(acts.logging.FATAL), pytest.raises(
0105 RuntimeError,
0106 match="Sequence configuration error: Missing data handle for key 'wrong_key'",
0107 ):
0108 s.addAlgorithm(inspector)
0109
0110
0111
0112
0113
0114
0115
0116 def test_read_particles_via_handle():
0117 """A Python IAlgorithm reads SimParticleContainer from the whiteboard."""
0118
0119 class ParticleInspector(acts.examples.IAlgorithm):
0120 def __init__(self):
0121 super().__init__(name="ParticleInspector", level=acts.logging.INFO)
0122 self.particles = acts.examples.ReadDataHandle(
0123 self, acts.examples.SimParticleContainer, "InputParticles"
0124 )
0125 self.particles.initialize("particles_generated")
0126
0127 self.outputParticles = acts.examples.WriteDataHandle(
0128 self, acts.examples.SimParticleContainer, "OutputParticles"
0129 )
0130 self.outputParticles.initialize("output_particles")
0131
0132 self.seen_events = 0
0133
0134 def execute(self, context):
0135 particles = self.particles(context.eventStore)
0136 assert isinstance(particles, acts.examples.SimParticleContainer)
0137
0138 self.logger.info("Found {} particles", len(particles))
0139
0140 for particle in particles:
0141 print(particle)
0142
0143 assert not context.eventStore.exists("output_particles")
0144 newParticles = acts.examples.SimParticleContainer()
0145 self.outputParticles(context, newParticles)
0146 assert context.eventStore.exists("output_particles")
0147
0148 self.seen_events += 1
0149
0150 return acts.examples.ProcessCode.SUCCESS
0151
0152 s = _make_sequencer(events=3)
0153 inspector = ParticleInspector()
0154 s.addAlgorithm(inspector)
0155 s.run()
0156
0157 assert inspector.seen_events == 3