Source code for decaylanguage.modeling.decay
# Copyright (c) 2018-2024, Eduardo Rodrigues and Henry Schreiner.
#
# Distributed under the 3-clause BSD license, see accompanying file LICENSE
# or https://github.com/scikit-hep/decaylanguage for details.
"""
A general base class representing decays.
"""
from __future__ import annotations
import warnings
from itertools import product
import attr
from ..utils import iter_flatten
try:
import graphviz
except ImportError:
graphviz = None
warnings.warn(
"Graphviz is not installed. Line display not available.", stacklevel=1
)
[docs]
@attr.s(slots=True)
class ModelDecay:
"""
This describes a decay very generally, with search and print features.
Subclassed for further usage.
"""
particle = attr.ib()
daughters = attr.ib([], converter=lambda x: x if x else [])
name = attr.ib(None)
def __attrs_post_init__(self):
if self.name is None:
self.name = self.particle.name
def is_vertex(self):
return len(self) == 2
def is_strong(self):
if not self.is_vertex():
return None
return set(self.particle.quarks) == set(self[0].particle.quarks).union(
set(self[1].particle.quarks)
)
def __len__(self):
return len(self.daughters)
def __getitem__(self, item):
return self.daughters[item]
def _get_html(self):
"""
Get the html dot representation of this node only. Override in subclasses.
"""
return self.particle.html_name
def _add_nodes(self, drawing):
name = self._get_html()
drawing.node(str(id(self)), "<" + name + ">")
for p in self.daughters:
drawing.edge(str(id(self)), str(id(p)))
p._add_nodes(drawing)
@property
def vertexes(self):
verts = []
for d in self.daughters:
if d.is_vertex():
verts.append(d)
verts += d.vertexes
return verts
@property
def structure(self):
"""
The structure of the decay chain, simplified to only final state particles
"""
if self.daughters:
return [d.structure for d in self.daughters]
return self.particle
[docs]
def list_structure(self, final_states):
"""
The structure in the form [(0,1,2,3)], where the dual-list is used
for permutations for bose symmatrization.
So for final_states=[a,b,c,c], [a,c,[c,b]] would be:
[(0,2,3,1),(0,3,2,1)]
"""
structure = list(iter_flatten(self.structure))
if set(structure) - set(final_states):
raise RuntimeError(
"The final states must encompass all particles in final states!"
)
possibilities = [
[i for i, v in enumerate(final_states) if v == name] for name in structure
]
return [a for a in product(*possibilities) if len(set(a)) == len(a)]
def __str__(self):
name = str(self.particle)
if self.daughters:
name += "{" + ",".join(map(str, self.daughters)) + "}"
return name
if graphviz:
def _make_graphviz(self):
d = graphviz.Digraph()
d.attr(labelloc="t", label=str(self))
self._add_nodes(d)
return d
def _repr_mimebundle_(self, include=None, exclude=None, **kwargs):
try:
return self._make_graphviz()._repr_mimebundle_(
include=include, exclude=exclude, **kwargs
)
except AttributeError:
return {
"image/svg+xml": self._make_graphviz()._repr_svg_()
} # for graphviz < 0.19