From c9934e222f4255d33b23be6097dab8dbf283c417 Mon Sep 17 00:00:00 2001 From: Jacan Chaplais Date: Fri, 31 May 2024 12:48:35 +0100 Subject: [PATCH 1/3] classmethod - LHE event text to ParticleSet #177 --- graphicle/data.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/graphicle/data.py b/graphicle/data.py index 2cbc334..3fb1d29 100644 --- a/graphicle/data.py +++ b/graphicle/data.py @@ -2218,6 +2218,45 @@ def copy(self) -> "ParticleSet": """Copies the underlying data into a new ParticleSet instance.""" return _composite_copy(self) + @classmethod + def from_madgraph_table(cls, event_table: str) -> "ParticleSet": + schema = { + "pdg": 0, + "color": 4, + "anticolor": 5, + "x": 6, + "y": 7, + "z": 8, + "e": 9, + "helicity": 12, + } + records = cl.defaultdict(list) + lines = event_table.strip().split("\n")[1:] + num_pcls = len(lines) + + for line in lines: + particle_row = line.split() + for key, val in schema.items(): + records[key].append(float(particle_row[val])) + return cls( + pdg=PdgArray(records.pop("pdg")), + helicity=HelicityArray(records.pop("helicity")), + color=ColorArray( + np.fromiter( + zip(*op.itemgetter("color", "anticolor")(records)), + dtype=(np.int32, 2), + count=num_pcls, + ) + ), + pmu=MomentumArray( + np.fromiter( + zip(*op.itemgetter(*"xyze")(records)), + dtype=(np.float64, 4), + count=num_pcls, + ) + ), + ) + @classmethod def from_numpy( cls, From 4e992838cb588dce16981a810d6423a02062c48d Mon Sep 17 00:00:00 2001 From: Jacan Chaplais Date: Fri, 31 May 2024 15:47:24 +0100 Subject: [PATCH 2/3] initial attempt to interface LheEvent #177 --- graphicle/base.py | 34 ++++++++++++++++++++++++++++++++++ graphicle/data.py | 8 +++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/graphicle/base.py b/graphicle/base.py index 6e8db52..6164d38 100644 --- a/graphicle/base.py +++ b/graphicle/base.py @@ -45,6 +45,40 @@ DataType = ty.TypeVar("DataType") +class LheEventInterface(ty.Protocol): + """Interface for a generic Les Houches event. + + :group: base + + .. versionadded:: 0.4.0 + """ + + @property + def pdg(self) -> IntVector: + """PDG ID codes.""" + ... + + @property + def pmu(self) -> AnyVector: + """Four-momenta.""" + ... + + @property + def color(self) -> AnyVector: + """Color codes.""" + ... + + @property + def helicity(self) -> HalfIntVector: + """Spin / helicity.""" + ... + + @property + def status(self) -> HalfIntVector: + """Les Houches specific status codes.""" + ... + + class EventInterface(ty.Protocol): """Defines the interface for a generic event object expected by graphicle's routines. Attributes are stored as numpy arrays, with diff --git a/graphicle/data.py b/graphicle/data.py index 3fb1d29..95d3520 100644 --- a/graphicle/data.py +++ b/graphicle/data.py @@ -2219,7 +2219,13 @@ def copy(self) -> "ParticleSet": return _composite_copy(self) @classmethod - def from_madgraph_table(cls, event_table: str) -> "ParticleSet": + def from_lhe_event(cls, event: base.LheEventInterface) -> "ParticleSet": + prop_names = ("pdg", "pmu", "color", "helicity", "status") + data = cls(**{name: getattr(event, name) for name in prop_names}) + return data + + @classmethod + def _from_lhe_event(cls, event_table: str) -> "ParticleSet": schema = { "pdg": 0, "color": 4, From e59cbb4290da4d68607b26df751e5ae13ac0e368 Mon Sep 17 00:00:00 2001 From: Jacan Chaplais Date: Sun, 2 Jun 2024 12:40:22 +0100 Subject: [PATCH 3/3] added status code map for lhe classmethod #177 --- graphicle/base.py | 5 ---- graphicle/data.py | 67 ++++++++++++++++++----------------------------- 2 files changed, 26 insertions(+), 46 deletions(-) diff --git a/graphicle/base.py b/graphicle/base.py index 6164d38..8318413 100644 --- a/graphicle/base.py +++ b/graphicle/base.py @@ -55,27 +55,22 @@ class LheEventInterface(ty.Protocol): @property def pdg(self) -> IntVector: - """PDG ID codes.""" ... @property def pmu(self) -> AnyVector: - """Four-momenta.""" ... @property def color(self) -> AnyVector: - """Color codes.""" ... @property def helicity(self) -> HalfIntVector: - """Spin / helicity.""" ... @property def status(self) -> HalfIntVector: - """Les Houches specific status codes.""" ... diff --git a/graphicle/data.py b/graphicle/data.py index 80219b0..492a466 100644 --- a/graphicle/data.py +++ b/graphicle/data.py @@ -2298,48 +2298,33 @@ def copy(self) -> "ParticleSet": @classmethod def from_lhe_event(cls, event: base.LheEventInterface) -> "ParticleSet": - prop_names = ("pdg", "pmu", "color", "helicity", "status") - data = cls(**{name: getattr(event, name) for name in prop_names}) - return data + """Creates a ParticleSet instance directly from a data structure + holding LHE data. This is useful when you want to study the hard + process, without needing to shower or hadronize. - @classmethod - def _from_lhe_event(cls, event_table: str) -> "ParticleSet": - schema = { - "pdg": 0, - "color": 4, - "anticolor": 5, - "x": 6, - "y": 7, - "z": 8, - "e": 9, - "helicity": 12, - } - records = cl.defaultdict(list) - lines = event_table.strip().split("\n")[1:] - num_pcls = len(lines) - - for line in lines: - particle_row = line.split() - for key, val in schema.items(): - records[key].append(float(particle_row[val])) - return cls( - pdg=PdgArray(records.pop("pdg")), - helicity=HelicityArray(records.pop("helicity")), - color=ColorArray( - np.fromiter( - zip(*op.itemgetter("color", "anticolor")(records)), - dtype=(np.int32, 2), - count=num_pcls, - ) - ), - pmu=MomentumArray( - np.fromiter( - zip(*op.itemgetter(*"xyze")(records)), - dtype=(np.float64, 4), - count=num_pcls, - ) - ), - ) + .. versionadded:: 0.4.0 + + Parameters + ---------- + event : LheEventInterface + A data structure with attributes "pdg", "pmu", "color", + "helicity", and "status". These attributes provide access to + numpy arrays, which hold the underlying Les Houches event + data. + + Returns + ------- + ParticleSet + A composite object, wrapping the data provided in Graphicle + objects, and providing a unified interface to them. + """ + props = ("pdg", "pmu", "color", "helicity", "status") + pcls = cls.from_numpy(**{name: getattr(event, name) for name in props}) + pcls.final = MaskArray(np.zeros(len(pcls), dtype=np.bool_)) + status_map = {-1: -21, 1: -23, -2: -22, 2: -22, 3: -22, -9: -12} + for old_code, new_code in status_map.items(): + pcls.status.data[pcls.status.data == old_code] = new_code + return pcls @classmethod def from_numpy(