Source code for pyfeyn2.render.latex.feynmp

import uuid
from typing import List

from pylatex import Command
from pylatex.utils import NoEscape

from pyfeyn2 import feynmandiagram
from pyfeyn2.feynmandiagram import Connector
from pyfeyn2.render.latex.metapost import MetaPostRender

# converte FeynmanDiagram to tikz-feynman

type_map = {
    "line": ["plain"],
    "gluon": ["gluon"],
    "curly": ["curly"],
    "dbl_curly": ["dbl_curly"],
    "dashes": ["dashes"],
    "scalar": ["scalar"],
    "dashes_arrow": ["dashes_arrow"],
    "dbl_dashes": ["dbl_dashes"],
    "dbl_dashes_arrow": ["dbl_dashes_arrow"],
    "dots": ["dots"],
    "dots_arrow": ["dots_arrow"],
    "ghost": ["ghost"],
    "dbl_dots": ["dbl_dots"],
    "dbl_dots_arrow": ["dbl_dots_arrow"],
    "phantom": ["phantom"],
    "phantom_arrow": ["phantom_arrow"],
    "plain": ["plain"],
    "plain_arrow": ["plain_arrkddow"],
    "fermion": ["fermion"],
    "anti fermion": ["fermion"],
    "electron": ["electron"],
    "quark": ["quark"],
    "double": ["double"],
    "dbl_plain": ["dbl_plain"],
    "double_arrow": ["double_arrow"],
    "dbl_plain_arrow": ["dbl_plain_arrow"],
    "heavy": ["heavy"],
    "photon": ["photon"],
    "boson": ["boson"],
    "wiggly": ["wiggly"],
    "dbl_wiggly": ["dbl_wiggly"],
    "zigzag": ["zigzag"],
    "dbl_zigzag": ["dbl_zigzag"],
    "higgs": ["dashes"],
    "vector": ["boson"],
    "slepton": ["scalar"],
    "squark": ["scalar"],
    "gluino": ["gluon", "plain"],
    "gaugino": ["photon", "plain"],
}


[docs]def stylize_line(fd: feynmandiagram, c: Connector) -> str: cstyle = fd.get_style(c) style = "" if c.label is not None: style += f",label={c.label}" if cstyle.getProperty("tension") is not None: style += ",tension=" + str(cstyle.getProperty("tension").value) return style
[docs]def feynman_to_feynmp(fd): dire = fd.get_style(fd).getProperty("direction").value dirin = "" dirout = "" if dire == "left": dirin = "right" dirout = "left" elif dire == "right": dirin = "left" dirout = "right" elif dire == "up": dirin = "bottom" dirout = "top" elif dire == "down": dirin = "top" dirout = "bottom" else: raise Exception(f"Unknown direction: {dire}") # get random alphanumeric string result_str = uuid.uuid4().hex src = "\\begin{fmffile}{tmp-" + result_str + "}\n" src += "\\begin{fmfgraph*}(120,80)\n" incoming = [] outgoing = [] # Collect incoming and outgoing legs for l in fd.legs: if l.sense == "incoming": incoming += [l] elif l.sense == "outgoing": outgoing += [l] else: raise Exception("Unknown sense") if len(incoming) > 0: src += f"\t\t\\fmf{dirin}" + "{" for l in incoming: src += f"{l.id}," src = src[:-1] src += "}\n" if len(outgoing) > 0: src += f"\t\t\\fmf{dirout}" + "{" for l in outgoing: src += f"{l.id}," src = src[:-1] src += "}\n" def do_legs(src, legs, inward): for l in legs: lstyle = fd.get_style(l) if lstyle.getProperty("line") is not None: tttype = type_map[lstyle.getProperty("line").value] else: tttype = l.type # fallback to type if no line style is set style = stylize_line(fd, l) for ttype in tttype: lid = l.id ltarget = l.target if l.type.startswith("anti"): lid = l.target ltarget = l.id if inward: src += f"\t\t\\fmf{{{ttype}{style}}}{{{lid},{ltarget}}}\n" else: src += f"\t\t\\fmf{{{ttype}{style}}}{{{ltarget},{lid}}}\n" style = "" return src src = do_legs(src, incoming, True) src = do_legs(src, outgoing, False) for p in fd.propagators: pstyle = fd.get_style(p) if pstyle.getProperty("line") is not None: tttype = type_map[pstyle.getProperty("line").value] else: tttype = p.type # fallback to type if no line style is set style = stylize_line(fd, p) for ttype in tttype: psource = p.source ptarget = p.target if p.type.startswith("anti"): psource = p.target ptarget = p.source src += f"\t\t\\fmf{{{ttype}{style}}}{{{psource},{ptarget}}}\n" style = "" # Add labels for v in fd.vertices: if v.label is not None: src += f"\t\t\\fmflabel{{{v.label}}}{{{v.id}}}\n" src += "\\end{fmfgraph*}\n" src += "\\end{fmffile}\n" return src
[docs]class FeynmpRender(MetaPostRender):
[docs] def __init__( self, fd=None, documentclass="standalone", document_options=None, *args, **kwargs, ): if document_options is None: document_options = ["preview", "crop"] super().__init__( *args, fd=fd, documentclass=documentclass, document_options=document_options, **kwargs, ) self.preamble.append(Command("usepackage", NoEscape("feynmp-auto"))) if fd is not None: self.set_feynman_diagram(fd)
def set_feynman_diagram(self, fd): super().set_feynman_diagram(fd) self.set_src_diag(NoEscape(feynman_to_feynmp(fd))) @classmethod def valid_attributes(cls) -> List[str]: return super().valid_attributes() + ["label", "style"] @classmethod def valid_types(cls) -> List[str]: return super().valid_types() + list(type_map.keys()) @classmethod def valid_styles(cls) -> bool: return super().valid_styles() + [ "line", "direction", "tension", ]