1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """This files contains class for creating files or object representing a
17 diagram or a set of diagrams.
18
19 class structure:
20
21 DrawDiagram:
22 In principle ALL routines representing a diagram in Any format SHOULD derive
23 from this class. This is a (nearly empty) frameworks to draw a diagram
24 in any type format.
25
26 This frameworks defines in particular
27 - function to convert the input diagram in the correct object.
28 [convert_diagram]
29 - main loop to draw a diagram in a line-by-line method
30 [draw - draw_diagram]
31
32 DrawDiagramEPS:
33 This contains all the routines to represent one diagram in Encapsuled
34 PostScript (EPS)
35
36 DrawDiagramsEPS:
37 This contains all the routines to represent a set of diagrams in Encapsuled
38 PostScript (EPS)."""
39
40 from __future__ import division
41
42 import os
43 import math
44 import madgraph.core.drawing as draw
45 import madgraph.core.base_objects as base_objects
46
47 _file_path = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0] + '/'
48
49
50
51
53 """Class to write a EPS file containing the asked diagram
54 This class follows the DrawDiagram Frameworks.
55
56 The main routine to draw a diagram is 'draw' which call
57 1) initialize: setup things for the diagram (usually open a file)
58 2) convert_diagram : Update the diagram in the correct format if needed
59 3) draw_diagram : Perform diagram dependent operation
60 4) conclude : finish the operation.
61 """
62
63
64 width = 450
65 height = 450
66 npage = 1
67
68
69
70 x_min = 150
71 y_min = 450
72 x_max = 450
73 y_max = 750
74
75 blob_size = 1.5
76
78 """Operation done before starting to create diagram specific EPS content
79 First open the file in write mode then write in it the header and the
80 library of particle type."""
81
82
83 super(EpsDiagramDrawer, self).initialize()
84
85
86 text = "%!PS-Adobe-2.0\n"
87 text += "%%" + "BoundingBox: -20 -20 %s %s \n" % \
88 (self.width, self.height)
89 text += "%%DocumentFonts: Helvetica\n"
90 text += "%%" + "Pages: %s \n" % self.npage
91 self.file.writelines(text)
92
93
94 self.file.writelines(open(os.path.join(_file_path, \
95 'iolibs/template_files/drawing_eps_header.inc')).read())
96
97
99 """Operation to perform when all code related to a specific diagram are
100 finish. Operation :
101 - Add the 'end of page' code
102 - write unwritten text and close the file. [DrawDiagram.conclude]"""
103
104
105 self.text = 'showpage\n'
106 self.text += '%%trailer\n'
107
108
109 super(EpsDiagramDrawer, self).conclude()
110
111
113 """All coordinates belongs to [0,1]. So that in order to have a visible
114 graph we need to re-scale the graph. This method distort the square in
115 a oblong. Deformation are linear."""
116
117
118
119 x = self.x_min + (self.x_max - self.x_min) * x
120 y = self.y_min + (self.y_max - self.y_min) * y
121
122 return x, y
123
124
137
138 - def draw_vertex(self, vertex, bypass = ['QED','QCD'] ):
139 """Add blob in case on non QED-QCD information"""
140
141 interaction = self.model.get_interaction(vertex.id)
142 if interaction:
143 order = interaction.get('orders')
144 order = [key for key in order.keys() if order[key] and \
145 key not in bypass]
146
147 if order:
148 x1, y1 = self.rescale(vertex.pos_x, vertex.pos_y)
149 self.text += " %s %s %s 1.0 Fblob \n" % (x1, y1, self.blob_size)
150
151
152
154 """ADD the EPS code for this fermion line."""
155
156
157 self.text += self.line_format(line.start.pos_x, line.start.pos_y,
158 line.end.pos_x, line.end.pos_y, 'Ffermion')
159
160
162 """ADD the EPS code for this Higgs line."""
163
164
165 self.text += self.line_format(line.start.pos_x, line.start.pos_y,
166 line.end.pos_x, line.end.pos_y, 'Fhiggs')
167
168
170 """ADD the EPS code for this photon line."""
171
172
173 self.text += self.line_format(line.start.pos_x, line.start.pos_y,
174 line.end.pos_x, line.end.pos_y, '%d Fphoton%s' % (opt,type))
175
176
178 """ADD the EPS code for this gluon line."""
179
180
181
182
183 if (line.start.pos_x < line.end.pos_x) or \
184 (line.start.pos_x == line.end.pos_x and \
185 line.start.pos_y > line.end.pos_y):
186 self.text += self.line_format(line.start.pos_x,
187 line.start.pos_y, line.end.pos_x,
188 line.end.pos_y, '0 Fgluon%s' % type)
189 else:
190 self.text += self.line_format(line.end.pos_x,
191 line.end.pos_y, line.start.pos_x,
192 line.start.pos_y, '0 Fgluon%s' % type)
193
199
204
206 """ADD the EPS code for this neutralino line."""
207
208
209 length = math.sqrt((line.end.pos_y - line.start.pos_y)**2 + (line.end.pos_x - line.start.pos_x) **2)
210 c1 = (line.end.pos_x - line.start.pos_x)/length
211 c2 = (line.end.pos_y - line.start.pos_y)/length
212
213 gap = 0.013
214 start2_x = line.start.pos_x + gap * c1
215 start2_y = line.start.pos_y + gap * c2
216 stop1_x = line.end.pos_x - gap * c1
217 stop1_y = line.end.pos_y - gap * c2
218
219
220 self.text += self.line_format(line.start.pos_x, line.start.pos_y,
221 stop1_x, stop1_y, '0 Fphoton%s' % (type))
222
223 self.text += self.line_format(start2_x, start2_y,
224 line.end.pos_x, line.end.pos_y, '0 Fphoton%s' % (type))
225
226
228 """ADD the comment 'diagram [number]' just below the diagram."""
229
230
231 x = 0.2
232 y = -0.17
233
234 x, y = self.rescale(x, y)
235
236 self.text += ' %s %s moveto \n' % (x, y)
237 self.text += '( diagram %s ) show\n' % (number + 1)
238
239
240
241 mystr = " (%s)" % ", ".join(["%s=%d" % (key, self.diagram.diagram['orders'][key]) \
242 for key in sorted(self.diagram.diagram['orders'].keys()) \
243 if key != 'WEIGHTED'])
244
245 x = 0.6
246 y = -0.17
247 x, y = self.rescale(x, y)
248
249 self.text += ' %s %s moveto \n' % (x, y)
250 self.text += '%s show\n' % (mystr)
251
252
253
255 """Write in the EPS figure the MadGraph number associate to the line.
256 Note that this routine is called only for external particle."""
257
258
259 if line.start.is_external():
260 vertex = line.start
261 else:
262 vertex = line.end
263
264
265 x = vertex.pos_x
266 y = vertex.pos_y
267
268
269 if x == 0:
270 x = -0.04
271 else:
272 x += 0.04
273 y = line._has_ordinate(x)
274
275
276 x, y = self.rescale(x, y)
277
278 self.text += ' %s %s moveto \n' % (x, y)
279 self.text += '(%s) show\n' % (number)
280
282 """ADD the EPS code associate to the name of the particle. Place it near
283 to the center of the line.
284 """
285
286
287 x1, y1 = line.start.pos_x, line.start.pos_y
288 x2, y2 = line.end.pos_x, line.end.pos_y
289
290 d = line.get_length()
291 if d == 0:
292 raise self.DrawDiagramError('Line can not have 0 length')
293
294
295
296 if abs(x1 - x2) < 1e-3:
297 dx = 0.015
298 dy = -0.01
299 elif abs(y1 - y2) < 1e-3:
300 dx = -0.01
301 dy = 0.025
302 elif ((x1 < x2) == (y1 < y2)):
303 dx = -0.03 * len(name)
304 dy = 0.02 * len(name)
305 else:
306 dx = 0.01
307 dy = 0.02
308
309
310 x_pos = (x1 + x2) / 2 + dx
311 y_pos = (y1 + y2) / 2 + dy
312
313
314 x_pos, y_pos = self.rescale(x_pos, y_pos)
315
316 self.text += ' %s %s moveto \n' % (x_pos, y_pos)
317 self.text += '(' + name + ') show\n'
318
319
320
321
322
324 """Class to write a EPS file containing the asked set of diagram
325 This class follows the DrawDiagram Frameworks.
326
327 The main routine to draw a diagram is 'draw' which call
328 1) initialize: setup things for the diagram (usually open a file)
329 2) convert_diagram : Update the diagram in the correct format if needed
330 3) draw_diagram : Perform diagram dependent operation
331 4) conclude : finish the operation.
332 """
333
334
335
336
337
338 x_min = 75
339 x_size = 200
340 y_min = 560
341 y_size = 150
342
343 x_gap = 75
344 y_gap = 70
345
346
347 font=9
348
349
350 nb_line = 3
351 nb_col = 2
352
353 blob_size = 1.5
354
355 lower_scale = 5
356 second_scale ={'x_min': 40, 'x_size':150,'y_min':620,'y_size':100,
357 'x_gap':42,'y_gap':30,'font':6,'nb_line':5,'nb_col':3,
358 'blob_size':0.9}
359
360 - def __init__(self, diagramlist=None, filename='diagram.eps', \
361 model=None, amplitude=None, legend=''):
362 """Define basic variable and store some global information
363 all argument are optional
364 diagramlist : are the list of object to draw. item should inherit
365 from either base_objects.Diagram or drawing_lib.FeynmanDiagram
366 filename: filename of the file to write
367 model: model associate to the diagram. In principle use only if diagram
368 inherit from base_objects.Diagram
369 amplitude: amplitude associate to the diagram. NOT USE for the moment.
370 In future you could pass the amplitude associate to the object in
371 order to adjust fermion flow in case of Majorana fermion."""
372
373
374 super(MultiEpsDiagramDrawer, self).__init__(None, filename , model, \
375 amplitude)
376 self.legend = legend
377
378 self.block_nb = 0
379 self.curr_page = 0
380 self.block_in_page = 0
381
382 self.npage = 1
383
384 limit = self.lower_scale * self.nb_col * self.nb_line
385 if len(diagramlist) < limit:
386 self.npage += len(diagramlist) // (self.nb_col * self.nb_line)
387 else:
388 add = (len(diagramlist) - self.lower_scale) // \
389 (self.second_scale['nb_col'] * self.second_scale['nb_line'])
390 self.npage += self.lower_scale + add -2
391 if diagramlist:
392
393 assert(isinstance(diagramlist, base_objects.DiagramList))
394 self.diagramlist = diagramlist
395 else:
396 self.diagramlist = None
397
398
400 """All coordinates belongs to [0,1]. So that in order to have a visible
401 graph we need to re-scale the graph. This method distort the square in
402 a oblong. Deformation are linear."""
403
404
405 block_pos = self.block_in_page
406 line_pos = block_pos // self.nb_col
407 col_pos = block_pos % self.nb_col
408
409
410
411 x_min = self.x_min + (self.x_size + self.x_gap) * col_pos
412 x_max = self.x_min + self.x_gap * (col_pos) + self.x_size * \
413 (col_pos + 1)
414 y_min = self.y_min - (self.y_size + self.y_gap) * line_pos
415 y_max = self.y_min - self.y_gap * (line_pos) - self.y_size * \
416 (line_pos - 1)
417
418
419 x = x_min + (x_max - x_min) * x
420 y = y_min + (y_max - y_min) * y
421
422 return x, y
423
425 """Creates the representation in EPS format associate to a specific
426 diagram."""
427
428
429 super(MultiEpsDiagramDrawer, self).draw_diagram(diagram, self.block_nb)
430
431
432 self.block_nb += 1
433 self.block_in_page +=1
434
435
436 - def draw(self, diagramlist='', opt=None):
437 """Creates the representation in EPS format associate to a specific
438 diagram. 'opt' keeps track of possible option of drawing. Those option
439 are used if we need to convert diagram to Drawing Object.
440 opt is an DrawOption object containing all the possible option on how
441 draw a diagram."""
442
443 if diagramlist == '':
444 diagramlist = self.diagramlist
445
446
447
448 self.initialize()
449 self.text += '/Helvetica findfont %s scalefont setfont\n' % self.font
450 self.text += ' 50 770 moveto\n'
451 self.text += ' (%s) show\n' % self.legend
452 self.text += ' 525 770 moveto\n'
453 self.text += ' (page %s/%s) show\n' % (self.curr_page + 1, self.npage)
454 self.text += ' 260 50 moveto\n'
455 self.text += ' (Diagrams made by MadGraph5) show\n'
456
457 for diagram in diagramlist:
458
459 diagram = self.convert_diagram(diagram, self.model, self.amplitude, opt)
460
461 self.draw_diagram(diagram)
462
463
464 if self.block_in_page % (self.nb_col * self.nb_line) == 0:
465
466 self.pass_to_next_page()
467
468
469 self.conclude()
470
472 """Insert text in order to pass to next EPS page."""
473
474 self.curr_page += 1
475 self.block_in_page = 0
476 if self.curr_page == self.lower_scale:
477 for key, value in self.second_scale.items():
478 setattr(self, key, value)
479
480
481 self.text += 'showpage\n'
482 self.text += '%%' + 'Page: %s %s \n' % (self.curr_page, self.curr_page)
483 self.text += '%%PageBoundingBox:-20 -20 600 800\n'
484 self.text += '%%PageFonts: Helvetica\n'
485 self.text += ' 50 770 moveto\n'
486 self.text += ' (%s) show\n' % self.legend
487 self.text += ' 525 770 moveto\n'
488 self.text += ' (page %s/%s) show\n' % (self.curr_page + 1, self.npage)
489 self.text += ' 260 40 moveto\n'
490 self.text += ' (Diagrams made by MadGraph5) show\n'
491