1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """Methods and classes to export matrix elements to v4 format."""
16
17 from __future__ import absolute_import
18 import copy
19 import fractions
20 import glob
21 import logging
22 import os
23 import stat
24 import sys
25 import re
26 import shutil
27 import subprocess
28 import itertools
29 import time
30 import datetime
31
32
33 import aloha
34
35 import madgraph.core.base_objects as base_objects
36 import madgraph.core.color_algebra as color
37 import madgraph.core.helas_objects as helas_objects
38 import madgraph.loop.loop_helas_objects as loop_helas_objects
39 import madgraph.iolibs.drawing_eps as draw
40 import madgraph.iolibs.files as files
41 import madgraph.iolibs.group_subprocs as group_subprocs
42 import madgraph.various.banner as banner_mod
43 import madgraph.various.misc as misc
44 import madgraph.various.q_polynomial as q_polynomial
45 import madgraph.iolibs.file_writers as writers
46 import madgraph.iolibs.gen_infohtml as gen_infohtml
47 import madgraph.iolibs.template_files as template_files
48 import madgraph.iolibs.ufo_expression_parsers as parsers
49 import madgraph.iolibs.export_v4 as export_v4
50 import madgraph.various.diagram_symmetry as diagram_symmetry
51 import madgraph.various.process_checks as process_checks
52 import madgraph.various.progressbar as pbar
53 import madgraph.various.q_polynomial as q_polynomial
54 import madgraph.core.color_amp as color_amp
55 import madgraph.iolibs.helas_call_writers as helas_call_writers
56 import models.check_param_card as check_param_card
57 from madgraph.loop.loop_base_objects import LoopDiagram
58 from madgraph.loop.MadLoopBannerStyles import MadLoopBannerStyles
59 from six.moves import range
60 from six.moves import zip
61
62
63
64 pjoin = os.path.join
65
66 import aloha.create_aloha as create_aloha
67 import models.write_param_card as param_writer
68 from madgraph import MadGraph5Error, MG5DIR, InvalidCmd
69 from madgraph.iolibs.files import cp, ln, mv
70 pjoin = os.path.join
71 _file_path = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0] + '/'
72 logger = logging.getLogger('madgraph.loop_exporter')
73
74
75
76
78 """ Class to define general helper functions to the different
79 loop fortran exporters (ME, SA, MEGroup, etc..) which will inherit both
80 from this class AND from the corresponding ProcessExporterFortran(ME,SA,...).
81 It plays the same role as ProcessExporterFrotran and simply defines here
82 loop-specific helpers functions necessary for all loop exporters.
83 Notice that we do not have LoopExporterFortran inheriting from
84 ProcessExporterFortran but give access to arguments like dir_path and
85 clean using options. This avoids method resolution object ambiguity"""
86
87 default_opt = dict(export_v4.ProcessExporterFortran.default_opt)
88 default_opt.update({'clean': False, 'complex_mass':False,
89 'export_format':'madloop', 'mp':True,
90 'loop_dir':'', 'cuttools_dir':'',
91 'fortran_compiler':'gfortran',
92 'SubProc_prefix': 'P',
93 'output_dependencies': 'external',
94 'compute_color_flows': False,
95 'mode':''})
96
97 include_names = {'ninja' : 'mninja.mod',
98 'golem' : 'generic_function_1p.mod',
99 'samurai':'msamurai.mod',
100 'collier': 'collier.mod'}
101
102 - def __init__(self, dir_path = "", opt=None):
103 """Initiate the LoopExporterFortran with directory information on where
104 to find all the loop-related source files, like CutTools"""
105
106
107 self.opt = dict(self.default_opt)
108 if opt:
109 self.opt.update(opt)
110
111 self.SubProc_prefix = self.opt['SubProc_prefix']
112 self.loop_dir = self.opt['loop_dir']
113 self.cuttools_dir = self.opt['cuttools_dir']
114 self.fortran_compiler = self.opt['fortran_compiler']
115 self.dependencies = self.opt['output_dependencies']
116 self.compute_color_flows = self.opt['compute_color_flows']
117
118 super(LoopExporterFortran,self).__init__(dir_path, self.opt)
119
120
194
196 """ Caches the aloha model created here as an attribute of the loop
197 exporter so that it can later be used in the LoopHelasMatrixElement
198 in the function compute_all_analytic_information for recycling aloha
199 computations across different LoopHelasMatrixElements steered by the
200 same loop exporter.
201 """
202 if not hasattr(self, 'aloha_model'):
203 self.aloha_model = create_aloha.AbstractALOHAModel(model.get('modelpath'))
204
205 missing_lor = []
206 for lor in model.get('lorentz'):
207 if not hasattr(self.aloha_model.model.lorentz, lor.name):
208 missing_lor.append(lor)
209 if missing_lor:
210 logger.debug("adding in aloha model %s lorentz struct" % len(missing_lor))
211 self.aloha_model.add_Lorentz_object(missing_lor)
212
213 return self.aloha_model
214
215
216
217
229
230
231
232
235
236 """Class to take care of exporting a set of loop matrix elements in the
237 Fortran format."""
238
239 template_dir=os.path.join(_file_path,'iolibs/template_files/loop')
240 madloop_makefile_name = 'makefile'
241
242 MadLoop_banner = MadLoopBannerStyles.get_MadLoop_Banner(
243 style='classic2', color='green',
244 top_frame_char = '=', bottom_frame_char = '=',
245 left_frame_char = '{',right_frame_char = '}',
246 print_frame=True, side_margin = 7, up_margin = 1)
247
252
259
260 - def finalize(self, matrix_element, cmdhistory, MG5options, outputflag):
261 """create the global information for loops"""
262
263 super(LoopProcessExporterFortranSA,self).finalize(matrix_element,
264 cmdhistory, MG5options, outputflag)
265
266
267 MLCard = banner_mod.MadLoopParam(pjoin(self.dir_path, 'Cards', 'MadLoopParams.dat'))
268
269
270 if self.has_loop_induced:
271 MLCard['MLReductionLib'] = "7|6|1"
272
273
274
275
276
277 MLCard['COLLIERComputeUVpoles'] = False
278 MLCard['COLLIERComputeIRpoles'] = False
279
280 MLCard.write(pjoin(self.dir_path, 'Cards', 'MadLoopParams_default.dat'))
281 MLCard.write(pjoin(self.dir_path, 'Cards', 'MadLoopParams.dat'))
282
285
287 """ Write the general check_sa.py in SubProcesses that calls all processes successively."""
288
289
290 file = open(os.path.join(self.template_dir,\
291 'check_sa_all.py.inc')).read()
292 open(output_path,'w').writelines(file)
293
294 os.chmod(output_path, os.stat(output_path).st_mode | stat.S_IEXEC)
295
296
298 """write a function to call the correct matrix element"""
299
300 template = """
301 %(python_information)s
302
303 SUBROUTINE INITIALISE(PATH)
304 C ROUTINE FOR F2PY to read the benchmark point.
305 IMPLICIT NONE
306 CHARACTER*512 PATH
307 CF2PY INTENT(IN) :: PATH
308 CALL SETPARA(PATH) !first call to setup the paramaters
309 RETURN
310 END
311
312 subroutine CHANGE_PARA(name, value)
313 implicit none
314 CF2PY intent(in) :: name
315 CF2PY intent(in) :: value
316
317 character*512 name
318 double precision value
319
320 include '../Source/MODEL/input.inc'
321 include '../Source/MODEL/coupl.inc'
322 include '../Source/MODEL/mp_coupl.inc'
323 include '../Source/MODEL/mp_input.inc'
324
325 SELECT CASE (name)
326 %(parameter_setup)s
327 CASE DEFAULT
328 write(*,*) 'no parameter matching', name
329 END SELECT
330
331 return
332 end
333
334 subroutine update_all_coup()
335 implicit none
336 call coup()
337 call printout()
338 return
339 end
340
341
342 SUBROUTINE SET_MADLOOP_PATH(PATH)
343 C Routine to set the path of the folder 'MadLoop5_resources' to MadLoop
344 CHARACTER(512) PATH
345 CF2PY intent(in)::path
346 CALL SETMADLOOPPATH(PATH)
347 END
348
349 subroutine smatrixhel(pdgs, procid, npdg, p, ALPHAS, SCALES2, nhel, ANS, RETURNCODE)
350 IMPLICIT NONE
351
352 CF2PY double precision, intent(in), dimension(0:3,npdg) :: p
353 CF2PY integer, intent(in), dimension(npdg) :: pdgs
354 CF2PY integer, intent(in):: procid
355 CF2PY integer, intent(in) :: npdg
356 CF2PY double precision, intent(out) :: ANS
357 CF2PY integer, intent(out) :: RETURNCODE
358 CF2PY double precision, intent(in) :: ALPHAS
359 CF2PY double precision, intent(in) :: SCALES2
360
361 integer pdgs(*)
362 integer npdg, nhel, RETURNCODE, procid
363 double precision p(*)
364 double precision ANS, ALPHAS, PI,SCALES2
365 1 continue
366 %(smatrixhel)s
367
368 return
369 end
370
371 subroutine get_pdg_order(OUT, ALLPROC)
372 IMPLICIT NONE
373 CF2PY INTEGER, intent(out) :: OUT(%(nb_me)i,%(maxpart)i)
374 CF2PY INTEGER, intent(out) :: ALLPROC(%(nb_me)i)
375 INTEGER OUT(%(nb_me)i,%(maxpart)i), PDGS(%(nb_me)i,%(maxpart)i)
376 INTEGER ALLPROC(%(nb_me)i),PIDs(%(nb_me)i)
377 DATA PDGS/ %(pdgs)s /
378 DATA PIDS/ %(pids)s /
379 OUT=PDGS
380 ALLPROC = PIDS
381 RETURN
382 END
383
384 subroutine get_prefix(PREFIX)
385 IMPLICIT NONE
386 CF2PY CHARACTER*20, intent(out) :: PREFIX(%(nb_me)i)
387 character*20 PREFIX(%(nb_me)i),PREF(%(nb_me)i)
388 DATA PREF / '%(prefix)s'/
389 PREFIX = PREF
390 RETURN
391 END
392
393 """
394
395 allids = list(self.prefix_info.keys())
396 allprefix = [self.prefix_info[key][0] for key in allids]
397 min_nexternal = min([len(ids[0]) for ids in allids])
398 max_nexternal = max([len(ids[0]) for ids in allids])
399
400 info = []
401 for (key,pid), (prefix, tag) in self.prefix_info.items():
402 info.append('#PY %s : %s # %s %s' % (tag, key, prefix, pid))
403
404
405 text = []
406 for n_ext in range(min_nexternal, max_nexternal+1):
407 current_id = [ids[0] for ids in allids if len(ids[0])==n_ext]
408 current_pid = [ids[1] for ids in allids if len(ids[0])==n_ext]
409 if not current_id:
410 continue
411 if min_nexternal != max_nexternal:
412 if n_ext == min_nexternal:
413 text.append(' if (npdg.eq.%i)then' % n_ext)
414 else:
415 text.append(' else if (npdg.eq.%i)then' % n_ext)
416 for ii,pdgs in enumerate(current_id):
417 pid = current_pid[ii]
418 condition = '.and.'.join(['%i.eq.pdgs(%i)' %(pdg, i+1) for i, pdg in enumerate(pdgs)])
419 if ii==0:
420 text.append( ' if(%s.and.(procid.le.0.or.procid.eq.%d)) then ! %i' % (condition, pid, len(pdgs)))
421 else:
422 text.append( ' else if(%s.and.(procid.le.0.or.procid.eq.%d)) then ! %i' % (condition,pid,len(pdgs)))
423 text.append(' call %sget_me(p, ALPHAS, DSQRT(SCALES2), NHEL, ANS, RETURNCODE)' % self.prefix_info[(pdgs,pid)][0])
424 text.append( ' else if(procid.gt.0) then !')
425 text.append( ' procid = -1' )
426 text.append( ' goto 1' )
427
428 text.append(' endif')
429
430 if min_nexternal != max_nexternal:
431 text.append('endif')
432
433 params = self.get_model_parameter(self.model)
434 parameter_setup =[]
435 for key, var in params.items():
436 parameter_setup.append(' CASE ("%s")\n %s = value\n MP__%s = value'
437 % (key, var, var))
438
439
440
441 formatting = {'python_information':'\n'.join(info),
442 'smatrixhel': '\n'.join(text),
443 'maxpart': max_nexternal,
444 'nb_me': len(allids),
445 'pdgs': ','.join([str(pdg[i]) if i<len(pdg) else '0'
446 for i in range(max_nexternal) \
447 for (pdg,pid) in allids]),
448 'prefix':'\',\''.join(allprefix),
449 'parameter_setup': '\n'.join(parameter_setup),
450 'pids': ','.join(str(pid) for (pdg,pid) in allids),
451 }
452
453
454 text = template % formatting
455 fsock = writers.FortranWriter(pjoin(self.dir_path, 'SubProcesses', 'all_matrix.f'),'w')
456 fsock.writelines(text)
457 fsock.close()
458
459
460
462 """ Perform additional actions specific for this class when setting
463 up the template with the copy_template function."""
464
465
466 cpfiles= ["Cards/MadLoopParams.dat",
467 "SubProcesses/MadLoopParamReader.f",
468 "SubProcesses/MadLoopParams.inc"]
469 if copy_Source_makefile:
470 cpfiles.append("Source/makefile")
471
472 for file in cpfiles:
473 shutil.copy(os.path.join(self.loop_dir,'StandAlone/', file),
474 os.path.join(self.dir_path, file))
475
476 cp(pjoin(self.loop_dir,'StandAlone/Cards/MadLoopParams.dat'),
477 pjoin(self.dir_path, 'Cards/MadLoopParams_default.dat'))
478
479 ln(pjoin(self.dir_path, 'Cards','MadLoopParams.dat'), pjoin(self.dir_path,'SubProcesses'))
480
481
482 shutil.copy(pjoin(self.loop_dir,'StandAlone','SubProcesses','makefile'),
483 pjoin(self.dir_path, 'SubProcesses',self.madloop_makefile_name))
484
485
486
487 link_tir_libs=[]
488 tir_libs=[]
489
490 filePath = pjoin(self.dir_path, 'SubProcesses',
491 'MadLoop_makefile_definitions')
492 calls = self.write_loop_makefile_definitions(
493 writers.MakefileWriter(filePath),link_tir_libs,tir_libs)
494
495
496
497
498 MadLoopCommon = open(os.path.join(self.loop_dir,'StandAlone',
499 "SubProcesses","MadLoopCommons.inc")).read()
500 writer = writers.FortranWriter(os.path.join(self.dir_path,
501 "SubProcesses","MadLoopCommons.f"))
502 writer.writelines(MadLoopCommon%{
503 'print_banner_commands':self.MadLoop_banner}, context={
504 'collier_available':False})
505 writer.close()
506
507
508 if not os.path.exists(pjoin(self.dir_path,'SubProcesses',
509 'MadLoop5_resources')):
510 cp(pjoin(self.loop_dir,'StandAlone','SubProcesses',
511 'MadLoop5_resources'),pjoin(self.dir_path,'SubProcesses'))
512
513
514 ln(pjoin(self.dir_path,'SubProcesses','MadLoopParams.dat'),
515 pjoin(self.dir_path,'SubProcesses','MadLoop5_resources'))
516 ln(pjoin(self.dir_path,'Cards','param_card.dat'),
517 pjoin(self.dir_path,'SubProcesses','MadLoop5_resources'))
518 ln(pjoin(self.dir_path,'Cards','ident_card.dat'),
519 pjoin(self.dir_path,'SubProcesses','MadLoop5_resources'))
520
521
522
523 if os.path.isfile(pjoin(self.dir_path,'SubProcesses','check_sa.f')):
524 os.remove(pjoin(self.dir_path,'SubProcesses','check_sa.f'))
525
526 cwd = os.getcwd()
527 dirpath = os.path.join(self.dir_path, 'SubProcesses')
528 try:
529 os.chdir(dirpath)
530 except os.error:
531 logger.error('Could not cd to directory %s' % dirpath)
532 return 0
533
534
535 self.write_mp_files(writers.FortranWriter('cts_mprec.h'),\
536 writers.FortranWriter('cts_mpc.h'))
537
538
539 os.chdir(cwd)
540
541
542 super(LoopProcessExporterFortranSA, self).link_CutTools(self.dir_path)
543
544
545
548 """ Create the file makefile which links to the TIR libraries."""
549
550 file = open(os.path.join(self.loop_dir,'StandAlone',
551 'SubProcesses','MadLoop_makefile_definitions.inc')).read()
552 replace_dict={}
553 replace_dict['link_tir_libs']=' '.join(link_tir_libs)
554 replace_dict['tir_libs']=' '.join(tir_libs)
555 replace_dict['dotf']='%.f'
556 replace_dict['prefix']= self.SubProc_prefix
557 replace_dict['doto']='%.o'
558 replace_dict['tir_include']=' '.join(tir_include)
559 file=file%replace_dict
560 if writer:
561 writer.writelines(file)
562 else:
563 return file
564
565 - def convert_model(self, model, wanted_lorentz = [],
566 wanted_couplings = []):
573
574 - def get_ME_identifier(self, matrix_element,
575 group_number = None, group_elem_number = None):
576 """ A function returning a string uniquely identifying the matrix
577 element given in argument so that it can be used as a prefix to all
578 MadLoop5 subroutines and common blocks related to it. This allows
579 to compile several processes into one library as requested by the
580 BLHA (Binoth LesHouches Accord) guidelines.
581 The arguments group_number and proc_id are just for the LoopInduced
582 output with MadEvent."""
583
584
585
586
587 if (not group_number is None) and group_elem_number is None:
588 return 'ML5_%d_%s_'%(matrix_element.get('processes')[0].get('id'),
589 group_number)
590 elif group_number is None or group_elem_number is None:
591 return 'ML5_%d_'%matrix_element.get('processes')[0].get('id')
592 else:
593 return 'ML5_%d_%s_%s_'%(matrix_element.get('processes')[0].get('id'),
594 group_number, group_elem_number)
595
598 """Returns the name of the SubProcess directory, which can contain
599 the process goup and group element number for the case of loop-induced
600 integration with MadEvent."""
601
602
603
604
605 if not group_number is None and group_elem_number is None:
606 return "%s%d_%s_%s"%(self.SubProc_prefix, process.get('id'),
607 group_number,process.shell_string(print_id=False))
608 elif group_number is None or group_elem_number is None:
609 return "%s%s" %(self.SubProc_prefix,process.shell_string())
610 else:
611 return "%s%d_%s_%s_%s"%(self.SubProc_prefix, process.get('id'),
612 group_number, group_elem_number,process.shell_string(print_id=False))
613
614
615
616
618 """ Different daughter classes might want different compilers.
619 Here, the gfortran compiler is used throughout the compilation
620 (mandatory for CutTools written in f90) """
621 if isinstance(compiler, str):
622 fortran_compiler = compiler
623 compiler = export_v4.default_compiler
624 compiler['fortran'] = fortran_compiler
625
626 if not compiler['fortran'] is None and not \
627 any([name in compiler['fortran'] for name in \
628 ['gfortran','ifort']]):
629 logger.info('For loop processes, the compiler must be fortran90'+\
630 'compatible, like gfortran.')
631 compiler['fortran'] = 'gfortran'
632 self.set_compiler(compiler,True)
633 else:
634 self.set_compiler(compiler)
635
636 self.set_cpp_compiler(compiler['cpp'])
637
639
640
641
642
643
644
645
646 MP=re.compile(r"(?P<toSub>^.*CALL\s+)",re.IGNORECASE | re.MULTILINE)
647
648 def replaceWith(match_obj):
649 return match_obj.group('toSub')+'MP_'
650
651 DCMPLX=re.compile(r"DCMPLX\((?P<toSub>([^\)]*))\)",\
652 re.IGNORECASE | re.MULTILINE)
653
654 for i, helas_call in enumerate(helas_calls_list):
655 new_helas_call=MP.sub(replaceWith,helas_call)
656 helas_calls_list[i]=DCMPLX.sub(r"CMPLX(\g<toSub>,KIND=16)",\
657 new_helas_call)
658
660 """ In the loop output, we don't need the files from the Source folder """
661 pass
662
664 """ Add the linking of the additional model files for multiple precision
665 """
666 super(LoopProcessExporterFortranSA, self).make_model_symbolic_link()
667 model_path = self.dir_path + '/Source/MODEL/'
668 ln(model_path + '/mp_coupl.inc', self.dir_path + '/SubProcesses')
669 ln(model_path + '/mp_coupl_same_name.inc', self.dir_path + '/SubProcesses')
670
672 """ Compiles the additional dependences for loop (such as CutTools)."""
673 super(LoopProcessExporterFortranSA, self).make()
674
675
676 libdir = os.path.join(self.dir_path,'lib')
677 sourcedir = os.path.join(self.dir_path,'Source')
678 if self.dependencies=='internal':
679 if not os.path.exists(os.path.realpath(pjoin(libdir, 'libcts.a'))) or \
680 not os.path.exists(os.path.realpath(pjoin(libdir, 'mpmodule.mod'))):
681 if os.path.exists(pjoin(sourcedir,'CutTools')):
682 logger.info('Compiling CutTools (can take a couple of minutes) ...')
683 misc.compile(['CutTools','-j1'], cwd = sourcedir, nb_core=1)
684 logger.info(' ...done.')
685 else:
686 raise MadGraph5Error('Could not compile CutTools because its'+\
687 ' source directory could not be found in the SOURCE folder.')
688 if not os.path.exists(os.path.realpath(pjoin(libdir, 'libcts.a'))) or \
689 not os.path.exists(os.path.realpath(pjoin(libdir, 'mpmodule.mod'))):
690 raise MadGraph5Error('CutTools compilation failed.')
691
692
693
694 compiler_log_path = pjoin(os.path.dirname((os.path.realpath(pjoin(
695 libdir, 'libcts.a')))),'compiler_version.log')
696 if os.path.exists(compiler_log_path):
697 compiler_version_used = open(compiler_log_path,'r').read()
698 if not str(misc.get_gfortran_version(misc.detect_current_compiler(\
699 pjoin(sourcedir,'make_opts')))) in compiler_version_used:
700 if os.path.exists(pjoin(sourcedir,'CutTools')):
701 logger.info('CutTools was compiled with a different fortran'+\
702 ' compiler. Re-compiling it now...')
703 misc.compile(['cleanCT'], cwd = sourcedir)
704 misc.compile(['CutTools','-j1'], cwd = sourcedir, nb_core=1)
705 logger.info(' ...done.')
706 else:
707 raise MadGraph5Error("CutTools installation in %s"\
708 %os.path.realpath(pjoin(libdir, 'libcts.a'))+\
709 " seems to have been compiled with a different compiler than"+\
710 " the one specified in MG5_aMC. Please recompile CutTools.")
711
712 - def cat_coeff(self, ff_number, frac, is_imaginary, Nc_power, Nc_value=3):
713 """Concatenate the coefficient information to reduce it to
714 (fraction, is_imaginary) """
715
716 total_coeff = ff_number * frac * fractions.Fraction(Nc_value) ** Nc_power
717
718 return (total_coeff, is_imaginary)
719
721 """ Returns a list with element 'i' being a list of tuples corresponding
722 to all apparition of amplitude number 'i' in the jamp number 'j'
723 with coeff 'coeff_j'. The format of each tuple describing an apparition
724 is (j, coeff_j). where coeff_j is of the form (Fraction, is_imag)."""
725
726 if(isinstance(col_amps,list)):
727 if(col_amps and isinstance(col_amps[0],list)):
728 color_amplitudes=col_amps
729 else:
730 raise MadGraph5Error("Incorrect col_amps argument passed to get_amp_to_jamp_map")
731 else:
732 raise MadGraph5Error("Incorrect col_amps argument passed to get_amp_to_jamp_map")
733
734
735 res_list = [[] for i in range(n_amps)]
736 for i, coeff_list in enumerate(color_amplitudes):
737 for (coefficient, amp_number) in coeff_list:
738 res_list[amp_number-1].append((i,self.cat_coeff(\
739 coefficient[0],coefficient[1],coefficient[2],coefficient[3])))
740
741 return res_list
742
744 """Return the color matrix definition lines. This color matrix is of size
745 NLOOPAMPSxNBORNAMPS and allows for squaring individually each Loop and Born
746 amplitude."""
747
748 logger.info('Computing diagram color coefficients')
749
750
751
752
753
754 ampl_to_jampl=self.get_amp_to_jamp_map(\
755 matrix_element.get_loop_color_amplitudes(),
756 matrix_element.get_number_of_loop_amplitudes())
757 if matrix_element.get('processes')[0].get('has_born'):
758 ampb_to_jampb=self.get_amp_to_jamp_map(\
759 matrix_element.get_born_color_amplitudes(),
760 matrix_element.get_number_of_born_amplitudes())
761 else:
762 ampb_to_jampb=ampl_to_jampl
763
764 if matrix_element.get('color_matrix'):
765 ColorMatrixDenom = \
766 matrix_element.get('color_matrix').get_line_denominators()
767 ColorMatrixNum = [ matrix_element.get('color_matrix').\
768 get_line_numerators(index, denominator) for
769 (index, denominator) in enumerate(ColorMatrixDenom) ]
770 else:
771 ColorMatrixDenom= [1]
772 ColorMatrixNum = [[1]]
773
774
775 ColorMatrixNumOutput=[]
776 ColorMatrixDenomOutput=[]
777
778
779
780 start = time.time()
781 progress_bar = None
782 time_info = False
783 for i, jampl_list in enumerate(ampl_to_jampl):
784
785
786
787 if i==5:
788 elapsed_time = time.time()-start
789 t = len(ampl_to_jampl)*(elapsed_time/5.0)
790 if t > 10.0:
791 time_info = True
792 logger.info('The color factors computation will take '+\
793 ' about %s to run. '%str(datetime.timedelta(seconds=int(t)))+\
794 'Started on %s.'%datetime.datetime.now().strftime(\
795 "%d-%m-%Y %H:%M"))
796 if logger.getEffectiveLevel()<logging.WARNING:
797 widgets = ['Color computation:', pbar.Percentage(), ' ',
798 pbar.Bar(),' ', pbar.ETA(), ' ']
799 progress_bar = pbar.ProgressBar(widgets=widgets,
800 maxval=len(ampl_to_jampl), fd=sys.stdout)
801
802 if not progress_bar is None:
803 progress_bar.update(i+1)
804
805 sys.stdout.flush()
806
807 line_num=[]
808 line_denom=[]
809
810
811
812
813
814
815
816
817 if len(jampl_list)==0:
818 line_num=[0]*len(ampb_to_jampb)
819 line_denom=[1]*len(ampb_to_jampb)
820 ColorMatrixNumOutput.append(line_num)
821 ColorMatrixDenomOutput.append(line_denom)
822 continue
823
824 for jampb_list in ampb_to_jampb:
825 real_num=0
826 imag_num=0
827 common_denom=color_amp.ColorMatrix.lcmm(*[abs(ColorMatrixDenom[jampl]*
828 ampl_coeff[0].denominator*ampb_coeff[0].denominator) for
829 ((jampl, ampl_coeff),(jampb,ampb_coeff)) in
830 itertools.product(jampl_list,jampb_list)])
831 for ((jampl, ampl_coeff),(jampb, ampb_coeff)) in \
832 itertools.product(jampl_list,jampb_list):
833
834
835 buff_num=ampl_coeff[0].numerator*\
836 ampb_coeff[0].numerator*ColorMatrixNum[jampl][jampb]*\
837 abs(common_denom)/(ampl_coeff[0].denominator*\
838 ampb_coeff[0].denominator*ColorMatrixDenom[jampl])
839
840
841
842 if ampl_coeff[1] and ampb_coeff[1]:
843 real_num=real_num+buff_num
844 elif not ampl_coeff[1] and not ampb_coeff[1]:
845 real_num=real_num+buff_num
846 elif not ampl_coeff[1] and ampb_coeff[1]:
847 imag_num=imag_num-buff_num
848 else:
849 imag_num=imag_num+buff_num
850 assert not (real_num!=0 and imag_num!=0), "MadGraph5_aMC@NLO found a "+\
851 "color matrix element which has both a real and imaginary part."
852 if imag_num!=0:
853 assert int(imag_num) == imag_num and int(common_denom) == common_denom
854 res=fractions.Fraction(int(imag_num),int(common_denom))
855 line_num.append(res.numerator)
856
857
858 line_denom.append(res.denominator*-1)
859 else:
860 assert int(real_num) == real_num and int(common_denom) == common_denom
861 res=fractions.Fraction(int(real_num),int(common_denom))
862 line_num.append(res.numerator)
863
864 line_denom.append(res.denominator)
865
866 ColorMatrixNumOutput.append(line_num)
867 ColorMatrixDenomOutput.append(line_denom)
868
869 if time_info:
870 logger.info('Finished on %s.'%datetime.datetime.now().strftime(\
871 "%d-%m-%Y %H:%M"))
872 if progress_bar!=None:
873 progress_bar.finish()
874
875 return (ColorMatrixNumOutput,ColorMatrixDenomOutput)
876
877 - def get_context(self,matrix_element):
878 """ Returns the contextual variables which need to be set when
879 pre-processing the template files."""
880
881
882
883
884
885
886 try:
887 n_squared_split_orders = matrix_element.rep_dict['nSquaredSO']
888 except (KeyError, AttributeError):
889 n_squared_split_orders = 1
890
891 LoopInduced = not matrix_element.get('processes')[0].get('has_born')
892 self.has_loop_induced = max(LoopInduced, self.has_loop_induced)
893
894 ComputeColorFlows = self.compute_color_flows or LoopInduced
895
896
897 AmplitudeReduction = LoopInduced or ComputeColorFlows
898
899
900 TIRCaching = AmplitudeReduction or n_squared_split_orders>1
901 MadEventOutput = False
902 return {'LoopInduced': LoopInduced,
903 'ComputeColorFlows': ComputeColorFlows,
904 'AmplitudeReduction': AmplitudeReduction,
905 'TIRCaching': TIRCaching,
906 'MadEventOutput': MadEventOutput}
907
908
909
910
911
912 - def generate_loop_subprocess(self, matrix_element, fortran_model,
913 group_number = None, proc_id = None, config_map=None, unique_id=None):
914 """Generate the Pxxxxx directory for a loop subprocess in MG4 standalone,
915 including the necessary loop_matrix.f, born_matrix.f and include files.
916 Notice that this is too different from generate_subprocess_directory
917 so that there is no point reusing this mother function.
918 The 'group_number' and 'proc_id' options are only used for the LoopInduced
919 MadEvent output and only to specify the ME_identifier and the P*
920 SubProcess directory name."""
921
922 cwd = os.getcwd()
923 proc_dir_name = self.get_SubProc_folder_name(
924 matrix_element.get('processes')[0],group_number,proc_id)
925 dirpath = os.path.join(self.dir_path, 'SubProcesses', proc_dir_name)
926
927 try:
928 os.mkdir(dirpath)
929 except os.error as error:
930 logger.warning(error.strerror + " " + dirpath)
931
932 try:
933 os.chdir(dirpath)
934 except os.error:
935 logger.error('Could not cd to directory %s' % dirpath)
936 return 0
937
938 logger.info('Creating files in directory %s' % dirpath)
939
940 if unique_id is None:
941 raise MadGraph5Error('A unique id must be provided to the function'+\
942 'generate_loop_subprocess of LoopProcessExporterFortranSA.')
943
944 open('unique_id.inc','w').write(
945 """ integer UNIQUE_ID
946 parameter(UNIQUE_ID=%d)"""%unique_id)
947
948
949 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial()
950
951 calls=self.write_loop_matrix_element_v4(None,matrix_element,
952 fortran_model, group_number = group_number,
953 proc_id = proc_id, config_map = config_map)
954
955
956
957
958
959 if matrix_element.get('processes')[0].get('has_born'):
960 filename = 'born_matrix.f'
961 calls = self.write_bornmatrix(
962 writers.FortranWriter(filename),
963 matrix_element,
964 fortran_model)
965
966 filename = 'pmass.inc'
967 self.write_pmass_file(writers.FortranWriter(filename),
968 matrix_element)
969
970 filename = 'ngraphs.inc'
971 self.write_ngraphs_file(writers.FortranWriter(filename),
972 len(matrix_element.get_all_amplitudes()))
973
974
975
976 loop_diags = [loop_diag for loop_diag in\
977 matrix_element.get('base_amplitude').get('loop_diagrams')\
978 if isinstance(loop_diag,LoopDiagram) and loop_diag.get('type') > 0]
979 if len(loop_diags)>5000:
980 logger.info("There are more than 5000 loop diagrams."+\
981 "Only the first 5000 are drawn.")
982 filename = "loop_matrix.ps"
983 plot = draw.MultiEpsDiagramDrawer(base_objects.DiagramList(
984 loop_diags[:5000]),filename,
985 model=matrix_element.get('processes')[0].get('model'),amplitude='')
986 logger.info("Drawing loop Feynman diagrams for " + \
987 matrix_element.get('processes')[0].nice_string())
988 plot.draw()
989
990 if matrix_element.get('processes')[0].get('has_born'):
991 filename = "born_matrix.ps"
992 plot = draw.MultiEpsDiagramDrawer(matrix_element.get('base_amplitude').\
993 get('born_diagrams'),
994 filename,
995 model=matrix_element.get('processes')[0].\
996 get('model'),
997 amplitude='')
998 logger.info("Generating born Feynman diagrams for " + \
999 matrix_element.get('processes')[0].nice_string(\
1000 print_weighted=False))
1001 plot.draw()
1002
1003 self.link_files_from_Subprocesses(self.get_SubProc_folder_name(
1004 matrix_element.get('processes')[0],group_number,proc_id))
1005
1006
1007 os.chdir(cwd)
1008
1009 if not calls:
1010 calls = 0
1011 return calls
1012
1014 """ To link required files from the Subprocesses directory to the
1015 different P* ones"""
1016
1017 linkfiles = ['coupl.inc',
1018 'cts_mprec.h', 'cts_mpc.h', 'mp_coupl.inc',
1019 'mp_coupl_same_name.inc',
1020 'MadLoopParamReader.f','MadLoopCommons.f',
1021 'MadLoopParams.inc','global_specs.inc']
1022
1023 for file in linkfiles:
1024 ln('../%s' % file)
1025
1026 ln('../%s'%self.madloop_makefile_name, name='makefile')
1027
1028
1029 ln('../../lib/mpmodule.mod')
1030
1031
1032 ln('../MadLoop5_resources')
1033
1036 """Generates the entries for the general replacement dictionary used
1037 for the different output codes for this exporter.The arguments
1038 group_number and proc_id are just for the LoopInduced output with MadEvent."""
1039
1040 dict={}
1041
1042
1043
1044
1045 dict['proc_prefix'] = self.get_ME_identifier(matrix_element,
1046 group_number = group_number, group_elem_number = proc_id)
1047
1048 if 'prefix' in self.cmd_options and self.cmd_options['prefix'] in ['int','proc']:
1049 for proc in matrix_element.get('processes'):
1050 ids = [l.get('id') for l in proc.get('legs_with_decays')]
1051 self.prefix_info[tuple(ids),proc.get('id')] = [dict['proc_prefix'], proc.get_tag()]
1052
1053
1054
1055 dict['proc_id'] = ''
1056
1057 info_lines = self.get_mg5_info_lines()
1058 dict['info_lines'] = info_lines
1059
1060 process_lines = self.get_process_info_lines(matrix_element)
1061 dict['process_lines'] = process_lines
1062
1063 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial()
1064 dict['nexternal'] = nexternal
1065 dict['nincoming'] = ninitial
1066
1067 ncomb = matrix_element.get_helicity_combinations()
1068 dict['ncomb'] = ncomb
1069
1070 nloopamps = matrix_element.get_number_of_loop_amplitudes()
1071 dict['nloopamps'] = nloopamps
1072
1073 nloopdiags = len(matrix_element.get('diagrams'))
1074 dict['nloopdiags'] = nloopdiags
1075
1076 nctamps = matrix_element.get_number_of_CT_amplitudes()
1077 dict['nctamps'] = nctamps
1078
1079 nwavefuncs = matrix_element.get_number_of_external_wavefunctions()
1080 dict['nwavefuncs'] = nwavefuncs
1081
1082 dict['real_dp_format']='real*8'
1083 dict['real_mp_format']='real*16'
1084
1085 dict['complex_dp_format']='complex*16'
1086 dict['complex_mp_format']='complex*32'
1087
1088 dict['mass_dp_format'] = dict['complex_dp_format']
1089 dict['mass_mp_format'] = dict['complex_mp_format']
1090
1091
1092 dict['nmultichannels'] = 0
1093 dict['nmultichannel_configs'] = 0
1094 dict['config_map_definition'] = ''
1095 dict['config_index_map_definition'] = ''
1096
1097
1098
1099
1100
1101 if matrix_element.get('processes')[0].get('has_born'):
1102 dict['color_matrix_size'] = 'nbornamps'
1103 dict['get_nsqso_born']=\
1104 "include 'nsqso_born.inc'"
1105 else:
1106 dict['get_nsqso_born']="""INTEGER NSQSO_BORN
1107 PARAMETER (NSQSO_BORN=0)
1108 """
1109 dict['color_matrix_size'] = 'nloopamps'
1110
1111
1112
1113
1114 if matrix_element.get('processes')[0].get('has_born'):
1115
1116 nbornamps = matrix_element.get_number_of_born_amplitudes()
1117 dict['nbornamps'] = nbornamps
1118 dict['ncomb_helas_objs'] = ',ncomb'
1119 dict['nbornamps_decl'] = \
1120 """INTEGER NBORNAMPS
1121 PARAMETER (NBORNAMPS=%d)"""%nbornamps
1122 dict['nBornAmps'] = nbornamps
1123
1124 else:
1125 dict['ncomb_helas_objs'] = ''
1126 dict['dp_born_amps_decl'] = ''
1127 dict['dp_born_amps_decl_in_mp'] = ''
1128 dict['copy_mp_to_dp_born_amps'] = ''
1129 dict['mp_born_amps_decl'] = ''
1130 dict['nbornamps_decl'] = ''
1131 dict['nbornamps'] = 0
1132 dict['nBornAmps'] = 0
1133
1134 return dict
1135
1136 - def write_loop_matrix_element_v4(self, writer, matrix_element, fortran_model,
1137 group_number = None, proc_id = None, config_map = None):
1138 """ Writes loop_matrix.f, CT_interface.f, loop_num.f and
1139 mp_born_amps_and_wfs.
1140 The arguments group_number and proc_id are just for the LoopInduced
1141 output with MadEvent and only used in get_ME_identifier.
1142 """
1143
1144
1145
1146 if config_map:
1147 raise MadGraph5Error('The default loop output cannot be used with'+\
1148 'MadEvent and cannot compute the AMP2 for multi-channeling.')
1149
1150 if not isinstance(fortran_model,\
1151 helas_call_writers.FortranUFOHelasCallWriter):
1152 raise MadGraph5Error('The loop fortran output can only'+\
1153 ' work with a UFO Fortran model')
1154
1155 LoopFortranModel = helas_call_writers.FortranUFOHelasCallWriter(
1156 argument=fortran_model.get('model'),
1157 hel_sum=matrix_element.get('processes')[0].get('has_born'))
1158
1159
1160
1161
1162
1163 matrix_element.compute_all_analytic_information(
1164 self.get_aloha_model(matrix_element.get('processes')[0].get('model')))
1165
1166
1167
1168 matrix_element.rep_dict = self.generate_general_replace_dict(
1169 matrix_element, group_number = group_number, proc_id = proc_id)
1170
1171
1172 matrix_element.rep_dict['maxlcouplings']= \
1173 matrix_element.find_max_loop_coupling()
1174
1175
1176 if matrix_element.get('processes')[0].get('has_born'):
1177 matrix_element.rep_dict['dp_born_amps_decl_in_mp'] = \
1178 matrix_element.rep_dict['complex_dp_format']+" DPAMP(NBORNAMPS,NCOMB)"+\
1179 "\n common/%sAMPS/DPAMP"%matrix_element.rep_dict['proc_prefix']
1180 matrix_element.rep_dict['dp_born_amps_decl'] = \
1181 matrix_element.rep_dict['complex_dp_format']+" AMP(NBORNAMPS,NCOMB)"+\
1182 "\n common/%sAMPS/AMP"%matrix_element.rep_dict['proc_prefix']
1183 matrix_element.rep_dict['mp_born_amps_decl'] = \
1184 matrix_element.rep_dict['complex_mp_format']+" AMP(NBORNAMPS,NCOMB)"+\
1185 "\n common/%sMP_AMPS/AMP"%matrix_element.rep_dict['proc_prefix']
1186 matrix_element.rep_dict['copy_mp_to_dp_born_amps'] = \
1187 '\n'.join(['DO I=1,NBORNAMPS','DPAMP(I,H)=AMP(I,H)','ENDDO'])
1188
1189 if writer:
1190 raise MadGraph5Error('Matrix output mode no longer supported.')
1191
1192 filename = 'loop_matrix.f'
1193 calls = self.write_loopmatrix(writers.FortranWriter(filename),
1194 matrix_element,
1195 LoopFortranModel)
1196
1197
1198 proc_prefix_writer = writers.FortranWriter('proc_prefix.txt','w')
1199 proc_prefix_writer.write(matrix_element.rep_dict['proc_prefix'])
1200 proc_prefix_writer.close()
1201
1202 filename = 'check_sa.f'
1203 self.write_check_sa(writers.FortranWriter(filename),matrix_element)
1204
1205 filename = 'CT_interface.f'
1206 self.write_CT_interface(writers.FortranWriter(filename),\
1207 matrix_element)
1208
1209
1210
1211 filename = 'improve_ps.f'
1212 calls = self.write_improve_ps(writers.FortranWriter(filename),
1213 matrix_element)
1214
1215 filename = 'loop_num.f'
1216 self.write_loop_num(writers.FortranWriter(filename),\
1217 matrix_element,LoopFortranModel)
1218
1219 filename = 'mp_born_amps_and_wfs.f'
1220 self.write_born_amps_and_wfs(writers.FortranWriter(filename),\
1221 matrix_element,LoopFortranModel)
1222
1223
1224 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial()
1225 filename = 'nexternal.inc'
1226 self.write_nexternal_file(writers.FortranWriter(filename),
1227 nexternal, ninitial)
1228
1229 filename = 'process_info.inc'
1230 self.write_process_info_file(writers.FortranWriter(filename),
1231 matrix_element)
1232 return calls
1233
1235 """A small structural function to write the include file specifying some
1236 process characteristics."""
1237
1238 model = matrix_element.get('processes')[0].get('model')
1239 process_info = {}
1240
1241
1242
1243
1244
1245 process_info['max_spin_connected_to_loop']=\
1246 matrix_element.get_max_spin_connected_to_loop()
1247
1248 process_info['max_spin_external_particle']= max(
1249 model.get_particle(l.get('id')).get('spin') for l in
1250 matrix_element.get('processes')[0].get('legs'))
1251
1252 proc_include = \
1253 """
1254 INTEGER MAX_SPIN_CONNECTED_TO_LOOP
1255 PARAMETER(MAX_SPIN_CONNECTED_TO_LOOP=%(max_spin_connected_to_loop)d)
1256 INTEGER MAX_SPIN_EXTERNAL_PARTICLE
1257 PARAMETER(MAX_SPIN_EXTERNAL_PARTICLE=%(max_spin_external_particle)d)
1258 """%process_info
1259
1260 writer.writelines(proc_include)
1261
1263 """ To overload the default name for this function such that the correct
1264 function is used when called from the command interface """
1265
1266 self.unique_id +=1
1267 return self.generate_loop_subprocess(matrix_element,fortran_model,
1268 unique_id=self.unique_id)
1269
1271 """Writes out the steering code check_sa. In the optimized output mode,
1272 All the necessary entries in the replace_dictionary have already been
1273 set in write_loopmatrix because it is only there that one has access to
1274 the information about split orders."""
1275 replace_dict = copy.copy(matrix_element.rep_dict)
1276 for key in ['print_so_born_results','print_so_loop_results',
1277 'write_so_born_results','write_so_loop_results','set_coupling_target']:
1278 if key not in list(replace_dict.keys()):
1279 replace_dict[key]=''
1280
1281 if matrix_element.get('processes')[0].get('has_born'):
1282 file = open(os.path.join(self.template_dir,'check_sa.inc')).read()
1283 else:
1284 file = open(os.path.join(self.template_dir,\
1285 'check_sa_loop_induced.inc')).read()
1286 file=file%replace_dict
1287 writer.writelines(file)
1288
1289
1290 if not os.path.isfile(pjoin(self.template_dir,'check_py.f.inc')):
1291 return
1292
1293 file = open(os.path.join(self.template_dir,\
1294 'check_py.f.inc')).read()
1295
1296 if 'prefix' in self.cmd_options and self.cmd_options['prefix'] in ['int','proc']:
1297 replace_dict['prefix_routine'] = replace_dict['proc_prefix']
1298 else:
1299 replace_dict['prefix_routine'] = ''
1300 file=file%replace_dict
1301 new_path = writer.name.replace('check_sa.f', 'f2py_wrapper.f')
1302 new_writer = writer.__class__(new_path, 'w')
1303 new_writer.writelines(file)
1304
1305 file = open(os.path.join(self.template_dir,\
1306 'check_sa.py.inc')).read()
1307
1308
1309 curr_proc = matrix_element.get('processes')[0]
1310 random_PSpoint_python_formatted = \
1311 """# Specify your chosen PS point below. If you leave it filled with None, then the script will attempt to read it from the file PS.input.
1312 p= [[None,]*4]*%d"""%len(curr_proc.get('legs'))
1313
1314 process_definition_string = curr_proc.nice_string().replace('Process:','')
1315 file=file.format(random_PSpoint_python_formatted,process_definition_string,
1316 replace_dict['proc_prefix'].lower())
1317 new_path = writer.name.replace('check_sa.f', 'check_sa.py')
1318 new_writer = open(new_path, 'w')
1319 new_writer.writelines(file)
1320
1321 os.chmod(new_path, os.stat(new_path).st_mode | stat.S_IEXEC)
1322
1324 """ Write out the improve_ps subroutines which modify the PS point
1325 given in input and slightly deform it to achieve exact onshellness on
1326 all external particles as well as perfect energy-momentum conservation"""
1327 replace_dict = copy.copy(matrix_element.rep_dict)
1328
1329 (nexternal,ninitial)=matrix_element.get_nexternal_ninitial()
1330 replace_dict['ninitial']=ninitial
1331 mass_list=matrix_element.get_external_masses()[:-2]
1332 mp_variable_prefix = check_param_card.ParamCard.mp_prefix
1333
1334
1335 replace_dict['real_format']=replace_dict['real_mp_format']
1336 replace_dict['mp_prefix']='MP_'
1337 replace_dict['exp_letter']='e'
1338 replace_dict['mp_specifier']='_16'
1339 replace_dict['coupl_inc_name']='mp_coupl.inc'
1340 replace_dict['masses_def']='\n'.join(['MASSES(%(i)d)=%(prefix)s%(m)s'\
1341 %{'i':i+1,'m':m, 'prefix':mp_variable_prefix} for \
1342 i, m in enumerate(mass_list)])
1343 file_mp = open(os.path.join(self.template_dir,'improve_ps.inc')).read()
1344 file_mp=file_mp%replace_dict
1345
1346 writer.writelines(file_mp)
1347
1349 """ Create the file containing the core subroutine called by CutTools
1350 which contains the Helas calls building the loop"""
1351
1352 if not matrix_element.get('processes') or \
1353 not matrix_element.get('diagrams'):
1354 return 0
1355
1356
1357 writers.FortranWriter.downcase = False
1358
1359 file = open(os.path.join(self.template_dir,'loop_num.inc')).read()
1360
1361 replace_dict = copy.copy(matrix_element.rep_dict)
1362
1363 loop_helas_calls=fortran_model.get_loop_amplitude_helas_calls(matrix_element)
1364 replace_dict['maxlcouplings']=matrix_element.find_max_loop_coupling()
1365 replace_dict['loop_helas_calls'] = "\n".join(loop_helas_calls)
1366
1367
1368
1369 dp_squaring_lines=['DO I=1,NBORNAMPS',
1370 'CFTOT=DCMPLX(CF_N(AMPLNUM,I)/DBLE(ABS(CF_D(AMPLNUM,I))),0.0d0)',
1371 'IF(CF_D(AMPLNUM,I).LT.0) CFTOT=CFTOT*IMAG1',
1372 'RES=RES+CFTOT*BUFF*DCONJG(AMP(I,H))','ENDDO']
1373 mp_squaring_lines=['DO I=1,NBORNAMPS',
1374 'CFTOT=CMPLX(CF_N(AMPLNUM,I)/(1.0E0_16*ABS(CF_D(AMPLNUM,I))),0.0E0_16,KIND=16)',
1375 'IF(CF_D(AMPLNUM,I).LT.0) CFTOT=CFTOT*IMAG1',
1376 'QPRES=QPRES+CFTOT*BUFF*CONJG(AMP(I,H))','ENDDO']
1377 if matrix_element.get('processes')[0].get('has_born'):
1378 replace_dict['dp_squaring']='\n'.join(dp_squaring_lines)
1379 replace_dict['mp_squaring']='\n'.join(mp_squaring_lines)
1380 else:
1381 replace_dict['dp_squaring']='RES=BUFF'
1382 replace_dict['mp_squaring']='QPRES=BUFF'
1383
1384
1385 self.turn_to_mp_calls(loop_helas_calls)
1386 replace_dict['mp_loop_helas_calls'] = "\n".join(loop_helas_calls)
1387
1388 file=file%replace_dict
1389
1390 if writer:
1391 writer.writelines(file)
1392 else:
1393 return file
1394
1396 """ Create the file CT_interface.f which contains the subroutine defining
1397 the loop HELAS-like calls along with the general interfacing subroutine.
1398 It is used to interface against any OPP tool, including Samurai and Ninja."""
1399
1400 files=[]
1401
1402
1403 replace_dict=copy.copy(matrix_element.rep_dict)
1404
1405
1406
1407 if matrix_element.get('processes')[0].get('has_born'):
1408 replace_dict['finalize_CT']='\n'.join([\
1409 'RES(%d)=NORMALIZATION*2.0d0*DBLE(RES(%d))'%(i,i) for i in range(1,4)])
1410 else:
1411 replace_dict['finalize_CT']='\n'.join([\
1412 'RES(%d)=NORMALIZATION*RES(%d)'%(i,i) for i in range(1,4)])
1413
1414 file = open(os.path.join(self.template_dir,'CT_interface.inc')).read()
1415
1416 file = file % replace_dict
1417 files.append(file)
1418
1419
1420
1421 HelasLoopAmpsCallKeys=matrix_element.get_used_helas_loop_amps()
1422
1423 for callkey in HelasLoopAmpsCallKeys:
1424 replace_dict=copy.copy(matrix_element.rep_dict)
1425
1426
1427 if matrix_element.get('processes')[0].get('has_born'):
1428 replace_dict['validh_or_nothing']=',validh'
1429 else:
1430 replace_dict['validh_or_nothing']=''
1431
1432
1433 if len(callkey)>2:
1434 replace_dict['ncplsargs']=callkey[2]
1435 cplsargs="".join(["C%d,MP_C%d, "%(i,i) for i in range(1,callkey[2]+1)])
1436 replace_dict['cplsargs']=cplsargs
1437 cplsdecl="".join(["C%d, "%i for i in range(1,callkey[2]+1)])[:-2]
1438 replace_dict['cplsdecl']=cplsdecl
1439 mp_cplsdecl="".join(["MP_C%d, "%i for i in range(1,callkey[2]+1)])[:-2]
1440 replace_dict['mp_cplsdecl']=mp_cplsdecl
1441 cplset="\n".join(["\n".join(["LC(%d)=C%d"%(i,i),\
1442 "MP_LC(%d)=MP_C%d"%(i,i)])\
1443 for i in range(1,callkey[2]+1)])
1444 replace_dict['cplset']=cplset
1445
1446 replace_dict['nloopline']=callkey[0]
1447 wfsargs="".join(["W%d, "%i for i in range(1,callkey[1]+1)])
1448 replace_dict['wfsargs']=wfsargs
1449
1450 if not optimized_output:
1451 margs="".join(["M%d,MP_M%d, "%(i,i) for i in range(1,callkey[0]+1)])
1452 else:
1453 margs="".join(["M%d, "%i for i in range(1,callkey[0]+1)])
1454 replace_dict['margs']=margs
1455 wfsargsdecl="".join([("W%d, "%i) for i in range(1,callkey[1]+1)])[:-2]
1456 replace_dict['wfsargsdecl']=wfsargsdecl
1457 margsdecl="".join(["M%d, "%i for i in range(1,callkey[0]+1)])[:-2]
1458 replace_dict['margsdecl']=margsdecl
1459 mp_margsdecl="".join(["MP_M%d, "%i for i in range(1,callkey[0]+1)])[:-2]
1460 replace_dict['mp_margsdecl']=mp_margsdecl
1461 weset="\n".join([("WE("+str(i)+")=W"+str(i)) for \
1462 i in range(1,callkey[1]+1)])
1463 replace_dict['weset']=weset
1464 weset="\n".join([("WE(%d)=W%d"%(i,i)) for i in range(1,callkey[1]+1)])
1465 replace_dict['weset']=weset
1466 msetlines=["M2L(1)=M%d**2"%(callkey[0]),]
1467 mset="\n".join(msetlines+["M2L(%d)=M%d**2"%(i,i-1) for \
1468 i in range(2,callkey[0]+1)])
1469 replace_dict['mset']=mset
1470 mset2lines=["ML(1)=M%d"%(callkey[0]),"ML(2)=M%d"%(callkey[0]),
1471 "MP_ML(1)=MP_M%d"%(callkey[0]),"MP_ML(2)=MP_M%d"%(callkey[0])]
1472 mset2="\n".join(mset2lines+["\n".join(["ML(%d)=M%d"%(i,i-2),
1473 "MP_ML(%d)=MP_M%d"%(i,i-2)]) for \
1474 i in range(3,callkey[0]+3)])
1475 replace_dict['mset2']=mset2
1476 replace_dict['nwfsargs'] = callkey[1]
1477 if callkey[0]==callkey[1]:
1478 replace_dict['nwfsargs_header'] = ""
1479 replace_dict['pairingargs']=""
1480 replace_dict['pairingdecl']=""
1481 pairingset="""DO I=1,NLOOPLINE
1482 PAIRING(I)=1
1483 ENDDO
1484 """
1485 replace_dict['pairingset']=pairingset
1486 else:
1487 replace_dict['nwfsargs_header'] = '_%d'%callkey[1]
1488 pairingargs="".join([("P"+str(i)+", ") for i in \
1489 range(1,callkey[0]+1)])
1490 replace_dict['pairingargs']=pairingargs
1491 pairingdecl="integer "+"".join([("P"+str(i)+", ") for i in \
1492 range(1,callkey[0]+1)])[:-2]
1493 replace_dict['pairingdecl']=pairingdecl
1494 pairingset="\n".join([("PAIRING("+str(i)+")=P"+str(i)) for \
1495 i in range(1,callkey[0]+1)])
1496 replace_dict['pairingset']=pairingset
1497
1498 file = open(os.path.join(self.template_dir,\
1499 'helas_loop_amplitude.inc')).read()
1500 file = file % replace_dict
1501 files.append(file)
1502
1503 file="\n".join(files)
1504
1505 if writer:
1506 writer.writelines(file,context=self.get_context(matrix_element))
1507 else:
1508 return file
1509
1510
1511
1512 - def split_HELASCALLS(self, writer, replace_dict, template_name, masterfile, \
1513 helas_calls, entry_name, bunch_name,n_helas=2000,
1514 required_so_broadcaster = 'LOOP_REQ_SO_DONE',
1515 continue_label = 1000, momenta_array_name='P',
1516 context={}):
1517 """ Finish the code generation with splitting.
1518 Split the helas calls in the argument helas_calls into bunches of
1519 size n_helas and place them in dedicated subroutine with name
1520 <bunch_name>_i. Also setup the corresponding calls to these subroutine
1521 in the replace_dict dictionary under the entry entry_name.
1522 The context specified will be forwarded to the the fileWriter."""
1523 helascalls_replace_dict=copy.copy(replace_dict)
1524 helascalls_replace_dict['bunch_name']=bunch_name
1525 helascalls_files=[]
1526 for i, k in enumerate(range(0, len(helas_calls), n_helas)):
1527 helascalls_replace_dict['bunch_number']=i+1
1528 helascalls_replace_dict['helas_calls']=\
1529 '\n'.join(helas_calls[k:k + n_helas])
1530 helascalls_replace_dict['required_so_broadcaster']=\
1531 required_so_broadcaster
1532 helascalls_replace_dict['continue_label']=continue_label
1533 new_helascalls_file = open(os.path.join(self.template_dir,\
1534 template_name)).read()
1535 new_helascalls_file = new_helascalls_file % helascalls_replace_dict
1536 helascalls_files.append(new_helascalls_file)
1537
1538 helascalls_calls = [ "CALL %s%s_%d(%s,NHEL,H,IC)"%\
1539 (replace_dict['proc_prefix'] ,bunch_name,a+1,momenta_array_name) \
1540 for a in range(len(helascalls_files))]
1541 replace_dict[entry_name]='\n'.join(helascalls_calls)
1542 if writer:
1543 for i, helascalls_file in enumerate(helascalls_files):
1544 filename = '%s_%d.f'%(bunch_name,i+1)
1545 writers.FortranWriter(filename).writelines(helascalls_file,
1546 context=context)
1547 else:
1548 masterfile='\n'.join([masterfile,]+helascalls_files)
1549
1550 return masterfile
1551
1552 - def write_loopmatrix(self, writer, matrix_element, fortran_model,
1553 noSplit=False):
1554 """Create the loop_matrix.f file."""
1555
1556 if not matrix_element.get('processes') or \
1557 not matrix_element.get('diagrams'):
1558 return 0
1559
1560
1561
1562 writers.FortranWriter.downcase = False
1563
1564 replace_dict = copy.copy(matrix_element.rep_dict)
1565
1566
1567
1568 den_factor_line = self.get_den_factor_line(matrix_element)
1569 replace_dict['den_factor_line'] = den_factor_line
1570
1571
1572 replace_dict['hel_avg_factor'] = matrix_element.get_hel_avg_factor()
1573 replace_dict['beamone_helavgfactor'], replace_dict['beamtwo_helavgfactor'] =\
1574 matrix_element.get_beams_hel_avg_factor()
1575
1576
1577
1578
1579 if not matrix_element.get('processes')[0].get('has_born'):
1580 replace_dict['compute_born']=\
1581 """C There is of course no born for loop induced processes
1582 ANS(0)=0.0d0
1583 """
1584 replace_dict['set_reference']='\n'.join([
1585 'C For loop-induced, the reference for comparison is set later'+\
1586 ' from the total contribution of the previous PS point considered.',
1587 'C But you can edit here the value to be used for the first PS point.',
1588 'if (NPSPOINTS.eq.0) then','ref=1.0d-50','else',
1589 'ref=nextRef/DBLE(NPSPOINTS)','endif'])
1590 replace_dict['loop_induced_setup'] = '\n'.join([
1591 'HELPICKED_BU=HELPICKED','HELPICKED=H','MP_DONE=.FALSE.',
1592 'IF(SKIPLOOPEVAL) THEN','GOTO 1227','ENDIF'])
1593 replace_dict['loop_induced_finalize'] = \
1594 ("""DO I=NCTAMPS+1,NLOOPAMPS
1595 IF((CTMODERUN.NE.-1).AND..NOT.CHECKPHASE.AND.(.NOT.S(I))) THEN
1596 WRITE(*,*) '##W03 WARNING Contribution ',I
1597 WRITE(*,*) ' is unstable for helicity ',H
1598 ENDIF
1599 C IF(.NOT.%(proc_prefix)sISZERO(ABS(AMPL(2,I))+ABS(AMPL(3,I)),REF,-1,H)) THEN
1600 C WRITE(*,*) '##W04 WARNING Contribution ',I,' for helicity ',H,' has a contribution to the poles.'
1601 C WRITE(*,*) 'Finite contribution = ',AMPL(1,I)
1602 C WRITE(*,*) 'single pole contribution = ',AMPL(2,I)
1603 C WRITE(*,*) 'double pole contribution = ',AMPL(3,I)
1604 C ENDIF
1605 ENDDO
1606 1227 CONTINUE
1607 HELPICKED=HELPICKED_BU""")%replace_dict
1608 replace_dict['loop_helas_calls']=""
1609 replace_dict['nctamps_or_nloopamps']='nloopamps'
1610 replace_dict['nbornamps_or_nloopamps']='nloopamps'
1611 replace_dict['squaring']=\
1612 """ANS(1)=ANS(1)+DBLE(CFTOT*AMPL(1,I)*DCONJG(AMPL(1,J)))
1613 IF (J.EQ.1) THEN
1614 ANS(2)=ANS(2)+DBLE(CFTOT*AMPL(2,I))+DIMAG(CFTOT*AMPL(2,I))
1615 ANS(3)=ANS(3)+DBLE(CFTOT*AMPL(3,I))+DIMAG(CFTOT*AMPL(3,I))
1616 ENDIF"""
1617 else:
1618 replace_dict['compute_born']=\
1619 """C Compute the born, for a specific helicity if asked so.
1620 call %(proc_prefix)ssmatrixhel(P_USER,USERHEL,ANS(0))
1621 """%matrix_element.rep_dict
1622 replace_dict['set_reference']=\
1623 """C We chose to use the born evaluation for the reference
1624 call %(proc_prefix)ssmatrix(p,ref)"""%matrix_element.rep_dict
1625 replace_dict['loop_induced_helas_calls'] = ""
1626 replace_dict['loop_induced_finalize'] = ""
1627 replace_dict['loop_induced_setup'] = ""
1628 replace_dict['nctamps_or_nloopamps']='nctamps'
1629 replace_dict['nbornamps_or_nloopamps']='nbornamps'
1630 replace_dict['squaring']='\n'.join(['DO K=1,3',
1631 'ANS(K)=ANS(K)+2.0d0*DBLE(CFTOT*AMPL(K,I)*DCONJG(AMP(J,H)))',
1632 'ENDDO'])
1633
1634
1635
1636
1637 writers.FortranWriter('nsquaredSO.inc').writelines(
1638 """INTEGER NSQUAREDSO
1639 PARAMETER (NSQUAREDSO=0)""")
1640
1641
1642
1643 actualize_ans=[]
1644 if matrix_element.get('processes')[0].get('has_born'):
1645 actualize_ans.append("DO I=NCTAMPS+1,NLOOPAMPS")
1646 actualize_ans.extend("ANS(%d)=ANS(%d)+AMPL(%d,I)"%(i,i,i) for i \
1647 in range(1,4))
1648 actualize_ans.append(\
1649 "IF((CTMODERUN.NE.-1).AND..NOT.CHECKPHASE.AND.(.NOT.S(I))) THEN")
1650 actualize_ans.append(\
1651 "WRITE(*,*) '##W03 WARNING Contribution ',I,' is unstable.'")
1652 actualize_ans.extend(["ENDIF","ENDDO"])
1653 replace_dict['actualize_ans']='\n'.join(actualize_ans)
1654 else:
1655 replace_dict['actualize_ans']=\
1656 ("""C We add five powers to the reference value to loosen a bit the vanishing pole check.
1657 C IF(.NOT.(CHECKPHASE.OR.(.NOT.HELDOUBLECHECKED)).AND..NOT.%(proc_prefix)sISZERO(ABS(ANS(2))+ABS(ANS(3)),ABS(ANS(1))*(10.0d0**5),-1,H)) THEN
1658 C WRITE(*,*) '##W05 WARNING Found a PS point with a contribution to the single pole.'
1659 C WRITE(*,*) 'Finite contribution = ',ANS(1)
1660 C WRITE(*,*) 'single pole contribution = ',ANS(2)
1661 C WRITE(*,*) 'double pole contribution = ',ANS(3)
1662 C ENDIF""")%replace_dict
1663
1664
1665 (CMNum,CMDenom) = self.get_color_matrix(matrix_element)
1666 CMWriter=open(pjoin('..','MadLoop5_resources',
1667 '%(proc_prefix)sColorNumFactors.dat'%matrix_element.rep_dict),'w')
1668 for ColorLine in CMNum:
1669 CMWriter.write(' '.join(['%d'%C for C in ColorLine])+'\n')
1670 CMWriter.close()
1671 CMWriter=open(pjoin('..','MadLoop5_resources',
1672 '%(proc_prefix)sColorDenomFactors.dat'%matrix_element.rep_dict),'w')
1673 for ColorLine in CMDenom:
1674 CMWriter.write(' '.join(['%d'%C for C in ColorLine])+'\n')
1675 CMWriter.close()
1676
1677
1678 HelConfigs=matrix_element.get_helicity_matrix()
1679 HelConfigWriter=open(pjoin('..','MadLoop5_resources',
1680 '%(proc_prefix)sHelConfigs.dat'%matrix_element.rep_dict),'w')
1681 for HelConfig in HelConfigs:
1682 HelConfigWriter.write(' '.join(['%d'%H for H in HelConfig])+'\n')
1683 HelConfigWriter.close()
1684
1685
1686 loop_amp_helas_calls = fortran_model.get_loop_amp_helas_calls(\
1687 matrix_element)
1688
1689 loop_amp_helas_calls = [lc % matrix_element.rep_dict
1690 for lc in loop_amp_helas_calls]
1691
1692 born_ct_helas_calls, UVCT_helas_calls = \
1693 fortran_model.get_born_ct_helas_calls(matrix_element)
1694
1695
1696 born_ct_helas_calls = born_ct_helas_calls + UVCT_helas_calls
1697 file = open(os.path.join(self.template_dir,\
1698
1699 'loop_matrix_standalone.inc')).read()
1700
1701 if matrix_element.get('processes')[0].get('has_born'):
1702 toBeRepaced='loop_helas_calls'
1703 else:
1704 toBeRepaced='loop_induced_helas_calls'
1705
1706
1707 if (not noSplit and (len(matrix_element.get_all_amplitudes())>1000)):
1708 file=self.split_HELASCALLS(writer,replace_dict,\
1709 'helas_calls_split.inc',file,born_ct_helas_calls,\
1710 'born_ct_helas_calls','helas_calls_ampb')
1711 file=self.split_HELASCALLS(writer,replace_dict,\
1712 'helas_calls_split.inc',file,loop_amp_helas_calls,\
1713 toBeRepaced,'helas_calls_ampl')
1714 else:
1715 replace_dict['born_ct_helas_calls']='\n'.join(born_ct_helas_calls)
1716 replace_dict[toBeRepaced]='\n'.join(loop_amp_helas_calls)
1717
1718 file = file % replace_dict
1719
1720 loop_calls_finder = re.compile(r'^\s*CALL\S*LOOP\S*')
1721 n_loop_calls = len([call for call in loop_amp_helas_calls if not loop_calls_finder.match(call) is None])
1722 if writer:
1723
1724 writer.writelines(file)
1725 return n_loop_calls
1726 else:
1727
1728 return n_loop_calls, file
1729
1731 """Create the born_matrix.f file for the born process as for a standard
1732 tree-level computation."""
1733
1734 if not matrix_element.get('processes') or \
1735 not matrix_element.get('diagrams'):
1736 return 0
1737
1738 if not isinstance(writer, writers.FortranWriter):
1739 raise writers.FortranWriter.FortranWriterError(\
1740 "writer not FortranWriter")
1741
1742
1743
1744
1745
1746
1747
1748 bornME = helas_objects.HelasMatrixElement()
1749 for prop in bornME.keys():
1750 bornME.set(prop,copy.deepcopy(matrix_element.get(prop)))
1751 bornME.set('base_amplitude',None,force=True)
1752 bornME.set('diagrams',copy.deepcopy(\
1753 matrix_element.get_born_diagrams()))
1754 bornME.set('color_basis',copy.deepcopy(\
1755 matrix_element.get('born_color_basis')))
1756 bornME.set('color_matrix',copy.deepcopy(\
1757 color_amp.ColorMatrix(bornME.get('color_basis'))))
1758
1759
1760 bornME.optimization = True
1761 return super(LoopProcessExporterFortranSA,self).write_matrix_element_v4(
1762 writer, bornME, fortran_model,
1763 proc_prefix=matrix_element.rep_dict['proc_prefix'])
1764
1767 """ Writes out the code for the subroutine MP_BORN_AMPS_AND_WFS which
1768 computes just the external wavefunction and born amplitudes in
1769 multiple precision. """
1770
1771 if not matrix_element.get('processes') or \
1772 not matrix_element.get('diagrams'):
1773 return 0
1774
1775 replace_dict = copy.copy(matrix_element.rep_dict)
1776
1777
1778 if matrix_element.get('processes')[0].get('has_born'):
1779 replace_dict['h_w_suffix']=',H'
1780 else:
1781 replace_dict['h_w_suffix']=''
1782
1783
1784 born_amps_and_wfs_calls , uvct_amp_calls = \
1785 fortran_model.get_born_ct_helas_calls(matrix_element, include_CT=True)
1786
1787
1788 born_amps_and_wfs_calls = born_amps_and_wfs_calls + uvct_amp_calls
1789
1790
1791
1792 self.turn_to_mp_calls(born_amps_and_wfs_calls)
1793
1794 file = open(os.path.join(self.template_dir,\
1795 'mp_born_amps_and_wfs.inc')).read()
1796
1797 if (not noSplit and (len(matrix_element.get_all_amplitudes())>2000)):
1798 file=self.split_HELASCALLS(writer,replace_dict,\
1799 'mp_helas_calls_split.inc',file,\
1800 born_amps_and_wfs_calls,'born_amps_and_wfs_calls',\
1801 'mp_helas_calls')
1802 else:
1803 replace_dict['born_amps_and_wfs_calls']=\
1804 '\n'.join(born_amps_and_wfs_calls)
1805
1806 file = file % replace_dict
1807 if writer:
1808
1809 writer.writelines(file)
1810 else:
1811
1812 return file
1813
1814
1815
1816
1817
1819 """Class to take care of exporting a set of loop matrix elements in the
1820 Fortran format which exploits the Pozzorini method of representing
1821 the loop numerators as polynomial to render its evaluations faster."""
1822
1823 template_dir=os.path.join(_file_path,'iolibs/template_files/loop_optimized')
1824
1825
1826 forbid_loop_grouping = False
1827
1828
1829
1830
1831
1832
1833
1834 all_tir=['pjfry','iregi','ninja','golem','samurai','collier']
1835
1836 - def __init__(self, dir_path = "", opt=None):
1837 """Initiate the LoopProcessOptimizedExporterFortranSA with directory
1838 information on where to find all the loop-related source files,
1839 like CutTools and TIR"""
1840
1841 super(LoopProcessOptimizedExporterFortranSA,self).__init__(dir_path, opt)
1842
1843
1844 self.tir_available_dict={'pjfry':True,'iregi':True,'golem':True,
1845 'samurai':True,'ninja':True,'collier':True}
1846
1847 for tir in self.all_tir:
1848 tir_dir="%s_dir"%tir
1849 if tir_dir in self.opt and not self.opt[tir_dir] is None:
1850
1851 tir_path = self.opt[tir_dir].strip()
1852 if tir_path.startswith('.'):
1853 tir_path = os.path.abspath(pjoin(MG5DIR,tir_path))
1854 setattr(self,tir_dir,tir_path)
1855 else:
1856 setattr(self,tir_dir,'')
1857
1865
1866 - def get_context(self,matrix_element, **opts):
1867 """ Additional contextual information which needs to be created for
1868 the optimized output."""
1869
1870 context = LoopProcessExporterFortranSA.get_context(self, matrix_element,
1871 **opts)
1872
1873
1874 try:
1875 context['ninja_supports_quad_prec'] = \
1876 misc.get_ninja_quad_prec_support(getattr(self,'ninja_dir'))
1877 except AttributeError:
1878 context['ninja_supports_quad_prec'] = False
1879
1880 for tir in self.all_tir:
1881 context['%s_available'%tir]=self.tir_available_dict[tir]
1882
1883 if tir not in ['golem','pjfry','iregi','samurai','ninja','collier']:
1884 raise MadGraph5Error("%s was not a TIR currently interfaced."%tir_name)
1885
1886 return context
1887
1889 """ Perform additional actions specific for this class when setting
1890 up the template with the copy_template function."""
1891
1892
1893 link_tir_libs=[]
1894 tir_libs=[]
1895 tir_include=[]
1896
1897 for tir in self.all_tir:
1898 tir_dir="%s_dir"%tir
1899 libpath=getattr(self,tir_dir)
1900 libname="lib%s.a"%tir
1901 tir_name=tir
1902 libpath = self.link_TIR(os.path.join(self.dir_path, 'lib'),
1903 libpath,libname,tir_name=tir_name)
1904 if libpath != "":
1905 if tir in ['ninja','pjfry','golem','samurai','collier']:
1906
1907 link_tir_libs.append('-L%s/ -l%s'%(libpath,tir))
1908 tir_libs.append('%s/lib%s.$(libext)'%(libpath,tir))
1909
1910 if tir in ['ninja']:
1911 if not any(os.path.isfile(pjoin(libpath,'libavh_olo.%s'%ext))
1912 for ext in ['a','dylib','so']):
1913 raise MadGraph5Error(
1914 "The OneLOop library 'libavh_olo.(a|dylib|so)' could no be found in path '%s'. Please place a symlink to it there."%libpath)
1915 link_tir_libs.append('-L%s/ -l%s'%(libpath,'avh_olo'))
1916 tir_libs.append('%s/lib%s.$(libext)'%(libpath,'avh_olo'))
1917 if tir in ['ninja','golem', 'samurai','collier']:
1918 trgt_path = pjoin(os.path.dirname(libpath),'include')
1919 if os.path.isdir(trgt_path):
1920 to_include = misc.find_includes_path(trgt_path,
1921 self.include_names[tir])
1922 else:
1923 to_include = None
1924
1925 if to_include is None and tir=='collier':
1926 to_include = misc.find_includes_path(
1927 pjoin(libpath,'modules'),self.include_names[tir])
1928 if to_include is None:
1929 logger.error(
1930 'Could not find the include directory for %s, looking in %s.\n' % (tir, str(trgt_path))+
1931 'Generation carries on but you will need to edit the include path by hand in the makefiles.')
1932 to_include = '<Not_found_define_it_yourself>'
1933 tir_include.append('-I %s'%str(to_include))
1934
1935
1936
1937
1938 name_map = {'golem':'golem95','samurai':'samurai',
1939 'ninja':'ninja','collier':'collier'}
1940 ln(to_include, starting_dir=pjoin(self.dir_path,'lib'),
1941 name='%s_include'%name_map[tir],abspath=True)
1942 ln(libpath, starting_dir=pjoin(self.dir_path,'lib'),
1943 name='%s_lib'%name_map[tir],abspath=True)
1944 else :
1945 link_tir_libs.append('-l%s'%tir)
1946 tir_libs.append('$(LIBDIR)lib%s.$(libext)'%tir)
1947
1948 MadLoop_makefile_definitions = pjoin(self.dir_path,'SubProcesses',
1949 'MadLoop_makefile_definitions')
1950 if os.path.isfile(MadLoop_makefile_definitions):
1951 os.remove(MadLoop_makefile_definitions)
1952
1953 calls = self.write_loop_makefile_definitions(
1954 writers.MakefileWriter(MadLoop_makefile_definitions),
1955 link_tir_libs,tir_libs, tir_include=tir_include)
1956
1957
1958
1959 MadLoopCommon = open(os.path.join(self.loop_dir,'StandAlone',
1960 "SubProcesses","MadLoopCommons.inc")).read()
1961 writer = writers.FortranWriter(os.path.join(self.dir_path,
1962 "SubProcesses","MadLoopCommons.f"))
1963 writer.writelines(MadLoopCommon%{
1964 'print_banner_commands':self.MadLoop_banner}, context={
1965 'collier_available':self.tir_available_dict['collier']})
1966 writer.close()
1967
1969 """ Does the same as the mother routine except that it also links
1970 coef_specs.inc in the HELAS folder."""
1971
1972 LoopProcessExporterFortranSA.link_files_from_Subprocesses(self,proc_name)
1973
1974
1975
1976 ln(os.path.join(self.dir_path,'Source','DHELAS','coef_specs.inc'),
1977 os.path.join(self.dir_path, 'SubProcesses', proc_name),
1978 abspath=False, cwd=None)
1979
1980
1981 - def link_TIR(self, targetPath,libpath,libname,tir_name='TIR'):
1982 """Link the TIR source directory inside the target path given
1983 in argument"""
1984
1985 if tir_name in ['pjfry','golem','samurai','ninja','collier']:
1986
1987 if (not isinstance(libpath,str)) or (not os.path.exists(libpath)) \
1988 or (not os.path.isfile(pjoin(libpath,libname))):
1989 if isinstance(libpath,str) and libpath != '' and \
1990 (not os.path.isfile(pjoin(libpath,libname))):
1991
1992 logger.warning("The %s reduction library could not be found"%tir_name\
1993 +" with PATH:%s specified in mg5_configuration.txt."%libpath\
1994 +" It will not be available.")
1995 self.tir_available_dict[tir_name]=False
1996 return ""
1997
1998 if tir_name in ['ninja','samurai'] and self.tir_available_dict[tir_name]:
1999
2000
2001 if os.path.isfile(pjoin(libpath,os.pardir,'AUTHORS')):
2002 try:
2003 version = open(pjoin(libpath,os.pardir,'VERSION'),'r').read()
2004 except IOError:
2005 version = None
2006 if version is None :
2007 logger.warning(
2008 "Your version of '%s' in \n %s\nseems too old %sto be compatible with MG5_aMC."
2009 %(tir_name, libpath ,'' if not version else '(v%s) '%version)+
2010 ("\nConsider updating it by hand or using the 'install' function of MG5_aMC." if tir_name!='samurai'
2011 else "\nAsk the authors for the latest version compatible with MG5_aMC."))
2012 else:
2013
2014 if (not isinstance(libpath,str)) or (not os.path.exists(libpath)):
2015
2016 logger.warning("The %s reduction library could not be found"%tir_name\
2017 +" with PATH:%s specified in mg5_configuration.txt."%libpath\
2018 +" It will not be available.")
2019 self.tir_available_dict[tir_name]=False
2020 return ""
2021
2022 if self.dependencies=='internal':
2023 if tir_name in ['pjfry','golem','samurai','ninja','collier']:
2024 self.tir_available_dict[tir_name]=False
2025 logger.info("When using the 'output_dependencies=internal' "+\
2026 " MG5_aMC option, the (optional) reduction library %s cannot be employed because"%tir_name+\
2027 " it is not distributed with the MG5_aMC code so that it cannot be copied locally.")
2028 return ""
2029 elif tir_name == "iregi":
2030
2031 new_iregi_path = pjoin(targetPath,os.path.pardir,'Source','IREGI')
2032 shutil.copytree(pjoin(libpath,os.path.pardir), new_iregi_path,
2033 symlinks=True)
2034
2035 current = misc.detect_current_compiler(
2036 pjoin(new_iregi_path,'src','makefile_ML5_lib'))
2037 new = 'gfortran' if self.fortran_compiler is None else \
2038 self.fortran_compiler
2039 if current != new:
2040 misc.mod_compilator(pjoin(new_iregi_path,'src'), new,current)
2041 misc.mod_compilator(pjoin(new_iregi_path,'src','oneloop'),
2042 new, current)
2043
2044
2045 ln(pjoin(targetPath,os.path.pardir,'Source','IREGI','src',
2046 libname),targetPath)
2047 else:
2048 logger.info("Tensor integral reduction library "+\
2049 "%s not implemented yet."%tir_name)
2050 return libpath
2051
2052 elif self.dependencies=='external':
2053 if not os.path.exists(pjoin(libpath,libname)) and tir_name=='iregi':
2054
2055 if 'heptools_install_dir' in self.opt and os.path.exists(pjoin(self.opt['heptools_install_dir'], 'IREGI')):
2056 misc.sprint('Going to use pre-compiled version of IREGI')
2057
2058 ln(os.path.join(self.opt['heptools_install_dir'],'IREGI','src','libiregi.a'),
2059 os.path.join(targetPath),abspath=True)
2060 return os.path.join(targetPath, 'libiregi.a')
2061
2062
2063
2064 logger.info('Compiling IREGI. This has to be done only once and'+\
2065 ' can take a couple of minutes.','$MG:BOLD')
2066
2067 current = misc.detect_current_compiler(os.path.join(\
2068 libpath,'makefile_ML5_lib'))
2069 new = 'gfortran' if self.fortran_compiler is None else \
2070 self.fortran_compiler
2071 if current != new:
2072 misc.mod_compilator(libpath, new,current)
2073 misc.mod_compilator(pjoin(libpath,'oneloop'), new, current)
2074
2075 misc.compile(cwd=libpath, job_specs = False)
2076
2077 if not os.path.exists(pjoin(libpath,libname)):
2078 logger.warning("IREGI could not be compiled. Check"+\
2079 "the compilation errors at %s. The related "%libpath+\
2080 "functionalities are turned off.")
2081 self.tir_available_dict[tir_name]=False
2082 return ""
2083
2084 if not tir_name in ['pjfry','golem','samurai','ninja','collier']:
2085 ln(os.path.join(libpath,libname),targetPath,abspath=True)
2086
2087 elif self.dependencies=='environment_paths':
2088
2089
2090 newlibpath = misc.which_lib(libname)
2091 if not newlibpath is None:
2092 logger.info('MG5_aMC is using %s installation found at %s.'%\
2093 (tir_name,newlibpath))
2094
2095 if not tir_name in ['pjfry','golem','samurai','ninja','collier']:
2096 ln(newlibpath,targetPath,abspath=True)
2097 self.tir_available_dict[tir_name]=True
2098 return os.path.dirname(newlibpath)
2099 else:
2100 logger.warning("Could not find the location of the file"+\
2101 " %s in you environment paths. The related "%libname+\
2102 "functionalities are turned off.")
2103 self.tir_available_dict[tir_name]=False
2104 return ""
2105
2106 self.tir_available_dict[tir_name]=True
2107 return libpath
2108
2110 """ Decides whether we must group loops or not for this matrix element"""
2111
2112
2113
2114 if self.forbid_loop_grouping:
2115 self.group_loops = False
2116 else:
2117 self.group_loops = (not self.get_context(matrix_element)['ComputeColorFlows'])\
2118 and matrix_element.get('processes')[0].get('has_born')
2119
2120 return self.group_loops
2121
2122 - def finalize(self, matrix_element, cmdhistory, MG5options, outputflag):
2128
2129
2130
2131 - def write_loop_matrix_element_v4(self, writer, matrix_element, fortran_model,
2132 group_number = None, proc_id = None, config_map = None):
2133 """ Writes loop_matrix.f, CT_interface.f,TIR_interface.f,GOLEM_inteface.f
2134 and loop_num.f only but with the optimized FortranModel.
2135 The arguments group_number and proc_id are just for the LoopInduced
2136 output with MadEvent and only used in get_ME_identifier."""
2137
2138
2139
2140 if writer:
2141 raise MadGraph5Error('Matrix output mode no longer supported.')
2142
2143 if not isinstance(fortran_model,\
2144 helas_call_writers.FortranUFOHelasCallWriter):
2145 raise MadGraph5Error('The optimized loop fortran output can only'+\
2146 ' work with a UFO Fortran model')
2147 OptimizedFortranModel=\
2148 helas_call_writers.FortranUFOHelasCallWriterOptimized(\
2149 fortran_model.get('model'),False)
2150
2151
2152 if not matrix_element.get('processes')[0].get('has_born') and \
2153 not self.compute_color_flows:
2154 logger.debug("Color flows will be employed despite the option"+\
2155 " 'loop_color_flows' being set to False because it is necessary"+\
2156 " for optimizations.")
2157
2158
2159
2160
2161
2162 matrix_element.compute_all_analytic_information(
2163 self.get_aloha_model(matrix_element.get('processes')[0].get('model')))
2164
2165 self.set_group_loops(matrix_element)
2166
2167
2168
2169 matrix_element.rep_dict = LoopProcessExporterFortranSA.\
2170 generate_general_replace_dict(self, matrix_element,
2171 group_number = group_number, proc_id = proc_id)
2172
2173
2174 self.set_optimized_output_specific_replace_dict_entries(matrix_element)
2175
2176
2177 proc_prefix_writer = writers.FortranWriter('proc_prefix.txt','w')
2178 proc_prefix_writer.write(matrix_element.rep_dict['proc_prefix'])
2179 proc_prefix_writer.close()
2180
2181 filename = 'loop_matrix.f'
2182 calls = self.write_loopmatrix(writers.FortranWriter(filename),
2183 matrix_element,
2184 OptimizedFortranModel)
2185
2186 filename = 'check_sa.f'
2187 self.write_check_sa(writers.FortranWriter(filename),matrix_element)
2188
2189 filename = 'polynomial.f'
2190 calls = self.write_polynomial_subroutines(
2191 writers.FortranWriter(filename),
2192 matrix_element)
2193
2194 filename = 'improve_ps.f'
2195 calls = self.write_improve_ps(writers.FortranWriter(filename),
2196 matrix_element)
2197
2198 filename = 'CT_interface.f'
2199 self.write_CT_interface(writers.FortranWriter(filename),\
2200 matrix_element)
2201
2202 filename = 'TIR_interface.f'
2203 self.write_TIR_interface(writers.FortranWriter(filename),
2204 matrix_element)
2205
2206 if 'golem' in self.tir_available_dict and self.tir_available_dict['golem']:
2207 filename = 'GOLEM_interface.f'
2208 self.write_GOLEM_interface(writers.FortranWriter(filename),
2209 matrix_element)
2210
2211 if 'collier' in self.tir_available_dict and self.tir_available_dict['collier']:
2212 filename = 'COLLIER_interface.f'
2213 self.write_COLLIER_interface(writers.FortranWriter(filename),
2214 matrix_element)
2215
2216 filename = 'loop_num.f'
2217 self.write_loop_num(writers.FortranWriter(filename),\
2218 matrix_element,OptimizedFortranModel)
2219
2220 filename = 'mp_compute_loop_coefs.f'
2221 self.write_mp_compute_loop_coefs(writers.FortranWriter(filename),\
2222 matrix_element,OptimizedFortranModel)
2223
2224 if self.get_context(matrix_element)['ComputeColorFlows']:
2225 filename = 'compute_color_flows.f'
2226 self.write_compute_color_flows(writers.FortranWriter(filename),
2227 matrix_element, config_map = config_map)
2228
2229
2230 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial()
2231 filename = 'nexternal.inc'
2232 self.write_nexternal_file(writers.FortranWriter(filename),
2233 nexternal, ninitial)
2234
2235
2236 filename = 'process_info.inc'
2237 self.write_process_info_file(writers.FortranWriter(filename),
2238 matrix_element)
2239
2240 if self.get_context(matrix_element)['TIRCaching']:
2241 filename = 'tir_cache_size.inc'
2242 self.write_tir_cache_size_include(writers.FortranWriter(filename))
2243
2244 return calls
2245
2247 """ Specify the entries of the replacement dictionary which are specific
2248 to the optimized output and only relevant to it (the more general entries
2249 are set in the the mother class LoopProcessExporterFortranSA."""
2250
2251 max_loop_rank=matrix_element.get_max_loop_rank()
2252 matrix_element.rep_dict['maxrank']=max_loop_rank
2253 matrix_element.rep_dict['loop_max_coefs']=\
2254 q_polynomial.get_number_of_coefs_for_rank(max_loop_rank)
2255 max_loop_vertex_rank=matrix_element.get_max_loop_vertex_rank()
2256 matrix_element.rep_dict['vertex_max_coefs']=\
2257 q_polynomial.get_number_of_coefs_for_rank(max_loop_vertex_rank)
2258
2259 matrix_element.rep_dict['nloopwavefuncs']=\
2260 matrix_element.get_number_of_loop_wavefunctions()
2261 max_spin=matrix_element.get_max_loop_particle_spin()
2262
2263 matrix_element.rep_dict['max_lwf_size']= 4 if max_spin <=3 else 16
2264 matrix_element.rep_dict['nloops']=len(\
2265 [1 for ldiag in matrix_element.get_loop_diagrams() for \
2266 lamp in ldiag.get_loop_amplitudes()])
2267
2268 if self.set_group_loops(matrix_element):
2269 matrix_element.rep_dict['nloop_groups']=\
2270 len(matrix_element.get('loop_groups'))
2271 else:
2272 matrix_element.rep_dict['nloop_groups']=\
2273 matrix_element.rep_dict['nloops']
2274
2276 """ Create the file containing the core subroutine called by CutTools
2277 which contains the Helas calls building the loop"""
2278
2279 replace_dict=copy.copy(matrix_element.rep_dict)
2280
2281 file = open(os.path.join(self.template_dir,'loop_num.inc')).read()
2282 file = file % replace_dict
2283 writer.writelines(file,context=self.get_context(matrix_element))
2284
2289
2291 """ Create the file TIR_interface.f which does NOT contain the subroutine
2292 defining the loop HELAS-like calls along with the general interfacing
2293 subroutine. """
2294
2295
2296 replace_dict=copy.copy(matrix_element.rep_dict)
2297
2298 file = open(os.path.join(self.template_dir,'TIR_interface.inc')).read()
2299
2300
2301
2302 loop_groups = matrix_element.get('loop_groups')
2303 has_HEFT_vertex = [False]*len(loop_groups)
2304 for i, (denom_structure, loop_amp_list) in enumerate(loop_groups):
2305 for lamp in loop_amp_list:
2306 final_lwf = lamp.get_final_loop_wavefunction()
2307 while not final_lwf is None:
2308
2309
2310 scalars = len([1 for wf in final_lwf.get('mothers') if
2311 wf.get('spin')==1])
2312 vectors = len([1 for wf in final_lwf.get('mothers') if
2313 wf.get('spin')==3 and wf.get('mass')=='ZERO'])
2314 if scalars>=1 and vectors>=1 and \
2315 scalars+vectors == len(final_lwf.get('mothers')):
2316 has_HEFT_vertex[i] = True
2317 break
2318 final_lwf = final_lwf.get_loop_mother()
2319 else:
2320 continue
2321 break
2322
2323 has_HEFT_list = []
2324 chunk_size = 9
2325 for k in range(0, len(has_HEFT_vertex), chunk_size):
2326 has_HEFT_list.append("DATA (HAS_AN_HEFT_VERTEX(I),I=%6r,%6r) /%s/" % \
2327 (k + 1, min(k + chunk_size, len(has_HEFT_vertex)),
2328 ','.join(['.TRUE.' if l else '.FALSE.' for l in
2329 has_HEFT_vertex[k:k + chunk_size]])))
2330 replace_dict['has_HEFT_list'] = '\n'.join(has_HEFT_list)
2331
2332 file = file % replace_dict
2333
2334 FPR = q_polynomial.FortranPolynomialRoutines(
2335 replace_dict['maxrank'],coef_format=replace_dict['complex_dp_format'],\
2336 sub_prefix=replace_dict['proc_prefix'])
2337 if self.tir_available_dict['pjfry']:
2338 file += '\n\n'+FPR.write_pjfry_mapping()
2339 if self.tir_available_dict['iregi']:
2340 file += '\n\n'+FPR.write_iregi_mapping()
2341
2342 if writer:
2343 writer.writelines(file,context=self.get_context(matrix_element))
2344 else:
2345 return file
2346
2348 """ Create the file COLLIER_interface.f"""
2349
2350
2351 replace_dict=copy.copy(matrix_element.rep_dict)
2352
2353 file = open(os.path.join(self.template_dir,'COLLIER_interface.inc')).read()
2354
2355 FPR = q_polynomial.FortranPolynomialRoutines(replace_dict['maxrank'],\
2356 coef_format=replace_dict['complex_dp_format'],\
2357 sub_prefix=replace_dict['proc_prefix'])
2358 map_definition = []
2359 collier_map = FPR.get_COLLIER_mapping()
2360
2361 chunk_size = 10
2362 for map_name, indices_list in \
2363 [('COEFMAP_ZERO',[c[0] for c in collier_map]),
2364 ('COEFMAP_ONE',[c[1] for c in collier_map]),
2365 ('COEFMAP_TWO',[c[2] for c in collier_map]),
2366 ('COEFMAP_THREE',[c[3] for c in collier_map])]:
2367 for k in range(0, len(indices_list), chunk_size):
2368 map_definition.append("DATA (%s(I),I=%3r,%3r) /%s/" % \
2369 (map_name,k, min(k + chunk_size, len(indices_list))-1,
2370 ','.join('%2r'%ind for ind in indices_list[k:k + chunk_size])))
2371
2372 replace_dict['collier_coefmap'] = '\n'.join(map_definition)
2373
2374 file = file % replace_dict
2375
2376 if writer:
2377 writer.writelines(file,context=self.get_context(matrix_element))
2378 else:
2379 return file
2380
2382 """ Create the file GOLEM_interface.f which does NOT contain the subroutine
2383 defining the loop HELAS-like calls along with the general interfacing
2384 subroutine. """
2385
2386
2387 replace_dict=copy.copy(matrix_element.rep_dict)
2388
2389
2390
2391 if not self.get_context(matrix_element)['AmplitudeReduction']:
2392 replace_dict['loop_induced_sqsoindex']=',SQSOINDEX'
2393 else:
2394 replace_dict['loop_induced_sqsoindex']=''
2395
2396 file = open(os.path.join(self.template_dir,'GOLEM_interface.inc')).read()
2397
2398 file = file % replace_dict
2399
2400 FPR = q_polynomial.FortranPolynomialRoutines(replace_dict['maxrank'],\
2401 coef_format=replace_dict['complex_dp_format'],\
2402 sub_prefix=replace_dict['proc_prefix'])
2403
2404 file += '\n\n'+FPR.write_golem95_mapping()
2405
2406 if writer:
2407 writer.writelines(file,context=self.get_context(matrix_element))
2408 else:
2409 return file
2410
2412 """ Subroutine to create all the subroutines relevant for handling
2413 the polynomials representing the loop numerator """
2414
2415
2416 IncWriter=writers.FortranWriter('loop_max_coefs.inc','w')
2417 IncWriter.writelines("""INTEGER LOOPMAXCOEFS
2418 PARAMETER (LOOPMAXCOEFS=%(loop_max_coefs)d)"""
2419 %matrix_element.rep_dict)
2420
2421
2422
2423
2424
2425 coef_specs_path = pjoin(self.dir_path, 'Source','DHELAS','coef_specs.inc')
2426 if not os.path.isfile(coef_specs_path):
2427 IncWriter=writers.FortranWriter(coef_specs_path,'w')
2428 IncWriter.writelines("""INTEGER MAXLWFSIZE
2429 PARAMETER (MAXLWFSIZE=%(max_lwf_size)d)
2430 INTEGER VERTEXMAXCOEFS
2431 PARAMETER (VERTEXMAXCOEFS=%(vertex_max_coefs)d)"""\
2432 %matrix_element.rep_dict)
2433 IncWriter.close()
2434
2435
2436 subroutines=[]
2437
2438
2439 replace_dict = copy.copy(matrix_element.rep_dict)
2440
2441 dp_routine = open(os.path.join(self.template_dir,'polynomial.inc')).read()
2442 mp_routine = open(os.path.join(self.template_dir,'polynomial.inc')).read()
2443
2444
2445 replace_dict['complex_format'] = replace_dict['complex_dp_format']
2446 replace_dict['real_format'] = replace_dict['real_dp_format']
2447 replace_dict['mp_prefix'] = ''
2448 replace_dict['kind'] = 8
2449 replace_dict['zero_def'] = '0.0d0'
2450 replace_dict['one_def'] = '1.0d0'
2451 dp_routine = dp_routine % replace_dict
2452
2453 replace_dict['complex_format'] = replace_dict['complex_mp_format']
2454 replace_dict['real_format'] = replace_dict['real_mp_format']
2455 replace_dict['mp_prefix'] = 'MP_'
2456 replace_dict['kind'] = 16
2457 replace_dict['zero_def'] = '0.0e0_16'
2458 replace_dict['one_def'] = '1.0e0_16'
2459 mp_routine = mp_routine % replace_dict
2460 subroutines.append(dp_routine)
2461 subroutines.append(mp_routine)
2462
2463
2464 poly_writer=q_polynomial.FortranPolynomialRoutines(
2465 matrix_element.get_max_loop_rank(),
2466 updater_max_rank = matrix_element.get_max_loop_vertex_rank(),
2467 sub_prefix=replace_dict['proc_prefix'],
2468 proc_prefix=replace_dict['proc_prefix'],
2469 mp_prefix='')
2470
2471 writer.writelines(poly_writer.write_polynomial_constant_module()+'\n')
2472
2473 mp_poly_writer=q_polynomial.FortranPolynomialRoutines(
2474 matrix_element.get_max_loop_rank(),
2475 updater_max_rank = matrix_element.get_max_loop_vertex_rank(),
2476 coef_format='complex*32', sub_prefix='MP_'+replace_dict['proc_prefix'],
2477 proc_prefix=replace_dict['proc_prefix'], mp_prefix='MP_')
2478
2479 subroutines.append(poly_writer.write_polynomial_evaluator())
2480 subroutines.append(mp_poly_writer.write_polynomial_evaluator())
2481
2482 subroutines.append(poly_writer.write_add_coefs())
2483 subroutines.append(mp_poly_writer.write_add_coefs())
2484
2485 subroutines.append(poly_writer.write_wl_merger())
2486 subroutines.append(mp_poly_writer.write_wl_merger())
2487 for wl_update in matrix_element.get_used_wl_updates():
2488
2489
2490
2491
2492 if wl_update[0]==wl_update[1]==1 or wl_update[0]==0 or wl_update[1]==0:
2493
2494
2495
2496 subroutines.append(poly_writer.write_expanded_wl_updater(\
2497 wl_update[0],wl_update[1]))
2498 subroutines.append(mp_poly_writer.write_expanded_wl_updater(\
2499 wl_update[0],wl_update[1]))
2500 elif wl_update[0] >= wl_update[1]:
2501
2502
2503
2504
2505 subroutines.append(poly_writer.write_compact_wl_updater(\
2506 wl_update[0],wl_update[1],loop_over_vertex_coefs_first=True))
2507 subroutines.append(mp_poly_writer.write_compact_wl_updater(\
2508 wl_update[0],wl_update[1],loop_over_vertex_coefs_first=True))
2509 else:
2510
2511
2512
2513
2514
2515
2516 subroutines.append(poly_writer.write_compact_wl_updater(\
2517 wl_update[0],wl_update[1],loop_over_vertex_coefs_first=False))
2518 subroutines.append(mp_poly_writer.write_compact_wl_updater(\
2519 wl_update[0],wl_update[1],loop_over_vertex_coefs_first=False))
2520
2521 writer.writelines('\n\n'.join(subroutines),
2522 context=self.get_context(matrix_element))
2523
2525 """Create the write_mp_compute_loop_coefs.f file."""
2526
2527 if not matrix_element.get('processes') or \
2528 not matrix_element.get('diagrams'):
2529 return 0
2530
2531
2532
2533 writers.FortranWriter.downcase = False
2534
2535 replace_dict = copy.copy(matrix_element.rep_dict)
2536
2537
2538 squared_orders = matrix_element.get_squared_order_contribs()
2539 split_orders = matrix_element.get('processes')[0].get('split_orders')
2540
2541 born_ct_helas_calls , uvct_helas_calls = \
2542 fortran_model.get_born_ct_helas_calls(matrix_element,
2543 squared_orders=squared_orders, split_orders=split_orders)
2544 self.turn_to_mp_calls(born_ct_helas_calls)
2545 self.turn_to_mp_calls(uvct_helas_calls)
2546 coef_construction, coef_merging = fortran_model.get_coef_construction_calls(\
2547 matrix_element,group_loops=self.group_loops,
2548 squared_orders=squared_orders,split_orders=split_orders)
2549
2550 coef_construction = [c % matrix_element.rep_dict for c
2551 in coef_construction]
2552 self.turn_to_mp_calls(coef_construction)
2553 self.turn_to_mp_calls(coef_merging)
2554
2555 file = open(os.path.join(self.template_dir,\
2556 'mp_compute_loop_coefs.inc')).read()
2557
2558
2559
2560 context = self.get_context(matrix_element)
2561 file=self.split_HELASCALLS(writer,replace_dict,\
2562 'mp_helas_calls_split.inc',file,born_ct_helas_calls,\
2563 'mp_born_ct_helas_calls','mp_helas_calls_ampb',
2564 required_so_broadcaster = 'MP_CT_REQ_SO_DONE',
2565 continue_label = 2000,
2566 momenta_array_name = 'MP_P',
2567 context=context)
2568 file=self.split_HELASCALLS(writer,replace_dict,\
2569 'mp_helas_calls_split.inc',file,uvct_helas_calls,\
2570 'mp_uvct_helas_calls','mp_helas_calls_uvct',
2571 required_so_broadcaster = 'MP_UVCT_REQ_SO_DONE',
2572 continue_label = 3000,
2573 momenta_array_name = 'MP_P',
2574 context=context)
2575 file=self.split_HELASCALLS(writer,replace_dict,\
2576 'mp_helas_calls_split.inc',file,coef_construction,\
2577 'mp_coef_construction','mp_coef_construction',
2578 required_so_broadcaster = 'MP_LOOP_REQ_SO_DONE',
2579 continue_label = 4000,
2580 momenta_array_name = 'MP_P',
2581 context=context)
2582
2583 replace_dict['mp_coef_merging']='\n'.join(coef_merging)
2584
2585 file = file % replace_dict
2586
2587
2588 writer.writelines(file,context=context)
2589
2591 """Writes out the files (Loop|Born)ColorFlowMatrix.dat corresponding
2592 to the color coefficients for JAMP(L|B)*JAMP(L|B)."""
2593
2594 res = []
2595 for line in range(len(col_matrix._col_basis1)):
2596 numerators = []
2597 denominators = []
2598 for row in range(len(col_matrix._col_basis2)):
2599 coeff = col_matrix.col_matrix_fixed_Nc[(line,row)]
2600 numerators.append('%6r'%coeff[0].numerator)
2601 denominators.append('%6r'%(
2602 coeff[0].denominator*(-1 if coeff[1] else 1)))
2603 res.append(' '.join(numerators))
2604 res.append(' '.join(denominators))
2605
2606 res.append('EOF')
2607
2608 writer.writelines('\n'.join(res))
2609
2612 """ Writes the file '(Loop|Born)ColorFlowCoefs.dat using the coefficients
2613 list of the color_amplitudes in the argument of this function."""
2614
2615 my_cs = color.ColorString()
2616
2617 res = []
2618
2619 for jamp_number, coeff_list in enumerate(color_amplitudes):
2620 my_cs.from_immutable(sorted(color_basis.keys())[jamp_number])
2621
2622 ordered_cs = color.ColorFactor([my_cs]).full_simplify()[0]
2623 res.append('%d # Coefficient for flow number %d with expr. %s'\
2624 %(len(coeff_list), jamp_number+1, repr(ordered_cs)))
2625
2626 line_element = []
2627
2628 for (coefficient, amp_number) in coeff_list:
2629 coef = self.cat_coeff(\
2630 coefficient[0],coefficient[1],coefficient[2],coefficient[3])
2631 line_element.append((coef[0].numerator,
2632 coef[0].denominator*(-1 if coef[1] else 1),amp_number))
2633
2634 line_element.sort(key=lambda el:el[2])
2635
2636 for i in range(3):
2637 res.append(' '.join('%6r'%elem[i] for elem in line_element))
2638
2639 res.append('EOF')
2640 writer.writelines('\n'.join(res))
2641
2643 """Writes the file compute_color_flows.f which uses the AMPL results
2644 from a common block to project them onto the color flow space so as
2645 to compute the JAMP quantities. For loop induced processes, this file
2646 will also contain a subroutine computing AMPL**2 for madevent
2647 multichanneling."""
2648
2649 loop_col_amps = matrix_element.get_loop_color_amplitudes()
2650 matrix_element.rep_dict['nLoopFlows'] = len(loop_col_amps)
2651
2652 dat_writer = open(pjoin('..','MadLoop5_resources',
2653 '%(proc_prefix)sLoopColorFlowCoefs.dat'
2654 %matrix_element.rep_dict),'w')
2655 self.write_color_flow_coefs_data_file(dat_writer,
2656 loop_col_amps, matrix_element.get('loop_color_basis'))
2657 dat_writer.close()
2658
2659 dat_writer = open(pjoin('..','MadLoop5_resources',
2660 '%(proc_prefix)sLoopColorFlowMatrix.dat'
2661 %matrix_element.rep_dict),'w')
2662 self.write_color_matrix_data_file(dat_writer,
2663 matrix_element.get('color_matrix'))
2664 dat_writer.close()
2665
2666 if matrix_element.get('processes')[0].get('has_born'):
2667 born_col_amps = matrix_element.get_born_color_amplitudes()
2668 matrix_element.rep_dict['nBornFlows'] = len(born_col_amps)
2669 dat_writer = open(pjoin('..','MadLoop5_resources',
2670 '%(proc_prefix)sBornColorFlowCoefs.dat'
2671 %matrix_element.rep_dict),'w')
2672 self.write_color_flow_coefs_data_file(dat_writer,
2673 born_col_amps, matrix_element.get('born_color_basis'))
2674 dat_writer.close()
2675
2676 dat_writer = open(pjoin('..','MadLoop5_resources',
2677 '%(proc_prefix)sBornColorFlowMatrix.dat'
2678 %matrix_element.rep_dict),'w')
2679 self.write_color_matrix_data_file(dat_writer,
2680 color_amp.ColorMatrix(matrix_element.get('born_color_basis')))
2681 dat_writer.close()
2682 else:
2683 matrix_element.rep_dict['nBornFlows'] = 0
2684
2685 replace_dict = copy.copy(matrix_element.rep_dict)
2686
2687
2688
2689 if self.get_context(matrix_element)['MadEventOutput']:
2690 self.get_amp2_lines(matrix_element, replace_dict, config_map)
2691 else:
2692 replace_dict['config_map_definition'] = ''
2693 replace_dict['config_index_map_definition'] = ''
2694 replace_dict['nmultichannels'] = 0
2695 replace_dict['nmultichannel_configs'] = 0
2696
2697
2698
2699 matrix_element.rep_dict['nmultichannels'] = \
2700 replace_dict['nmultichannels']
2701 matrix_element.rep_dict['nmultichannel_configs'] = \
2702 replace_dict['nmultichannel_configs']
2703
2704
2705 file = open(os.path.join(self.template_dir,\
2706 'compute_color_flows.inc')).read()%replace_dict
2707
2708 writer.writelines(file,context=self.get_context(matrix_element))
2709
2711 """ From the list of matrix element, or the single matrix element, derive
2712 the global quantities to write in global_coef_specs.inc"""
2713
2714 if isinstance(matrix_element_list, (group_subprocs.SubProcessGroupList,
2715 loop_helas_objects.LoopHelasProcess)):
2716 matrix_element_list = matrix_element_list.get_matrix_elements()
2717
2718 if isinstance(matrix_element_list, list):
2719 me_list = matrix_element_list
2720 else:
2721 me_list = [matrix_element_list]
2722
2723 if output_path is None:
2724 out_path = pjoin(self.dir_path,'SubProcesses','global_specs.inc')
2725 else:
2726 out_path = output_path
2727
2728 open(out_path,'w').write(
2729 """ integer MAXNEXTERNAL
2730 parameter(MAXNEXTERNAL=%d)
2731 integer OVERALLMAXRANK
2732 parameter(OVERALLMAXRANK=%d)
2733 integer NPROCS
2734 parameter(NPROCS=%d)"""%(
2735 max(me.get_nexternal_ninitial()[0] for me in me_list),
2736 max(me.get_max_loop_rank() for me in me_list),
2737 len(me_list)))
2738
2739
2740 - def fix_coef_specs(self, overall_max_lwf_spin, overall_max_loop_vert_rank):
2741 """ If processes with different maximum loop wavefunction size or
2742 different maximum loop vertex rank have to be output together, then
2743 the file 'coef.inc' in the HELAS Source folder must contain the overall
2744 maximum of these quantities. It is not safe though, and the user has
2745 been appropriatly warned at the output stage """
2746
2747
2748 coef_specs_path=os.path.join(self.dir_path,'Source','DHELAS',\
2749 'coef_specs.inc')
2750 os.remove(coef_specs_path)
2751
2752 spin_to_wf_size = {1:4,2:4,3:4,4:16,5:16}
2753 overall_max_lwf_size = spin_to_wf_size[overall_max_lwf_spin]
2754 overall_max_loop_vert_coefs = q_polynomial.get_number_of_coefs_for_rank(
2755 overall_max_loop_vert_rank)
2756
2757 IncWriter=writers.FortranWriter(coef_specs_path,'w')
2758 IncWriter.writelines("""INTEGER MAXLWFSIZE
2759 PARAMETER (MAXLWFSIZE=%(max_lwf_size)d)
2760 INTEGER VERTEXMAXCOEFS
2761 PARAMETER (VERTEXMAXCOEFS=%(vertex_max_coefs)d)"""\
2762 %{'max_lwf_size':overall_max_lwf_size,
2763 'vertex_max_coefs':overall_max_loop_vert_coefs})
2764 IncWriter.close()
2765
2768 """ Sets up the replacement dictionary for the writeout of the steering
2769 file check_sa.f"""
2770 if len(squared_orders)<1:
2771 matrix_element.rep_dict['print_so_loop_results']=\
2772 "write(*,*) 'No split orders defined.'"
2773 elif len(squared_orders)==1:
2774 matrix_element.rep_dict['set_coupling_target']=''
2775 matrix_element.rep_dict['print_so_loop_results']=\
2776 "write(*,*) 'All loop contributions are of split orders (%s)'"%(
2777 ' '.join(['%s=%d'%(split_orders[i],squared_orders[0][i]) \
2778 for i in range(len(split_orders))]))
2779 else:
2780 matrix_element.rep_dict['set_coupling_target']='\n'.join([
2781 '# Here we leave the default target squared split order to -1, meaning that we'+
2782 ' aim at computing all individual contributions. You can choose otherwise.',
2783 'call %(proc_prefix)sSET_COUPLINGORDERS_TARGET(-1)'%matrix_element.rep_dict])
2784 matrix_element.rep_dict['print_so_loop_results'] = '\n'.join([
2785 '\n'.join(["write(*,*) '%dL) Loop ME for orders (%s) :'"%((j+1),(' '.join(
2786 ['%s=%d'%(split_orders[i],so[i]) for i in range(len(split_orders))]))),
2787 "IF (PREC_FOUND(%d).NE.-1.0d0) THEN"%(j+1),
2788 "write(*,*) ' > accuracy = ',PREC_FOUND(%d)"%(j+1),
2789 "ELSE",
2790 "write(*,*) ' > accuracy = NA'",
2791 "ENDIF",
2792 "write(*,*) ' > finite = ',MATELEM(1,%d)"%(j+1),
2793 "write(*,*) ' > 1eps = ',MATELEM(2,%d)"%(j+1),
2794 "write(*,*) ' > 2eps = ',MATELEM(3,%d)"%(j+1)
2795 ]) for j, so in enumerate(squared_orders)])
2796 matrix_element.rep_dict['write_so_loop_results'] = '\n'.join(
2797 ["write (69,*) 'Split_Orders_Names %s'"%(' '.join(split_orders))]+
2798 ['\n'.join([
2799 "write (69,*) 'Loop_SO_Results %s'"%(' '.join(
2800 ['%d'%so_value for so_value in so])),
2801 "write (69,*) 'SO_Loop ACC ',PREC_FOUND(%d)"%(j+1),
2802 "write (69,*) 'SO_Loop FIN ',MATELEM(1,%d)"%(j+1),
2803 "write (69,*) 'SO_Loop 1EPS ',MATELEM(2,%d)"%(j+1),
2804 "write (69,*) 'SO_Loop 2EPS ',MATELEM(3,%d)"%(j+1),
2805 ]) for j, so in enumerate(squared_orders)])
2806
2807
2808 squared_born_so_orders = []
2809 for i, amp_order in enumerate(amps_orders['born_amp_orders']):
2810 for j in range(0,i+1):
2811 key = tuple([ord1 + ord2 for ord1,ord2 in \
2812 zip(amp_order[0],amps_orders['born_amp_orders'][j][0])])
2813 if not key in squared_born_so_orders:
2814 squared_born_so_orders.append(key)
2815 if len(squared_born_so_orders)<1:
2816 matrix_element.rep_dict['print_so_born_results'] = ''
2817 elif len(squared_born_so_orders)==1:
2818 matrix_element.rep_dict['print_so_born_results'] = \
2819 "write(*,*) 'All Born contributions are of split orders (%s)'"%(
2820 ' '.join(['%s=%d'%(split_orders[i],squared_born_so_orders[0][i])
2821 for i in range(len(split_orders))]))
2822 else:
2823 matrix_element.rep_dict['print_so_born_results'] = '\n'.join([
2824 "write(*,*) '%dB) Born ME for orders (%s) = ',MATELEM(0,%d)"%(j+1,' '.join(
2825 ['%s=%d'%(split_orders[i],so[i]) for i in range(len(split_orders))]),j+1)
2826 for j, so in enumerate(squared_born_so_orders)])
2827 matrix_element.rep_dict['write_so_born_results'] = '\n'.join(
2828 ['\n'.join([
2829 "write (69,*) 'Born_SO_Results %s'"%(' '.join(
2830 ['%d'%so_value for so_value in so])),
2831 "write (69,*) 'SO_Born BORN ',MATELEM(0,%d)"%(j+1),
2832 ]) for j, so in enumerate(squared_born_so_orders)])
2833
2834
2835 matrix_element.rep_dict['print_so_born_results'] += \
2836 '\nwrite (*,*) "---------------------------------"'
2837 matrix_element.rep_dict['print_so_loop_results'] += \
2838 '\nwrite (*,*) "---------------------------------"'
2839
2841 """Write the file 'tir_cache_size.inc' which sets the size of the TIR
2842 cache the the user wishes to employ and the default value for it.
2843 This can have an impact on MadLoop speed when using stability checks
2844 but also impacts in a non-negligible way MadLoop's memory footprint.
2845 It is therefore important that the user can chose its size."""
2846
2847
2848
2849
2850
2851 tir_cach_size = "parameter(TIR_CACHE_SIZE=1)"
2852 writer.writelines(tir_cach_size)
2853
2854 - def write_loopmatrix(self, writer, matrix_element, fortran_model, \
2855 write_auxiliary_files=True,):
2856 """Create the loop_matrix.f file."""
2857
2858 if not matrix_element.get('processes') or \
2859 not matrix_element.get('diagrams'):
2860 return 0
2861
2862
2863 writers.FortranWriter.downcase = False
2864
2865
2866
2867
2868
2869
2870
2871 squared_orders, amps_orders = matrix_element.get_split_orders_mapping()
2872
2873
2874
2875 sqso_contribs = [sqso[0] for sqso in squared_orders]
2876 split_orders = matrix_element.get('processes')[0].get('split_orders')
2877
2878
2879
2880 self.setup_check_sa_replacement_dictionary(matrix_element,
2881 split_orders,sqso_contribs,amps_orders)
2882
2883
2884
2885 overall_so_basis = list(set(
2886 [born_so[0] for born_so in amps_orders['born_amp_orders']]+
2887 [born_so[0] for born_so in amps_orders['loop_amp_orders']]))
2888
2889 order_hierarchy = matrix_element.get('processes')[0]\
2890 .get('model').get('order_hierarchy')
2891 if set(order_hierarchy.keys()).union(set(split_orders))==\
2892 set(order_hierarchy.keys()):
2893 overall_so_basis.sort(key= lambda so:
2894 sum([order_hierarchy[split_orders[i]]*order_power for \
2895 i, order_power in enumerate(so)]))
2896
2897
2898
2899 matrix_element.rep_dict['split_order_str_list'] = str(split_orders)
2900 matrix_element.rep_dict['nSO'] = len(split_orders)
2901 matrix_element.rep_dict['nSquaredSO'] = len(sqso_contribs)
2902 matrix_element.rep_dict['nAmpSO'] = len(overall_so_basis)
2903
2904 writers.FortranWriter('nsquaredSO.inc').writelines(
2905 """INTEGER NSQUAREDSO
2906 PARAMETER (NSQUAREDSO=%d)"""%matrix_element.rep_dict['nSquaredSO'])
2907
2908 replace_dict = copy.copy(matrix_element.rep_dict)
2909
2910
2911 replace_dict['ampsplitorders'] = '\n'.join(self.get_split_orders_lines(\
2912 overall_so_basis,'AMPSPLITORDERS'))
2913 replace_dict['SquaredSO'] = '\n'.join(self.get_split_orders_lines(\
2914 sqso_contribs,'SQPLITORDERS'))
2915
2916
2917 replace_dict['chosen_so_configs'] = self.set_chosen_SO_index(
2918 matrix_element.get('processes')[0],sqso_contribs)
2919
2920
2921
2922 ampSO_list=[-1]*sum(len(el[1]) for el in amps_orders['loop_amp_orders'])
2923 for SO in amps_orders['loop_amp_orders']:
2924 for amp_number in SO[1]:
2925 ampSO_list[amp_number-1]=overall_so_basis.index(SO[0])+1
2926
2927 replace_dict['loopAmpSO'] = '\n'.join(self.format_integer_list(
2928 ampSO_list,'LOOPAMPORDERS'))
2929 ampSO_list=[-1]*sum(len(el[1]) for el in amps_orders['born_amp_orders'])
2930 for SO in amps_orders['born_amp_orders']:
2931 for amp_number in SO[1]:
2932 ampSO_list[amp_number-1]=overall_so_basis.index(SO[0])+1
2933 replace_dict['BornAmpSO'] = '\n'.join(self.format_integer_list(
2934 ampSO_list,'BORNAMPORDERS'))
2935
2936
2937
2938 looplibs_av=['.TRUE.']
2939
2940
2941 for tir_lib in ['pjfry','iregi','golem','samurai','ninja','collier']:
2942 looplibs_av.append('.TRUE.' if tir_lib in self.all_tir and \
2943 self.tir_available_dict[tir_lib] else '.FALSE.')
2944 replace_dict['data_looplibs_av']=','.join(looplibs_av)
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954 replace_dict['hel_offset'] = 10000
2955
2956
2957
2958 den_factor_line = self.get_den_factor_line(matrix_element)
2959 replace_dict['den_factor_line'] = den_factor_line
2960
2961
2962
2963 replace_dict['hel_avg_factor'] = matrix_element.get_hel_avg_factor()
2964 replace_dict['beamone_helavgfactor'], replace_dict['beamtwo_helavgfactor'] =\
2965 matrix_element.get_beams_hel_avg_factor()
2966
2967 if write_auxiliary_files:
2968
2969 (CMNum,CMDenom) = self.get_color_matrix(matrix_element)
2970 CMWriter=open(pjoin('..','MadLoop5_resources',
2971 '%(proc_prefix)sColorNumFactors.dat'%matrix_element.rep_dict),'w')
2972 for ColorLine in CMNum:
2973 CMWriter.write(' '.join(['%d'%C for C in ColorLine])+'\n')
2974 CMWriter.close()
2975 CMWriter=open(pjoin('..','MadLoop5_resources',
2976 '%(proc_prefix)sColorDenomFactors.dat'%matrix_element.rep_dict),'w')
2977 for ColorLine in CMDenom:
2978 CMWriter.write(' '.join(['%d'%C for C in ColorLine])+'\n')
2979 CMWriter.close()
2980
2981
2982 HelConfigs=matrix_element.get_helicity_matrix()
2983 HelConfigWriter=open(pjoin('..','MadLoop5_resources',
2984 '%(proc_prefix)sHelConfigs.dat'%matrix_element.rep_dict),'w')
2985 for HelConfig in HelConfigs:
2986 HelConfigWriter.write(' '.join(['%d'%H for H in HelConfig])+'\n')
2987 HelConfigWriter.close()
2988
2989
2990 born_ct_helas_calls, uvct_helas_calls = \
2991 fortran_model.get_born_ct_helas_calls(matrix_element,
2992 squared_orders=squared_orders,split_orders=split_orders)
2993 coef_construction, coef_merging = fortran_model.get_coef_construction_calls(\
2994 matrix_element,group_loops=self.group_loops,
2995 squared_orders=squared_orders,split_orders=split_orders)
2996
2997 loop_CT_calls = fortran_model.get_loop_CT_calls(matrix_element,\
2998 group_loops=self.group_loops,
2999 squared_orders=squared_orders, split_orders=split_orders)
3000
3001 coef_construction = [c % matrix_element.rep_dict for c
3002 in coef_construction]
3003 loop_CT_calls = [lc % matrix_element.rep_dict for lc in loop_CT_calls]
3004
3005 file = open(os.path.join(self.template_dir,\
3006 'loop_matrix_standalone.inc')).read()
3007
3008
3009
3010 context = self.get_context(matrix_element)
3011 file=self.split_HELASCALLS(writer,replace_dict,\
3012 'helas_calls_split.inc',file,born_ct_helas_calls,\
3013 'born_ct_helas_calls','helas_calls_ampb',
3014 required_so_broadcaster = 'CT_REQ_SO_DONE',
3015 continue_label = 2000, context = context)
3016 file=self.split_HELASCALLS(writer,replace_dict,\
3017 'helas_calls_split.inc',file,uvct_helas_calls,\
3018 'uvct_helas_calls','helas_calls_uvct',
3019 required_so_broadcaster = 'UVCT_REQ_SO_DONE',
3020 continue_label = 3000, context=context)
3021 file=self.split_HELASCALLS(writer,replace_dict,\
3022 'helas_calls_split.inc',file,coef_construction,\
3023 'coef_construction','coef_construction',
3024 required_so_broadcaster = 'LOOP_REQ_SO_DONE',
3025 continue_label = 4000, context=context)
3026 file=self.split_HELASCALLS(writer,replace_dict,\
3027 'helas_calls_split.inc',file,loop_CT_calls,\
3028 'loop_CT_calls','loop_CT_calls',
3029 required_so_broadcaster = 'CTCALL_REQ_SO_DONE',
3030 continue_label = 5000, context=context)
3031
3032
3033
3034 matrix_element.rep_dict['loop_CT_calls']=replace_dict['loop_CT_calls']
3035 matrix_element.rep_dict['born_ct_helas_calls']=replace_dict['born_ct_helas_calls']
3036 matrix_element.rep_dict['uvct_helas_calls']=replace_dict['uvct_helas_calls']
3037 matrix_element.rep_dict['coef_construction']=replace_dict['coef_construction']
3038
3039 replace_dict['coef_merging']='\n'.join(coef_merging)
3040 file = file % replace_dict
3041 number_of_calls = len([call for call in loop_CT_calls if call.find('CALL LOOP') != 0])
3042 if writer:
3043
3044 writer.writelines(file,context=context)
3045 return number_of_calls
3046 else:
3047
3048 return number_of_calls, file
3049
3050
3051
3052
3055 """Class to take care of exporting a set of loop matrix elements in the
3056 Fortran format."""
3057
3058 default_opt = {'clean': False, 'complex_mass':False,
3059 'export_format':'madloop_matchbox', 'mp':True,
3060 'loop_dir':'', 'cuttools_dir':'',
3061 'fortran_compiler':'gfortran',
3062 'output_dependencies':'external',
3063 'sa_symmetry':True}
3064
3065
3066
3072
3073
3078
3079 - def get_ME_identifier(self, matrix_element, group_number = None, group_elem_number = None):
3080 """ To not mix notations between borns and virtuals we call it here also MG5 """
3081 return 'MG5_%d_'%matrix_element.get('processes')[0].get('id')
3082
3083
3084
3085
3086
3088 """ A class to specify all the functions common to LoopInducedExporterMEGroup
3089 and LoopInducedExporterMENoGroup (but not relevant for the original
3090 Madevent exporters)"""
3091
3092 madloop_makefile_name = 'makefile_MadLoop'
3093
3094
3096 """ Initialize the process, setting the proc characteristics."""
3097 super(LoopInducedExporterME, self).__init__(*args, **opts)
3098 self.proc_characteristic['loop_induced'] = True
3099
3100 - def get_context(self,*args,**opts):
3101 """ Make sure that the contextual variable MadEventOutput is set to
3102 True for this exporter"""
3103
3104 context = super(LoopInducedExporterME,self).get_context(*args,**opts)
3105 context['MadEventOutput'] = True
3106 return context
3107
3108
3109
3110
3112 """ write an equivalent of the MG4 proc_card in order that all the Madevent
3113 Perl script of MadEvent4 are still working properly for pure MG5 run.
3114 Not needed for StandAlone so we need to call the correct one
3115 """
3116
3117 return export_v4.ProcessExporterFortran.write_procdef_mg5(
3118 self, file_pos, modelname, process_str)
3119
3121 """ Returns the list of libraries to be compiling when compiling the
3122 SOURCE directory. It is different for loop_induced processes and
3123 also depends on the value of the 'output_dependencies' option"""
3124
3125 libraries_list = super(LoopInducedExporterME,self).\
3126 get_source_libraries_list()
3127
3128 if self.dependencies=='internal':
3129 libraries_list.append('$(LIBDIR)libcts.$(libext)')
3130 libraries_list.append('$(LIBDIR)libiregi.$(libext)')
3131
3132 return libraries_list
3133
3140
3151
3152
3153
3154
3155
3156 - def finalize(self, matrix_elements, history, mg5options, flaglist):
3157 """Function to finalize v4 directory, for inheritance.
3158 """
3159
3160 self.proc_characteristic['loop_induced'] = True
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170 self.write_global_specs(matrix_elements)
3171
3173 """Write the file 'tir_cache_size.inc' which sets the size of the TIR
3174 cache the the user wishes to employ and the default value for it.
3175 This can have an impact on MadLoop speed when using stability checks
3176 but also impacts in a non-negligible way MadLoop's memory footprint.
3177 It is therefore important that the user can chose its size."""
3178
3179
3180
3181
3182
3183 tir_cach_size = "parameter(TIR_CACHE_SIZE=2)"
3184 writer.writelines(tir_cach_size)
3185
3186 - def write_matrix_element_v4(self, writer, matrix_element, fortran_model,
3187 proc_id = None, config_map = [], subproc_number = None):
3188 """ Write it the wrapper to call the ML5 subroutine in the library."""
3189
3190
3191 if not matrix_element.get('processes') or \
3192 not matrix_element.get('diagrams'):
3193 return 0
3194
3195 if not isinstance(writer, writers.FortranWriter):
3196 raise writers.FortranWriter.FortranWriterError(\
3197 "writer not FortranWriter")
3198
3199 replace_dict = copy.copy(matrix_element.rep_dict)
3200
3201
3202 info_lines = self.get_mg5_info_lines()
3203 replace_dict['info_lines'] = info_lines
3204
3205
3206 process_lines = self.get_process_info_lines(matrix_element)
3207 replace_dict['process_lines'] = process_lines
3208
3209
3210
3211
3212
3213 if proc_id is None:
3214 replace_dict['proc_id'] = ''
3215 else:
3216 replace_dict['proc_id'] = proc_id
3217
3218
3219 replace_dict['hel_avg_factor'] = matrix_element.get_hel_avg_factor()
3220 replace_dict['beamone_helavgfactor'], replace_dict['beamtwo_helavgfactor'] =\
3221 matrix_element.get_beams_hel_avg_factor()
3222
3223
3224 helicity_lines = self.get_helicity_lines(matrix_element)
3225 replace_dict['helicity_lines'] = helicity_lines
3226
3227
3228
3229 ndiags = len(matrix_element.get('diagrams'))
3230 replace_dict['ndiags'] = ndiags
3231
3232
3233 replace_dict['define_iconfigs_lines'] = \
3234 """INTEGER MAPCONFIG(0:LMAXCONFIGS), ICONFIG
3235 COMMON/TO_MCONFIGS/MAPCONFIG, ICONFIG"""
3236
3237 if proc_id:
3238
3239
3240 replace_dict['define_iconfigs_lines'] += \
3241 """\nINTEGER SUBDIAG(MAXSPROC),IB(2)
3242 COMMON/TO_SUB_DIAG/SUBDIAG,IB"""
3243
3244 replace_dict['configID_in_matrix'] = "SUBDIAG(%s)"%proc_id
3245 else:
3246
3247
3248 replace_dict['configID_in_matrix'] = "MAPCONFIG(ICONFIG)"
3249
3250
3251 replace_dict['ml_prefix'] = \
3252 self.get_ME_identifier(matrix_element, subproc_number, proc_id)
3253
3254
3255 ncolor = max(1, len(matrix_element.get('color_basis')))
3256 replace_dict['ncolor'] = ncolor
3257
3258 n_tot_diags = len(matrix_element.get_loop_diagrams())
3259 replace_dict['n_tot_diags'] = n_tot_diags
3260
3261 file = open(pjoin(_file_path, \
3262 'iolibs/template_files/%s' % self.matrix_file)).read()
3263 file = file % replace_dict
3264
3265
3266 writer.writelines(file)
3267
3268 return 0, ncolor
3269
3271 """Make sure the function is implemented in the daughters"""
3272
3273 raise NotImplemented('The function get_amp2_lines must be called in '+\
3274 ' the daugthers of LoopInducedExporterME')
3275
3276
3277
3278
3281 """Class to take care of exporting a set of grouped loop induced matrix
3282 elements"""
3283
3284 matrix_file = "matrix_loop_induced_madevent_group.inc"
3285
3291
3298
3310
3324
3327 """Generate the Pn directory for a subprocess group in MadEvent,
3328 including the necessary matrix_N.f files, configs.inc and various
3329 other helper files"""
3330
3331
3332 calls = 0
3333 matrix_elements = subproc_group.get('matrix_elements')
3334 for ime, matrix_element in enumerate(matrix_elements):
3335 self.unique_id +=1
3336 calls += self.generate_loop_subprocess(matrix_element,fortran_model,
3337 group_number = group_number, proc_id = str(ime+1),
3338
3339 config_map = subproc_group.get('diagram_maps')[ime],
3340 unique_id=self.unique_id)
3341
3342
3343 export_v4.ProcessExporterFortranMEGroup.generate_subprocess_directory(
3344 self, subproc_group,fortran_model,group_number)
3345
3346 return calls
3347
3349 """Return the various replacement dictionary inputs necessary for the
3350 multichanneling amp2 definition for the loop-induced MadEvent output.
3351 """
3352
3353 if not config_map:
3354 raise MadGraph5Error('A multi-channeling configuration map is '+\
3355 ' necessary for the MadEvent Loop-induced output with grouping.')
3356
3357 nexternal, ninitial = matrix_element.get_nexternal_ninitial()
3358
3359 ret_lines = []
3360
3361
3362
3363 if isinstance(matrix_element, loop_helas_objects.LoopHelasMatrixElement):
3364 diagrams = matrix_element.get_loop_diagrams()
3365 else:
3366 diagrams = matrix_element.get('diagrams')
3367
3368
3369
3370
3371
3372 config_index_map = {}
3373
3374
3375 loop_amp_ID_to_config = {}
3376
3377
3378 config_to_diag_dict = {}
3379 for idiag, diag in enumerate(diagrams):
3380 try:
3381 config_to_diag_dict[config_map[idiag]].append(idiag)
3382 except KeyError:
3383 config_to_diag_dict[config_map[idiag]] = [idiag]
3384
3385 for config in sorted(config_to_diag_dict.keys()):
3386 config_index_map[config] = (config_to_diag_dict[config][0] + 1)
3387
3388
3389
3390 CT_amp_numbers = [a.get('number') for a in \
3391 sum([diagrams[idiag].get_ct_amplitudes() for \
3392 idiag in config_to_diag_dict[config]], [])]
3393
3394 for CT_amp_number in CT_amp_numbers:
3395 loop_amp_ID_to_config[CT_amp_number] = config
3396
3397
3398 loop_amp_numbers = [a.get('amplitudes')[0].get('number')
3399 for a in sum([diagrams[idiag].get_loop_amplitudes() for \
3400 idiag in config_to_diag_dict[config]], [])]
3401
3402 for loop_amp_number in loop_amp_numbers:
3403 loop_amp_ID_to_config[loop_amp_number] = config
3404
3405
3406
3407
3408
3409
3410 n_configs = max(config_index_map.keys())
3411 replace_dict['nmultichannel_configs'] = n_configs
3412
3413
3414
3415 conf_list = [(config_index_map[i] if i in config_index_map else 0) \
3416 for i in range(1,n_configs+1)]
3417
3418
3419 replace_dict['nmultichannels'] = len([_ for _ in conf_list if _!=0])
3420
3421
3422 res_list = []
3423 chunk_size = 6
3424 for k in range(0, len(conf_list), chunk_size):
3425 res_list.append("DATA (config_index_map(i),i=%6r,%6r) /%s/" % \
3426 (k + 1, min(k + chunk_size, len(conf_list)),
3427 ','.join(["%6r" % i for i in conf_list[k:k + chunk_size]])))
3428
3429 replace_dict['config_index_map_definition'] = '\n'.join(res_list)
3430
3431 res_list = []
3432 n_loop_amps = max(loop_amp_ID_to_config.keys())
3433 amp_list = [loop_amp_ID_to_config[i] for i in \
3434 sorted(loop_amp_ID_to_config.keys()) if i!=0]
3435 chunk_size = 6
3436 for k in range(0, len(amp_list), chunk_size):
3437 res_list.append("DATA (CONFIG_MAP(i),i=%6r,%6r) /%s/" % \
3438 (k + 1, min(k + chunk_size, len(amp_list)),
3439 ','.join(["%6r" % i for i in amp_list[k:k + chunk_size]])))
3440
3441 replace_dict['config_map_definition'] = '\n'.join(res_list)
3442
3443 return
3444
3445
3446
3447
3450 """Class to take care of exporting a set of individual loop induced matrix
3451 elements"""
3452
3453 matrix_file = "matrix_loop_induced_madevent.inc"
3454
3460
3467
3479
3492
3494 """Generate the Pn directory for a subprocess group in MadEvent,
3495 including the necessary matrix_N.f files, configs.inc and various
3496 other helper files"""
3497
3498 self.unique_id += 1
3499
3500 calls = self.generate_loop_subprocess(matrix_element,fortran_model,
3501 group_number = me_number,
3502 unique_id=self.unique_id)
3503
3504
3505
3506 calls += export_v4.ProcessExporterFortranME.generate_subprocess_directory(
3507 self, matrix_element, fortran_model, me_number)
3508 return calls
3509
3511 """Return the amp2(i) = sum(amp for diag(i))^2 lines"""
3512
3513 if config_map:
3514 raise MadGraph5Error('A configuration map should not be specified'+\
3515 ' for the Loop induced exporter without grouping.')
3516
3517 nexternal, ninitial = matrix_element.get_nexternal_ninitial()
3518
3519 vert_list = [max(diag.get_vertex_leg_numbers()) for diag in \
3520 matrix_element.get('diagrams') if diag.get_vertex_leg_numbers()!=[]]
3521 minvert = min(vert_list) if vert_list!=[] else 0
3522
3523
3524
3525
3526
3527 config_index_map = {}
3528
3529
3530 loop_amp_ID_to_config = {}
3531
3532 n_configs = 0
3533 for idiag, diag in enumerate(matrix_element.get('diagrams')):
3534
3535 use_for_multichanneling = True
3536 if diag.get_vertex_leg_numbers()!=[] and max(diag.get_vertex_leg_numbers()) > minvert:
3537 use_for_multichanneling = False
3538 curr_config = 0
3539 else:
3540 n_configs += 1
3541 curr_config = n_configs
3542
3543 if not use_for_multichanneling:
3544 if 0 not in config_index_map:
3545 config_index_map[0] = idiag + 1
3546 else:
3547 config_index_map[curr_config] = idiag + 1
3548
3549 CT_amps = [ a.get('number') for a in diag.get_ct_amplitudes()]
3550 for CT_amp in CT_amps:
3551 loop_amp_ID_to_config[CT_amp] = curr_config
3552
3553 Loop_amps = [a.get('amplitudes')[0].get('number')
3554 for a in diag.get_loop_amplitudes()]
3555 for Loop_amp in Loop_amps:
3556 loop_amp_ID_to_config[Loop_amp] = curr_config
3557
3558
3559 n_configs = len([k for k in config_index_map.keys() if k!=0])
3560 replace_dict['nmultichannel_configs'] = n_configs
3561
3562
3563
3564 replace_dict['nmultichannels'] = n_configs
3565
3566 res_list = []
3567 conf_list = [config_index_map[i] for i in sorted(config_index_map.keys())
3568 if i!=0]
3569 chunk_size = 6
3570 for k in range(0, len(conf_list), chunk_size):
3571 res_list.append("DATA (config_index_map(i),i=%6r,%6r) /%s/" % \
3572 (k + 1, min(k + chunk_size, len(conf_list)),
3573 ','.join(["%6r" % i for i in conf_list[k:k + chunk_size]])))
3574
3575 replace_dict['config_index_map_definition'] = '\n'.join(res_list)
3576
3577 res_list = []
3578 n_loop_amps = max(loop_amp_ID_to_config.keys())
3579 amp_list = [loop_amp_ID_to_config[i] for i in \
3580 sorted(loop_amp_ID_to_config.keys()) if i!=0]
3581 chunk_size = 6
3582 for k in range(0, len(amp_list), chunk_size):
3583 res_list.append("DATA (CONFIG_MAP(i),i=%6r,%6r) /%s/" % \
3584 (k + 1, min(k + chunk_size, len(amp_list)),
3585 ','.join(["%6r" % i for i in amp_list[k:k + chunk_size]])))
3586
3587 replace_dict['config_map_definition'] = '\n'.join(res_list)
3588