forked from hepcpt/qgraf-xml-drawer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
qgraf_interpreter.py
101 lines (86 loc) · 4.52 KB
/
qgraf_interpreter.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
from xml.etree.ElementTree import *
from xml.etree.ElementInclude import *
import re
def extra_translate(str):
rep = {"BACKSLASH": "\\", "CARET": "^", "MINUS": "-", "PLUS": "+", "CURLYL": "{", "CURLYR": "}" }
rep = dict((re.escape(k), v) for k, v in rep.items())
pattern = re.compile("|".join(rep.keys()))
return "$" + pattern.sub(lambda m: rep[re.escape(m.group(0))], str) + "$"
#From Andrew Clark at StackOverflow: https://stackoverflow.com/a/6117124
class qgraf_border:
def __init__(self, label, momentum):
self.label = label
self.momentum = momentum
class qgraf_line:
def __init__(self, particle, antiparticle, momentum, sign, previous, next):
self.particle = particle
self.antiparticle = antiparticle
self.momentum = momentum
self.sign = sign
self.base = previous
self.tip = next
class qgraf_info:
def __init__(self, diagram):
self.id = int(diagram.find("id").text)
self.sign = diagram.find("signsym").text[0]
self.incoming = {}
self.outgoing = {}
#Dictionaries for easier access.
#Might not be the most performant option,
#but seems to be the simplest.
for leg in list(diagram.find("legs")):
if leg.find("status").text == "in":
self.incoming[int(leg.find("id").text)] =qgraf_border(leg.find("field").text, leg.find("momentum").text)
elif leg.find("status").text == "out":
self.outgoing[int(leg.find("id").text)] = qgraf_border(leg.find("field").text, leg.find("momentum").text)
else:
print("Error: invalid leg status \'" + leg.find("status").text + "\' in leg " + leg.find("id").text)
self.propag = {}
for prop in list(diagram.find("propagators")):
self.propag[int(prop.find("begin").text)] = qgraf_line(prop.find("field").text,prop.find("dual_field").text, prop.find("momentum").text, prop.find("sign").text, int(prop.find("begin").text), int(prop.find("end").text))
self.vertex = {}
for vert in list(diagram.find("vertices")):
for n in list(vert.find("fields").text.split(",")):
self.vertex[int(n)] = int(vert.find("id").text)
def draw_incoming(self, file, dictionary):
for k,v in self.incoming.items():
file.write("\n in{} [particle={}] -- [ {} ] v{},".format(abs(k),extra_translate(v.label),dictionary[v.label],self.vertex[k]))
#Since incoming particles are -1, -3, -5, -7 (...),
#we integer-divide |index| by 2 so it becomes 0, 1, 2, 3 (...)
#and add 1 for consistency with the outgoing
def draw_vertices(self, file, dictionary):
for k,v in self.vertex.items():
if k < 0: #incoming or outgoing - handled elsewhere
continue
elif k not in self.propag: #is an ending point - will be covered by some other key-value pair
continue
else: #is the start of a(n internal) propagator
p = self.propag[k]
file.write("\n v{} -- [ {} , edge label = {} ] v{},".format(self.vertex[p.tip],
dictionary[p.particle],
extra_translate(p.particle),
v))
def draw_outgoing(self, file, dictionary):
for k,v in self.outgoing.items():
label = dictionary[v.label]
if label.startswith("photon") or label.startswith("gluon"):
pass
elif label.startswith("anti"):
label = label[4:]
else:
label = "anti " + label
file.write("\n out{} [particle={}] -- [ {} ] v{} ,".format(abs(k),extra_translate(v.label), label,self.vertex[k]))
#Since outgoing particles are -2, -4, -6, -8 (...),
#we just integer-divide |index| by 2 to get 1, 2, 3 ,4 (...)
def draw(self, file, dictionary):
file.write("\n {\Large " + self.sign + " } \\feynmandiagram[baseline=(current bounding box.center),medium, horizontal =in1 to out" + str(2*len(self.outgoing)) + "]{")
#This ensures in and out are aligned (hopefully)
#No worries because there should be at least one incoming and one outcoming particle
self.draw_incoming(file, dictionary)
self.draw_vertices(file, dictionary)
self.draw_outgoing(file, dictionary)
for i in range(1, len(self.incoming)):
file.write("\n in{} -- [draw=none] in{} ,".format(2*i -1, 2*i + 1))
for i in range(1, len(self.outgoing)):
file.write("\n out{} -- [draw=none] out{} ,".format(2*i, 2*i + 2))
file.write("\n};")