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 import copy
18 import fractions
19 import glob
20 import logging
21 import os
22 import sys
23 import re
24 import shutil
25 import subprocess
26 import itertools
27 import time
28 import datetime
29
30 import aloha
31
32 import madgraph.core.base_objects as base_objects
33 import madgraph.core.color_algebra as color
34 import madgraph.core.helas_objects as helas_objects
35 import madgraph.iolibs.drawing_eps as draw
36 import madgraph.iolibs.files as files
37 import madgraph.iolibs.group_subprocs as group_subprocs
38 import madgraph.various.misc as misc
39 import madgraph.various.q_polynomial as q_polynomial
40 import madgraph.iolibs.file_writers as writers
41 import madgraph.iolibs.gen_infohtml as gen_infohtml
42 import madgraph.iolibs.template_files as template_files
43 import madgraph.iolibs.ufo_expression_parsers as parsers
44 import madgraph.iolibs.export_v4 as export_v4
45 import madgraph.various.diagram_symmetry as diagram_symmetry
46 import madgraph.various.process_checks as process_checks
47 import madgraph.various.progressbar as pbar
48 import madgraph.core.color_amp as color_amp
49 import madgraph.iolibs.helas_call_writers as helas_call_writers
50 import models.check_param_card as check_param_card
51 from madgraph.loop.loop_base_objects import LoopDiagram
52 from madgraph.loop.MadLoopBannerStyles import MadLoopBannerStyles
53
54 pjoin = os.path.join
55
56 import aloha.create_aloha as create_aloha
57 import models.write_param_card as param_writer
58 from madgraph import MadGraph5Error, MG5DIR, InvalidCmd
59 from madgraph.iolibs.files import cp, ln, mv
60 pjoin = os.path.join
61 _file_path = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0] + '/'
62 logger = logging.getLogger('madgraph.loop_exporter')
63
64
65
66
68 """ Class to define general helper functions to the different
69 loop fortran exporters (ME, SA, MEGroup, etc..) which will inherit both
70 from this class AND from the corresponding ProcessExporterFortran(ME,SA,...).
71 It plays the same role as ProcessExporterFrotran and simply defines here
72 loop-specific helpers functions necessary for all loop exporters.
73 Notice that we do not have LoopExporterFortran inheriting from
74 ProcessExporterFortran but give access to arguments like dir_path and
75 clean using options. This avoids method resolution object ambiguity"""
76
77 - def __init__(self, mgme_dir="", dir_path = "", opt=None):
78 """Initiate the LoopExporterFortran with directory information on where
79 to find all the loop-related source files, like CutTools"""
80
81 if opt:
82 self.opt = opt
83 else:
84 self.opt = {'clean': False, 'complex_mass':False,
85 'export_format':'madloop', 'mp':True,
86 'loop_dir':'', 'cuttools_dir':'',
87 'fortran_compiler':'gfortran',
88 'output_dependencies':'external'}
89
90 self.loop_dir = self.opt['loop_dir']
91 self.cuttools_dir = self.opt['cuttools_dir']
92 self.fortran_compiler = self.opt['fortran_compiler']
93 self.dependencies = self.opt['output_dependencies']
94
95 super(LoopExporterFortran,self).__init__(mgme_dir, dir_path, self.opt)
96
97
159
161 """ Caches the aloha model created here as an attribute of the loop
162 exporter so that it can later be used in the LoopHelasMatrixElement
163 in the function compute_all_analytic_information for recycling aloha
164 computations across different LoopHelasMatrixElements steered by the
165 same loop exporter.
166 """
167 if not hasattr(self, 'aloha_model'):
168 self.aloha_model = create_aloha.AbstractALOHAModel(model.get('name'))
169 return self.aloha_model
170
171
172
173
175 """Write the cts_mprec.h and cts_mpc.h"""
176
177 file = open(os.path.join(self.cuttools_dir, 'src/cts/cts_mprec.h')).read()
178 writer_mprec.writelines(file)
179
180 file = open(os.path.join(self.cuttools_dir, 'src/cts/cts_mpc.h')).read()
181 file = file.replace('&','')
182 writer_mpc.writelines(file)
183
184 return True
185
186
187
188
191
192 """Class to take care of exporting a set of loop matrix elements in the
193 Fortran format."""
194
195 template_dir=os.path.join(_file_path,'iolibs/template_files/loop')
196
197 MadLoop_banner = MadLoopBannerStyles.get_MadLoop_Banner(
198 style='classic2', color='green',
199 top_frame_char = '=', bottom_frame_char = '=',
200 left_frame_char = '{',right_frame_char = '}',
201 print_frame=True, side_margin = 7, up_margin = 1)
202
204 """Additional actions needed for setup of Template
205 """
206 super(LoopProcessExporterFortranSA, self).copy_v4template(modelname)
207
208
209 cpfiles= ["Source/makefile",
210 "Cards/MadLoopParams.dat",
211 "SubProcesses/MadLoopParamReader.f",
212 "SubProcesses/MadLoopParams.inc"]
213
214
215 link_tir_libs=[]
216 tir_libs=[]
217 cwd = os.getcwd()
218 dirpath = os.path.join(self.dir_path, 'SubProcesses')
219 try:
220 os.chdir(dirpath)
221 except os.error:
222 logger.error('Could not cd to directory %s' % dirpath)
223 return 0
224 filename = 'makefile'
225 calls = self.write_makefile_TIR(writers.MakefileWriter(filename),
226 link_tir_libs,tir_libs)
227
228 os.chdir(cwd)
229
230 for file in cpfiles:
231 shutil.copy(os.path.join(self.loop_dir,'StandAlone/', file),
232 os.path.join(self.dir_path, file))
233
234
235 MadLoopCommon = open(os.path.join(self.loop_dir,'StandAlone',
236 "SubProcesses","MadLoopCommons.inc")).read()
237 writer = writers.FortranWriter(os.path.join(self.dir_path,
238 "SubProcesses","MadLoopCommons.f"))
239 writer.writelines(MadLoopCommon%{
240 'print_banner_commands':self.MadLoop_banner})
241 writer.close()
242
243
244
245 if not os.path.exists(pjoin(self.dir_path,'SubProcesses',
246 'MadLoop5_resources')):
247 cp(pjoin(self.loop_dir,'StandAlone','SubProcesses',
248 'MadLoop5_resources'),pjoin(self.dir_path,'SubProcesses'))
249
250
251 ln(pjoin(self.dir_path,'Cards','MadLoopParams.dat'),
252 pjoin(self.dir_path,'SubProcesses','MadLoop5_resources'))
253 ln(pjoin(self.dir_path,'Cards','param_card.dat'),
254 pjoin(self.dir_path,'SubProcesses','MadLoop5_resources'))
255 ln(pjoin(self.dir_path,'Cards','ident_card.dat'),
256 pjoin(self.dir_path,'SubProcesses','MadLoop5_resources'))
257
258
259
260 if os.path.isfile(pjoin(self.dir_path,'SubProcesses','check_sa.f')):
261 os.remove(pjoin(self.dir_path,'SubProcesses','check_sa.f'))
262
263 cwd = os.getcwd()
264 dirpath = os.path.join(self.dir_path, 'SubProcesses')
265 try:
266 os.chdir(dirpath)
267 except os.error:
268 logger.error('Could not cd to directory %s' % dirpath)
269 return 0
270
271
272 self.write_mp_files(writers.FortranWriter('cts_mprec.h'),\
273 writers.FortranWriter('cts_mpc.h'))
274
275
276 os.chdir(cwd)
277
278
279 super(LoopProcessExporterFortranSA, self).link_CutTools(self.dir_path)
280
281
282
284 """ Create the file makefile which links to the TIR libraries."""
285
286 file = open(os.path.join(self.loop_dir,'StandAlone',
287 'SubProcesses','makefile.inc')).read()
288 replace_dict={}
289 replace_dict['link_tir_libs']=' '.join(link_tir_libs)
290 replace_dict['tir_libs']=' '.join(tir_libs)
291 replace_dict['dotf']='%.f'
292 replace_dict['doto']='%.o'
293 replace_dict['tir_include']=' '.join(tir_include)
294 file=file%replace_dict
295 if writer:
296 writer.writelines(file)
297 else:
298 return file
299
308
309
311 """ A function returning a string uniquely identifying the matrix
312 element given in argument so that it can be used as a prefix to all
313 MadLoop5 subroutines and common blocks related to it. This allows
314 to compile several processes into one library as requested by the
315 BLHA (Binoth LesHouches Accord) guidelines. """
316
317
318
319 return 'ML5_%d_'%matrix_element.get('processes')[0].get('id')
320
321
322
323
325 """ Different daughter classes might want different compilers.
326 Here, the gfortran compiler is used throughout the compilation
327 (mandatory for CutTools written in f90) """
328 if not compiler is None and not any([name in compiler for name in \
329 ['gfortran','ifort']]):
330 logger.info('For loop processes, the compiler must be fortran90'+\
331 'compatible, like gfortran.')
332 self.set_compiler('gfortran',True)
333 else:
334 self.set_compiler(compiler)
335
337
338
339
340
341
342
343
344 MP=re.compile(r"(?P<toSub>^.*CALL\s+)",re.IGNORECASE | re.MULTILINE)
345
346 def replaceWith(match_obj):
347 return match_obj.group('toSub')+'MP_'
348
349 DCMPLX=re.compile(r"DCMPLX\((?P<toSub>([^\)]*))\)",\
350 re.IGNORECASE | re.MULTILINE)
351
352 for i, helas_call in enumerate(helas_calls_list):
353 new_helas_call=MP.sub(replaceWith,helas_call)
354 helas_calls_list[i]=DCMPLX.sub(r"CMPLX(\g<toSub>,KIND=16)",\
355 new_helas_call)
356
358 """ In the loop output, we don't need the files from the Source folder """
359 pass
360
362 """ Add the linking of the additional model files for multiple precision
363 """
364 super(LoopProcessExporterFortranSA, self).make_model_symbolic_link()
365 model_path = self.dir_path + '/Source/MODEL/'
366 ln(model_path + '/mp_coupl.inc', self.dir_path + '/SubProcesses')
367 ln(model_path + '/mp_coupl_same_name.inc', self.dir_path + '/SubProcesses')
368
370 """ Compiles the additional dependences for loop (such as CutTools)."""
371 super(LoopProcessExporterFortranSA, self).make()
372
373
374 libdir = os.path.join(self.dir_path,'lib')
375 sourcedir = os.path.join(self.dir_path,'Source')
376 if self.dependencies=='internal':
377 if not os.path.exists(os.path.realpath(pjoin(libdir, 'libcts.a'))) or \
378 not os.path.exists(os.path.realpath(pjoin(libdir, 'mpmodule.mod'))):
379 if os.path.exists(pjoin(sourcedir,'CutTools')):
380 logger.info('Compiling CutTools (can take a couple of minutes) ...')
381 misc.compile(['CutTools'], cwd = sourcedir)
382 logger.info(' ...done.')
383 else:
384 raise MadGraph5Error('Could not compile CutTools because its'+\
385 ' source directory could not be found in the SOURCE folder.')
386 if not os.path.exists(os.path.realpath(pjoin(libdir, 'libcts.a'))) or \
387 not os.path.exists(os.path.realpath(pjoin(libdir, 'mpmodule.mod'))):
388 raise MadGraph5Error('CutTools compilation failed.')
389
390
391
392 compiler_log_path = pjoin(os.path.dirname((os.path.realpath(pjoin(
393 libdir, 'libcts.a')))),'compiler_version.log')
394 if os.path.exists(compiler_log_path):
395 compiler_version_used = open(compiler_log_path,'r').read()
396 if not str(misc.get_gfortran_version(misc.detect_current_compiler(\
397 pjoin(sourcedir,'make_opts')))) in compiler_version_used:
398 if os.path.exists(pjoin(sourcedir,'CutTools')):
399 logger.info('CutTools was compiled with a different fortran'+\
400 ' compiler. Re-compiling it now...')
401 misc.compile(['cleanCT'], cwd = sourcedir)
402 misc.compile(['CutTools'], cwd = sourcedir)
403 logger.info(' ...done.')
404 else:
405 raise MadGraph5Error("CutTools installation in %s"\
406 %os.path.realpath(pjoin(libdir, 'libcts.a'))+\
407 " seems to have been compiled with a different compiler than"+\
408 " the one specified in MG5_aMC. Please recompile CutTools.")
409
410 - def cat_coeff(self, ff_number, frac, is_imaginary, Nc_power, Nc_value=3):
411 """Concatenate the coefficient information to reduce it to
412 (fraction, is_imaginary) """
413
414 total_coeff = ff_number * frac * fractions.Fraction(Nc_value) ** Nc_power
415
416 return (total_coeff, is_imaginary)
417
419 """ Returns a list with element 'i' being a list of tuples corresponding
420 to all apparition of amplitude number 'i' in the jamp number 'j'
421 with coeff 'coeff_j'. The format of each tuple describing an apparition
422 is (j, coeff_j). where coeff_j is of the form (Fraction, is_imag)."""
423
424 if(isinstance(col_amps,list)):
425 if(col_amps and isinstance(col_amps[0],list)):
426 color_amplitudes=col_amps
427 else:
428 raise MadGraph5Error, "Incorrect col_amps argument passed to get_amp_to_jamp_map"
429 else:
430 raise MadGraph5Error, "Incorrect col_amps argument passed to get_amp_to_jamp_map"
431
432
433 res_list = [[] for i in range(n_amps)]
434 for i, coeff_list in enumerate(color_amplitudes):
435 for (coefficient, amp_number) in coeff_list:
436 res_list[amp_number-1].append((i,self.cat_coeff(\
437 coefficient[0],coefficient[1],coefficient[2],coefficient[3])))
438
439 return res_list
440
442 """Return the color matrix definition lines. This color matrix is of size
443 NLOOPAMPSxNBORNAMPS and allows for squaring individually each Loop and Born
444 amplitude."""
445
446 logger.info('Computing diagram color coefficients')
447
448
449
450
451
452 ampl_to_jampl=self.get_amp_to_jamp_map(\
453 matrix_element.get_loop_color_amplitudes(),
454 matrix_element.get_number_of_loop_amplitudes())
455 if matrix_element.get('processes')[0].get('has_born'):
456 ampb_to_jampb=self.get_amp_to_jamp_map(\
457 matrix_element.get_born_color_amplitudes(),
458 matrix_element.get_number_of_born_amplitudes())
459 else:
460 ampb_to_jampb=ampl_to_jampl
461
462 if matrix_element.get('color_matrix'):
463 ColorMatrixDenom = \
464 matrix_element.get('color_matrix').get_line_denominators()
465 ColorMatrixNum = [ matrix_element.get('color_matrix').\
466 get_line_numerators(index, denominator) for
467 (index, denominator) in enumerate(ColorMatrixDenom) ]
468 else:
469 ColorMatrixDenom= [1]
470 ColorMatrixNum = [[1]]
471
472
473 ColorMatrixNumOutput=[]
474 ColorMatrixDenomOutput=[]
475
476
477
478 start = time.time()
479 progress_bar = None
480 time_info = False
481 for i, jampl_list in enumerate(ampl_to_jampl):
482
483
484
485 if i==10:
486 elapsed_time = time.time()-start
487 t = int(len(ampl_to_jampl)*(elapsed_time/10.0))
488 if t > 20:
489 time_info = True
490 logger.info('The color factors computation will take '+\
491 ' about %s to run. '%str(datetime.timedelta(seconds=t))+\
492 'Started on %s.'%datetime.datetime.now().strftime(\
493 "%d-%m-%Y %H:%M"))
494 if logger.getEffectiveLevel()<logging.WARNING:
495 widgets = ['Color computation:', pbar.Percentage(), ' ',
496 pbar.Bar(),' ', pbar.ETA(), ' ']
497 progress_bar = pbar.ProgressBar(widgets=widgets,
498 maxval=len(ampl_to_jampl),fd=sys.stdout)
499 if progress_bar!=None:
500 progress_bar.update(i+1)
501 line_num=[]
502 line_denom=[]
503
504
505
506
507
508
509
510
511 if len(jampl_list)==0:
512 line_num=[0]*len(ampb_to_jampb)
513 line_denom=[1]*len(ampb_to_jampb)
514 ColorMatrixNumOutput.append(line_num)
515 ColorMatrixDenomOutput.append(line_denom)
516 continue
517
518 for jampb_list in ampb_to_jampb:
519 real_num=0
520 imag_num=0
521 common_denom=color_amp.ColorMatrix.lcmm(*[abs(ColorMatrixDenom[jampl]*
522 ampl_coeff[0].denominator*ampb_coeff[0].denominator) for
523 ((jampl, ampl_coeff),(jampb,ampb_coeff)) in
524 itertools.product(jampl_list,jampb_list)])
525 for ((jampl, ampl_coeff),(jampb, ampb_coeff)) in \
526 itertools.product(jampl_list,jampb_list):
527
528
529 buff_num=ampl_coeff[0].numerator*\
530 ampb_coeff[0].numerator*ColorMatrixNum[jampl][jampb]*\
531 abs(common_denom)/(ampl_coeff[0].denominator*\
532 ampb_coeff[0].denominator*ColorMatrixDenom[jampl])
533
534
535
536 if ampl_coeff[1] and ampb_coeff[1]:
537 real_num=real_num+buff_num
538 elif not ampl_coeff[1] and not ampb_coeff[1]:
539 real_num=real_num+buff_num
540 elif not ampl_coeff[1] and ampb_coeff[1]:
541 imag_num=imag_num-buff_num
542 else:
543 imag_num=imag_num+buff_num
544 assert not (real_num!=0 and imag_num!=0), "MadGraph5_aMC@NLO found a "+\
545 "color matrix element which has both a real and imaginary part."
546 if imag_num!=0:
547 res=fractions.Fraction(imag_num,common_denom)
548 line_num.append(res.numerator)
549
550
551 line_denom.append(res.denominator*-1)
552 else:
553 res=fractions.Fraction(real_num,common_denom)
554 line_num.append(res.numerator)
555
556 line_denom.append(res.denominator)
557
558 ColorMatrixNumOutput.append(line_num)
559 ColorMatrixDenomOutput.append(line_denom)
560
561 if time_info:
562 logger.info('Finished on %s.'%datetime.datetime.now().strftime(\
563 "%d-%m-%Y %H:%M"))
564 if progress_bar!=None:
565 progress_bar.finish()
566
567 return (ColorMatrixNumOutput,ColorMatrixDenomOutput)
568
569
570
571
572
574 """Generate the Pxxxxx directory for a loop subprocess in MG4 standalone,
575 including the necessary loop_matrix.f, born_matrix.f and include files.
576 Notice that this is too different from generate_subprocess_directory_v4
577 so that there is no point reusing this mother function."""
578
579 cwd = os.getcwd()
580
581 dirpath = os.path.join(self.dir_path, 'SubProcesses', \
582 "P%s" % matrix_element.get('processes')[0].shell_string())
583
584 try:
585 os.mkdir(dirpath)
586 except os.error as error:
587 logger.warning(error.strerror + " " + dirpath)
588
589 try:
590 os.chdir(dirpath)
591 except os.error:
592 logger.error('Could not cd to directory %s' % dirpath)
593 return 0
594
595 logger.info('Creating files in directory %s' % dirpath)
596
597
598 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial()
599
600 calls=self.write_matrix_element_v4(None,matrix_element,fortran_model)
601
602
603
604
605
606 if matrix_element.get('processes')[0].get('has_born'):
607 filename = 'born_matrix.f'
608 calls = self.write_bornmatrix(
609 writers.FortranWriter(filename),
610 matrix_element,
611 fortran_model)
612
613 filename = 'nexternal.inc'
614 self.write_nexternal_file(writers.FortranWriter(filename),
615 (nexternal-2), ninitial)
616
617 filename = 'pmass.inc'
618 self.write_pmass_file(writers.FortranWriter(filename),
619 matrix_element)
620
621 filename = 'ngraphs.inc'
622 self.write_ngraphs_file(writers.FortranWriter(filename),
623 len(matrix_element.get_all_amplitudes()))
624
625
626
627 loop_diags = [loop_diag for loop_diag in\
628 matrix_element.get('base_amplitude').get('loop_diagrams')\
629 if isinstance(loop_diag,LoopDiagram) and \
630 loop_diag.get('type') > 0]
631 if len(loop_diags)>5000:
632 logger.info("There are more than 5000 loop diagrams."+\
633 "Only the first 5000 are drawn.")
634 filename = "loop_matrix.ps"
635 plot = draw.MultiEpsDiagramDrawer(base_objects.DiagramList(
636 loop_diags[:5000]),filename,
637 model=matrix_element.get('processes')[0].get('model'),amplitude='')
638 logger.info("Drawing loop Feynman diagrams for " + \
639 matrix_element.get('processes')[0].nice_string())
640 plot.draw()
641
642 if matrix_element.get('processes')[0].get('has_born'):
643 filename = "born_matrix.ps"
644 plot = draw.MultiEpsDiagramDrawer(matrix_element.get('base_amplitude').\
645 get('born_diagrams'),
646 filename,
647 model=matrix_element.get('processes')[0].\
648 get('model'),
649 amplitude='')
650 logger.info("Generating born Feynman diagrams for " + \
651 matrix_element.get('processes')[0].nice_string(\
652 print_weighted=False))
653 plot.draw()
654
655 self.link_files_from_Subprocesses(proc_name=\
656 matrix_element.get('processes')[0].shell_string())
657
658
659 os.chdir(cwd)
660
661 if not calls:
662 calls = 0
663 return calls
664
666 """ To link required files from the Subprocesses directory to the
667 different P* ones"""
668
669 linkfiles = ['coupl.inc', 'makefile',
670 'cts_mprec.h', 'cts_mpc.h', 'mp_coupl.inc',
671 'mp_coupl_same_name.inc',
672 'MadLoopParamReader.f','MadLoopCommons.f',
673 'MadLoopParams.inc']
674
675 for file in linkfiles:
676 ln('../%s' % file)
677
678
679 ln('../../lib/mpmodule.mod')
680
681
682 ln('../MadLoop5_resources')
683
685 """Generates the entries for the general replacement dictionary used
686 for the different output codes for this exporter"""
687
688 dict={}
689
690
691
692 dict['proc_prefix'] = self.get_ME_identifier(matrix_element)
693
694
695
696 dict['proc_id'] = ''
697
698 info_lines = self.get_mg5_info_lines()
699 dict['info_lines'] = info_lines
700
701 process_lines = self.get_process_info_lines(matrix_element)
702 dict['process_lines'] = process_lines
703
704 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial()
705 dict['nexternal'] = nexternal-2
706
707 ncomb = matrix_element.get_helicity_combinations()
708 dict['ncomb'] = ncomb
709
710 nloopamps = matrix_element.get_number_of_loop_amplitudes()
711 dict['nloopamps'] = nloopamps
712
713 nctamps = matrix_element.get_number_of_CT_amplitudes()
714 dict['nctamps'] = nctamps
715
716 nwavefuncs = matrix_element.get_number_of_external_wavefunctions()
717 dict['nwavefuncs'] = nwavefuncs
718
719 dict['real_dp_format']='real*8'
720 dict['real_mp_format']='real*16'
721
722 dict['complex_dp_format']='complex*16'
723 dict['complex_mp_format']='complex*32'
724
725 dict['mass_dp_format'] = dict['complex_dp_format']
726 dict['mass_mp_format'] = dict['complex_mp_format']
727
728
729
730
731
732 if matrix_element.get('processes')[0].get('has_born'):
733 dict['color_matrix_size'] = 'nbornamps'
734 dict['get_nsqso_born']=\
735 "include 'nsqso_born.inc'"
736 else:
737 dict['get_nsqso_born']="""INTEGER NSQSO_BORN
738 PARAMETER (NSQSO_BORN=0)
739 """
740 dict['color_matrix_size'] = 'nloopamps'
741
742
743
744
745 if matrix_element.get('processes')[0].get('has_born'):
746
747 nbornamps = matrix_element.get_number_of_born_amplitudes()
748 dict['nbornamps'] = nbornamps
749 dict['ncomb_helas_objs'] = ',ncomb'
750 dict['nbornamps_decl'] = \
751 """INTEGER NBORNAMPS
752 PARAMETER (NBORNAMPS=%d)"""%nbornamps
753 dict['nBornAmps'] = nbornamps
754
755 else:
756 dict['ncomb_helas_objs'] = ''
757 dict['dp_born_amps_decl'] = ''
758 dict['dp_born_amps_decl_in_mp'] = ''
759 dict['copy_mp_to_dp_born_amps'] = ''
760 dict['mp_born_amps_decl'] = ''
761 dict['nbornamps_decl'] = ''
762 dict['nBornAmps'] = 0
763
764 return dict
765
768 """ Writes loop_matrix.f, CT_interface.f and loop_num.f only"""
769
770
771
772 if not isinstance(fortran_model,\
773 helas_call_writers.FortranUFOHelasCallWriter):
774 raise MadGraph5Error, 'The loop fortran output can only'+\
775 ' work with a UFO Fortran model'
776
777 LoopFortranModel = helas_call_writers.FortranUFOHelasCallWriter(
778 argument=fortran_model.get('model'),
779 hel_sum=matrix_element.get('processes')[0].get('has_born'))
780
781
782
783
784
785 matrix_element.compute_all_analytic_information(
786 self.get_aloha_model(matrix_element.get('processes')[0].get('model')))
787
788
789
790 self.general_replace_dict=\
791 self.generate_general_replace_dict(matrix_element)
792
793
794 self.general_replace_dict['maxlcouplings']= \
795 matrix_element.find_max_loop_coupling()
796
797
798 if matrix_element.get('processes')[0].get('has_born'):
799 self.general_replace_dict['dp_born_amps_decl_in_mp'] = \
800 self.general_replace_dict['complex_dp_format']+" DPAMP(NBORNAMPS,NCOMB)"+\
801 "\n common/%sAMPS/DPAMP"%self.general_replace_dict['proc_prefix']
802 self.general_replace_dict['dp_born_amps_decl'] = \
803 self.general_replace_dict['complex_dp_format']+" AMP(NBORNAMPS,NCOMB)"+\
804 "\n common/%sAMPS/AMP"%self.general_replace_dict['proc_prefix']
805 self.general_replace_dict['mp_born_amps_decl'] = \
806 self.general_replace_dict['complex_mp_format']+" AMP(NBORNAMPS,NCOMB)"+\
807 "\n common/%sMP_AMPS/AMP"%self.general_replace_dict['proc_prefix']
808 self.general_replace_dict['copy_mp_to_dp_born_amps'] = \
809 '\n'.join(['DO I=1,NBORNAMPS','DPAMP(I,H)=AMP(I,H)','ENDDO'])
810
811 if writer:
812 raise MadGraph5Error, 'Matrix output mode no longer supported.'
813
814 else:
815 filename = 'loop_matrix.f'
816 calls = self.write_loopmatrix(writers.FortranWriter(filename),
817 matrix_element,
818 LoopFortranModel)
819
820
821 proc_prefix_writer = writers.FortranWriter('proc_prefix.txt','w')
822 proc_prefix_writer.write(self.general_replace_dict['proc_prefix'])
823 proc_prefix_writer.close()
824
825 filename = 'check_sa.f'
826 self.write_check_sa(writers.FortranWriter(filename),matrix_element)
827
828 filename = 'CT_interface.f'
829 self.write_CT_interface(writers.FortranWriter(filename),\
830 matrix_element)
831
832 filename = 'improve_ps.f'
833 calls = self.write_improve_ps(writers.FortranWriter(filename),
834 matrix_element)
835
836 filename = 'loop_num.f'
837 self.write_loop_num(writers.FortranWriter(filename),\
838 matrix_element,LoopFortranModel)
839
840 filename = 'mp_born_amps_and_wfs.f'
841 self.write_born_amps_and_wfs(writers.FortranWriter(filename),\
842 matrix_element,LoopFortranModel)
843
844 return calls
845
848 """ To overload the default name for this function such that the correct
849 function is used when called from the command interface """
850
851 return self.generate_loop_subprocess(matrix_element,fortran_model)
852
854 """Writes out the steering code check_sa. In the optimized output mode,
855 All the necessary entries in the replace_dictionary have already been
856 set in write_loopmatrix because it is only there that one has access to
857 the information about split orders."""
858 replace_dict = copy.copy(self.general_replace_dict)
859 for key in ['print_so_born_results','print_so_loop_results',
860 'write_so_born_results','write_so_loop_results','set_coupling_target']:
861 if key not in replace_dict.keys():
862 replace_dict[key]=''
863 if matrix_element.get('processes')[0].get('has_born'):
864 file = open(os.path.join(self.template_dir,'check_sa.inc')).read()
865 else:
866 file = open(os.path.join(self.template_dir,\
867 'check_sa_loop_induced.inc')).read()
868 file=file%replace_dict
869 writer.writelines(file)
870
872 """ Write out the improve_ps subroutines which modify the PS point
873 given in input and slightly deform it to achieve exact onshellness on
874 all external particles as well as perfect energy-momentum conservation"""
875 replace_dict = copy.copy(self.general_replace_dict)
876
877 (nexternal,ninitial)=matrix_element.get_nexternal_ninitial()
878 replace_dict['ninitial']=ninitial
879 mass_list=matrix_element.get_external_masses()[:-2]
880 mp_variable_prefix = check_param_card.ParamCard.mp_prefix
881
882
883 replace_dict['real_format']=replace_dict['real_mp_format']
884 replace_dict['mp_prefix']='MP_'
885 replace_dict['exp_letter']='e'
886 replace_dict['mp_specifier']='_16'
887 replace_dict['coupl_inc_name']='mp_coupl.inc'
888 replace_dict['masses_def']='\n'.join(['MASSES(%(i)d)=%(prefix)s%(m)s'\
889 %{'i':i+1,'m':m, 'prefix':mp_variable_prefix} for \
890 i, m in enumerate(mass_list)])
891 file_mp = open(os.path.join(self.template_dir,'improve_ps.inc')).read()
892 file_mp=file_mp%replace_dict
893
894 writer.writelines(file_mp)
895
897 """ Create the file containing the core subroutine called by CutTools
898 which contains the Helas calls building the loop"""
899
900 if not matrix_element.get('processes') or \
901 not matrix_element.get('diagrams'):
902 return 0
903
904
905 writers.FortranWriter.downcase = False
906
907 file = open(os.path.join(self.template_dir,'loop_num.inc')).read()
908
909 replace_dict = copy.copy(self.general_replace_dict)
910
911 loop_helas_calls=fortran_model.get_loop_amplitude_helas_calls(matrix_element)
912 replace_dict['maxlcouplings']=matrix_element.find_max_loop_coupling()
913 replace_dict['loop_helas_calls'] = "\n".join(loop_helas_calls)
914
915
916
917 dp_squaring_lines=['DO I=1,NBORNAMPS',
918 'CFTOT=DCMPLX(CF_N(AMPLNUM,I)/DBLE(ABS(CF_D(AMPLNUM,I))),0.0d0)',
919 'IF(CF_D(AMPLNUM,I).LT.0) CFTOT=CFTOT*IMAG1',
920 'RES=RES+CFTOT*BUFF*DCONJG(AMP(I,H))','ENDDO']
921 mp_squaring_lines=['DO I=1,NBORNAMPS',
922 'CFTOT=CMPLX(CF_N(AMPLNUM,I)/(1.0E0_16*ABS(CF_D(AMPLNUM,I))),0.0E0_16,KIND=16)',
923 'IF(CF_D(AMPLNUM,I).LT.0) CFTOT=CFTOT*IMAG1',
924 'QPRES=QPRES+CFTOT*BUFF*CONJG(AMP(I,H))','ENDDO']
925 if matrix_element.get('processes')[0].get('has_born'):
926 replace_dict['dp_squaring']='\n'.join(dp_squaring_lines)
927 replace_dict['mp_squaring']='\n'.join(mp_squaring_lines)
928 else:
929 replace_dict['dp_squaring']='RES=BUFF'
930 replace_dict['mp_squaring']='QPRES=BUFF'
931
932
933 self.turn_to_mp_calls(loop_helas_calls)
934 replace_dict['mp_loop_helas_calls'] = "\n".join(loop_helas_calls)
935
936 file=file%replace_dict
937
938 if writer:
939 writer.writelines(file)
940 else:
941 return file
942
944 """ Create the file CT_interface.f which contains the subroutine defining
945 the loop HELAS-like calls along with the general interfacing subroutine. """
946
947 files=[]
948
949
950 replace_dict=copy.copy(self.general_replace_dict)
951
952
953
954 if matrix_element.get('processes')[0].get('has_born'):
955 replace_dict['finalize_CT']='\n'.join([\
956 'RES(%d)=NORMALIZATION*2.0d0*DBLE(RES(%d))'%(i,i) for i in range(1,4)])
957 else:
958 replace_dict['finalize_CT']='\n'.join([\
959 'RES(%d)=NORMALIZATION*RES(%d)'%(i,i) for i in range(1,4)])
960
961 file = open(os.path.join(self.template_dir,'CT_interface.inc')).read()
962
963 file = file % replace_dict
964 files.append(file)
965
966
967
968 HelasLoopAmpsCallKeys=matrix_element.get_used_helas_loop_amps()
969
970 for callkey in HelasLoopAmpsCallKeys:
971 replace_dict=copy.copy(self.general_replace_dict)
972
973
974 if matrix_element.get('processes')[0].get('has_born'):
975 replace_dict['validh_or_nothing']=',validh'
976 else:
977 replace_dict['validh_or_nothing']=''
978
979
980 if len(callkey)>2:
981 replace_dict['ncplsargs']=callkey[2]
982 cplsargs="".join(["C%d,MP_C%d, "%(i,i) for i in range(1,callkey[2]+1)])
983 replace_dict['cplsargs']=cplsargs
984 cplsdecl="".join(["C%d, "%i for i in range(1,callkey[2]+1)])[:-2]
985 replace_dict['cplsdecl']=cplsdecl
986 mp_cplsdecl="".join(["MP_C%d, "%i for i in range(1,callkey[2]+1)])[:-2]
987 replace_dict['mp_cplsdecl']=mp_cplsdecl
988 cplset="\n".join(["\n".join(["LC(%d)=C%d"%(i,i),\
989 "MP_LC(%d)=MP_C%d"%(i,i)])\
990 for i in range(1,callkey[2]+1)])
991 replace_dict['cplset']=cplset
992
993 replace_dict['nloopline']=callkey[0]
994 wfsargs="".join(["W%d, "%i for i in range(1,callkey[1]+1)])
995 replace_dict['wfsargs']=wfsargs
996
997 if not optimized_output:
998 margs="".join(["M%d,MP_M%d, "%(i,i) for i in range(1,callkey[0]+1)])
999 else:
1000 margs="".join(["M%d, "%i for i in range(1,callkey[0]+1)])
1001 replace_dict['margs']=margs
1002 wfsargsdecl="".join([("W%d, "%i) for i in range(1,callkey[1]+1)])[:-2]
1003 replace_dict['wfsargsdecl']=wfsargsdecl
1004 margsdecl="".join(["M%d, "%i for i in range(1,callkey[0]+1)])[:-2]
1005 replace_dict['margsdecl']=margsdecl
1006 mp_margsdecl="".join(["MP_M%d, "%i for i in range(1,callkey[0]+1)])[:-2]
1007 replace_dict['mp_margsdecl']=mp_margsdecl
1008 weset="\n".join([("WE("+str(i)+")=W"+str(i)) for \
1009 i in range(1,callkey[1]+1)])
1010 replace_dict['weset']=weset
1011 weset="\n".join([("WE(%d)=W%d"%(i,i)) for i in range(1,callkey[1]+1)])
1012 replace_dict['weset']=weset
1013 msetlines=["M2L(1)=M%d**2"%(callkey[0]),]
1014 mset="\n".join(msetlines+["M2L(%d)=M%d**2"%(i,i-1) for \
1015 i in range(2,callkey[0]+1)])
1016 replace_dict['mset']=mset
1017 mset2lines=["ML(1)=M%d"%(callkey[0]),"ML(2)=M%d"%(callkey[0]),
1018 "MP_ML(1)=MP_M%d"%(callkey[0]),"MP_ML(2)=MP_M%d"%(callkey[0])]
1019 mset2="\n".join(mset2lines+["\n".join(["ML(%d)=M%d"%(i,i-2),
1020 "MP_ML(%d)=MP_M%d"%(i,i-2)]) for \
1021 i in range(3,callkey[0]+3)])
1022 replace_dict['mset2']=mset2
1023 replace_dict['nwfsargs'] = callkey[1]
1024 if callkey[0]==callkey[1]:
1025 replace_dict['nwfsargs_header'] = ""
1026 replace_dict['pairingargs']=""
1027 replace_dict['pairingdecl']=""
1028 pairingset="""DO I=1,NLOOPLINE
1029 PAIRING(I)=1
1030 ENDDO
1031 """
1032 replace_dict['pairingset']=pairingset
1033 else:
1034 replace_dict['nwfsargs_header'] = '_%d'%callkey[1]
1035 pairingargs="".join([("P"+str(i)+", ") for i in \
1036 range(1,callkey[0]+1)])
1037 replace_dict['pairingargs']=pairingargs
1038 pairingdecl="integer "+"".join([("P"+str(i)+", ") for i in \
1039 range(1,callkey[0]+1)])[:-2]
1040 replace_dict['pairingdecl']=pairingdecl
1041 pairingset="\n".join([("PAIRING("+str(i)+")=P"+str(i)) for \
1042 i in range(1,callkey[0]+1)])
1043 replace_dict['pairingset']=pairingset
1044
1045 file = open(os.path.join(self.template_dir,\
1046 'helas_loop_amplitude.inc')).read()
1047 file = file % replace_dict
1048 files.append(file)
1049
1050 file="\n".join(files)
1051
1052 if writer:
1053 writer.writelines(file)
1054 else:
1055 return file
1056
1057
1058
1059 - def split_HELASCALLS(self, writer, replace_dict, template_name, masterfile, \
1060 helas_calls, entry_name, bunch_name,n_helas=2000,
1061 required_so_broadcaster = 'LOOP_REQ_SO_DONE',
1062 continue_label = 1000):
1063 """ Finish the code generation with splitting.
1064 Split the helas calls in the argument helas_calls into bunches of
1065 size n_helas and place them in dedicated subroutine with name
1066 <bunch_name>_i. Also setup the corresponding calls to these subroutine
1067 in the replace_dict dictionary under the entry entry_name. """
1068 helascalls_replace_dict=copy.copy(replace_dict)
1069 helascalls_replace_dict['bunch_name']=bunch_name
1070 helascalls_files=[]
1071 for i, k in enumerate(range(0, len(helas_calls), n_helas)):
1072 helascalls_replace_dict['bunch_number']=i+1
1073 helascalls_replace_dict['helas_calls']=\
1074 '\n'.join(helas_calls[k:k + n_helas])
1075 helascalls_replace_dict['required_so_broadcaster']=\
1076 required_so_broadcaster
1077 helascalls_replace_dict['continue_label']=continue_label
1078 new_helascalls_file = open(os.path.join(self.template_dir,\
1079 template_name)).read()
1080 new_helascalls_file = new_helascalls_file % helascalls_replace_dict
1081 helascalls_files.append(new_helascalls_file)
1082
1083 helascalls_calls = [ "CALL %s%s_%d(P,NHEL,H,IC)"%\
1084 (self.general_replace_dict['proc_prefix'] ,bunch_name,a+1) \
1085 for a in range(len(helascalls_files))]
1086 replace_dict[entry_name]='\n'.join(helascalls_calls)
1087 if writer:
1088 for i, helascalls_file in enumerate(helascalls_files):
1089 filename = '%s_%d.f'%(bunch_name,i+1)
1090 writers.FortranWriter(filename).writelines(helascalls_file)
1091 else:
1092 masterfile='\n'.join([masterfile,]+helascalls_files)
1093
1094 return masterfile
1095
1096 - def write_loopmatrix(self, writer, matrix_element, fortran_model, \
1097 noSplit=False):
1098 """Create the loop_matrix.f file."""
1099
1100 if not matrix_element.get('processes') or \
1101 not matrix_element.get('diagrams'):
1102 return 0
1103
1104
1105
1106 writers.FortranWriter.downcase = False
1107
1108 replace_dict = copy.copy(self.general_replace_dict)
1109
1110
1111
1112 den_factor_line = self.get_den_factor_line(matrix_element)
1113 replace_dict['den_factor_line'] = den_factor_line
1114
1115
1116 replace_dict['hel_avg_factor'] = matrix_element.get_hel_avg_factor()
1117
1118
1119
1120
1121 if not matrix_element.get('processes')[0].get('has_born'):
1122 replace_dict['compute_born']=\
1123 """C There is of course no born for loop induced processes
1124 ANS(0)=0.0d0
1125 """
1126 replace_dict['set_reference']='\n'.join([
1127 'C For loop-induced, the reference for comparison is set later'+\
1128 ' from the total contribution of the previous PS point considered.',
1129 'C But you can edit here the value to be used for the first PS point.',
1130 'if (NPSPOINTS.eq.0) then','ref=1.0d-50','else',
1131 'ref=nextRef/DBLE(NPSPOINTS)','endif'])
1132 replace_dict['loop_induced_setup'] = '\n'.join([
1133 'HELPICKED_BU=HELPICKED','HELPICKED=H','MP_DONE=.FALSE.',
1134 'IF(SKIPLOOPEVAL) THEN','GOTO 1227','ENDIF'])
1135 replace_dict['loop_induced_finalize'] = \
1136 ("""HELPICKED=HELPICKED_BU
1137 DO I=NCTAMPS+1,NLOOPAMPS
1138 IF((CTMODERUN.NE.-1).AND..NOT.CHECKPHASE.AND.(.NOT.S(I))) THEN
1139 WRITE(*,*) '##W03 WARNING Contribution ',I
1140 WRITE(*,*) ' is unstable for helicity ',H
1141 ENDIF
1142 C IF(.NOT.%(proc_prefix)sISZERO(ABS(AMPL(2,I))+ABS(AMPL(3,I)),REF,-1,H)) THEN
1143 C WRITE(*,*) '##W04 WARNING Contribution ',I,' for helicity ',H,' has a contribution to the poles.'
1144 C WRITE(*,*) 'Finite contribution = ',AMPL(1,I)
1145 C WRITE(*,*) 'single pole contribution = ',AMPL(2,I)
1146 C WRITE(*,*) 'double pole contribution = ',AMPL(3,I)
1147 C ENDIF
1148 ENDDO
1149 1227 CONTINUE""")%replace_dict
1150 replace_dict['loop_helas_calls']=""
1151 replace_dict['nctamps_or_nloopamps']='nloopamps'
1152 replace_dict['nbornamps_or_nloopamps']='nloopamps'
1153 replace_dict['squaring']=\
1154 """ANS(1)=ANS(1)+DBLE(CFTOT*AMPL(1,I)*DCONJG(AMPL(1,J)))
1155 IF (J.EQ.1) THEN
1156 ANS(2)=ANS(2)+DBLE(CFTOT*AMPL(2,I))+DIMAG(CFTOT*AMPL(2,I))
1157 ANS(3)=ANS(3)+DBLE(CFTOT*AMPL(3,I))+DIMAG(CFTOT*AMPL(3,I))
1158 ENDIF"""
1159 else:
1160 replace_dict['compute_born']=\
1161 """C Compute the born, for a specific helicity if asked so.
1162 call %(proc_prefix)ssmatrixhel(P_USER,USERHEL,ANS(0))
1163 """%self.general_replace_dict
1164 replace_dict['set_reference']=\
1165 """C We chose to use the born evaluation for the reference
1166 call %(proc_prefix)ssmatrix(p,ref)"""%self.general_replace_dict
1167 replace_dict['loop_induced_helas_calls'] = ""
1168 replace_dict['loop_induced_finalize'] = ""
1169 replace_dict['loop_induced_setup'] = ""
1170 replace_dict['nctamps_or_nloopamps']='nctamps'
1171 replace_dict['nbornamps_or_nloopamps']='nbornamps'
1172 replace_dict['squaring']='\n'.join(['DO K=1,3',
1173 'ANS(K)=ANS(K)+2.0d0*DBLE(CFTOT*AMPL(K,I)*DCONJG(AMP(J,H)))',
1174 'ENDDO'])
1175
1176
1177
1178
1179 writers.FortranWriter('nsquaredSO.inc').writelines(
1180 """INTEGER NSQUAREDSO
1181 PARAMETER (NSQUAREDSO=0)""")
1182
1183
1184
1185 actualize_ans=[]
1186 if matrix_element.get('processes')[0].get('has_born'):
1187 actualize_ans.append("DO I=NCTAMPS+1,NLOOPAMPS")
1188 actualize_ans.extend("ANS(%d)=ANS(%d)+AMPL(%d,I)"%(i,i,i) for i \
1189 in range(1,4))
1190 actualize_ans.append(\
1191 "IF((CTMODERUN.NE.-1).AND..NOT.CHECKPHASE.AND.(.NOT.S(I))) THEN")
1192 actualize_ans.append(\
1193 "WRITE(*,*) '##W03 WARNING Contribution ',I,' is unstable.'")
1194 actualize_ans.extend(["ENDIF","ENDDO"])
1195 replace_dict['actualize_ans']='\n'.join(actualize_ans)
1196 else:
1197 replace_dict['actualize_ans']=\
1198 ("""C We add five powers to the reference value to loosen a bit the vanishing pole check.
1199 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
1200 C WRITE(*,*) '##W05 WARNING Found a PS point with a contribution to the single pole.'
1201 C WRITE(*,*) 'Finite contribution = ',ANS(1)
1202 C WRITE(*,*) 'single pole contribution = ',ANS(2)
1203 C WRITE(*,*) 'double pole contribution = ',ANS(3)
1204 C ENDIF""")%replace_dict
1205
1206
1207 (CMNum,CMDenom) = self.get_color_matrix(matrix_element)
1208 CMWriter=open(pjoin('..','MadLoop5_resources',
1209 '%(proc_prefix)sColorNumFactors.dat'%self.general_replace_dict),'w')
1210 for ColorLine in CMNum:
1211 CMWriter.write(' '.join(['%d'%C for C in ColorLine])+'\n')
1212 CMWriter.close()
1213 CMWriter=open(pjoin('..','MadLoop5_resources',
1214 '%(proc_prefix)sColorDenomFactors.dat'%self.general_replace_dict),'w')
1215 for ColorLine in CMDenom:
1216 CMWriter.write(' '.join(['%d'%C for C in ColorLine])+'\n')
1217 CMWriter.close()
1218
1219
1220 HelConfigs=matrix_element.get_helicity_matrix()
1221 HelConfigWriter=open(pjoin('..','MadLoop5_resources',
1222 '%(proc_prefix)sHelConfigs.dat'%self.general_replace_dict),'w')
1223 for HelConfig in HelConfigs:
1224 HelConfigWriter.write(' '.join(['%d'%H for H in HelConfig])+'\n')
1225 HelConfigWriter.close()
1226
1227
1228 loop_amp_helas_calls = fortran_model.get_loop_amp_helas_calls(\
1229 matrix_element)
1230
1231 loop_amp_helas_calls = [lc % self.general_replace_dict
1232 for lc in loop_amp_helas_calls]
1233
1234 born_ct_helas_calls, UVCT_helas_calls = \
1235 fortran_model.get_born_ct_helas_calls(matrix_element)
1236
1237
1238 born_ct_helas_calls = born_ct_helas_calls + UVCT_helas_calls
1239 file = open(os.path.join(self.template_dir,\
1240
1241 'loop_matrix_standalone.inc')).read()
1242
1243 if matrix_element.get('processes')[0].get('has_born'):
1244 toBeRepaced='loop_helas_calls'
1245 else:
1246 toBeRepaced='loop_induced_helas_calls'
1247
1248
1249 if (not noSplit and (len(matrix_element.get_all_amplitudes())>1000)):
1250 file=self.split_HELASCALLS(writer,replace_dict,\
1251 'helas_calls_split.inc',file,born_ct_helas_calls,\
1252 'born_ct_helas_calls','helas_calls_ampb')
1253 file=self.split_HELASCALLS(writer,replace_dict,\
1254 'helas_calls_split.inc',file,loop_amp_helas_calls,\
1255 toBeRepaced,'helas_calls_ampl')
1256 else:
1257 replace_dict['born_ct_helas_calls']='\n'.join(born_ct_helas_calls)
1258 replace_dict[toBeRepaced]='\n'.join(loop_amp_helas_calls)
1259
1260 file = file % replace_dict
1261
1262 loop_calls_finder = re.compile(r'^\s*CALL\S*LOOP\S*')
1263 n_loop_calls = len(filter(lambda call:
1264 not loop_calls_finder.match(call) is None, loop_amp_helas_calls))
1265 if writer:
1266
1267 writer.writelines(file)
1268 return n_loop_calls
1269 else:
1270
1271 return n_loop_calls, file
1272
1274 """Create the born_matrix.f file for the born process as for a standard
1275 tree-level computation."""
1276
1277 if not matrix_element.get('processes') or \
1278 not matrix_element.get('diagrams'):
1279 return 0
1280
1281 if not isinstance(writer, writers.FortranWriter):
1282 raise writers.FortranWriter.FortranWriterError(\
1283 "writer not FortranWriter")
1284
1285
1286
1287
1288
1289
1290
1291 bornME = helas_objects.HelasMatrixElement()
1292 for prop in bornME.keys():
1293 bornME.set(prop,copy.deepcopy(matrix_element.get(prop)))
1294 bornME.set('base_amplitude',None,force=True)
1295 bornME.set('diagrams',copy.deepcopy(\
1296 matrix_element.get_born_diagrams()))
1297 bornME.set('color_basis',copy.deepcopy(\
1298 matrix_element.get('born_color_basis')))
1299 bornME.set('color_matrix',copy.deepcopy(\
1300 color_amp.ColorMatrix(bornME.get('color_basis'))))
1301
1302
1303 bornME.optimization = True
1304
1305 return super(LoopProcessExporterFortranSA,self).write_matrix_element_v4(
1306 writer, bornME, fortran_model,
1307 proc_prefix=self.general_replace_dict['proc_prefix'])
1308
1311 """ Writes out the code for the subroutine MP_BORN_AMPS_AND_WFS which
1312 computes just the external wavefunction and born amplitudes in
1313 multiple precision. """
1314
1315 if not matrix_element.get('processes') or \
1316 not matrix_element.get('diagrams'):
1317 return 0
1318
1319 replace_dict = copy.copy(self.general_replace_dict)
1320
1321
1322 if matrix_element.get('processes')[0].get('has_born'):
1323 replace_dict['h_w_suffix']=',H'
1324 else:
1325 replace_dict['h_w_suffix']=''
1326
1327
1328 born_amps_and_wfs_calls , uvct_amp_calls = \
1329 fortran_model.get_born_ct_helas_calls(matrix_element, include_CT=True)
1330
1331
1332 born_amps_and_wfs_calls = born_amps_and_wfs_calls + uvct_amp_calls
1333
1334
1335
1336 self.turn_to_mp_calls(born_amps_and_wfs_calls)
1337
1338 file = open(os.path.join(self.template_dir,\
1339 'mp_born_amps_and_wfs.inc')).read()
1340
1341 if (not noSplit and (len(matrix_element.get_all_amplitudes())>2000)):
1342 file=self.split_HELASCALLS(writer,replace_dict,\
1343 'mp_helas_calls_split.inc',file,\
1344 born_amps_and_wfs_calls,'born_amps_and_wfs_calls',\
1345 'mp_helas_calls')
1346 else:
1347 replace_dict['born_amps_and_wfs_calls']=\
1348 '\n'.join(born_amps_and_wfs_calls)
1349
1350 file = file % replace_dict
1351 if writer:
1352
1353 writer.writelines(file)
1354 else:
1355
1356 return file
1357
1358
1359
1360
1361
1363 """Class to take care of exporting a set of loop matrix elements in the
1364 Fortran format which exploits the Pozzorini method of representing
1365 the loop numerators as polynomial to render its evaluations faster."""
1366
1367 template_dir=os.path.join(_file_path,'iolibs/template_files/loop_optimized')
1368
1369
1370 group_loops=True
1371
1372
1373 all_tir=['pjfry','iregi','golem']
1374
1375 - def __init__(self, mgme_dir="", dir_path = "", opt=None):
1376 """Initiate the LoopProcessOptimizedExporterFortranSA with directory
1377 information on where to find all the loop-related source files,
1378 like CutTools and TIR"""
1379
1380 super(LoopProcessOptimizedExporterFortranSA,self).__init__(mgme_dir,
1381 dir_path, opt)
1382
1383
1384 self.tir_available_dict={'pjfry':True,'iregi':True,'golem':True}
1385
1386 for tir in self.all_tir:
1387 tir_dir="%s_dir"%tir
1388 if tir_dir in self.opt:
1389 setattr(self,tir_dir,self.opt[tir_dir])
1390 else:
1391 setattr(self,tir_dir,'')
1392
1394 """Additional actions needed for setup of Template
1395 """
1396 super(LoopProcessOptimizedExporterFortranSA, self).copy_v4template(modelname)
1397
1398 link_tir_libs=[]
1399 tir_libs=[]
1400 tir_include=[]
1401
1402 link_pjfry_lib=""
1403 pjfry_lib=""
1404 pjdir=""
1405 for tir in self.all_tir:
1406 tir_dir="%s_dir"%tir
1407 libpath=getattr(self,tir_dir)
1408 libname="lib%s.a"%tir
1409 tir_name=tir
1410 libpath = self.link_TIR(os.path.join(self.dir_path, 'lib'),
1411 libpath,libname,tir_name=tir_name)
1412 setattr(self,tir_dir,libpath)
1413 if libpath != "":
1414 if tir in ['pjfry','golem']:
1415
1416
1417 link_tir_libs.append('-L%s/ -l%s'%(libpath,tir))
1418 tir_libs.append('%s/lib%s.$(libext)'%(libpath,tir))
1419 if tir=='golem':
1420 trgt_path = pjoin(os.path.dirname(libpath),'include')
1421 golem_include = misc.find_includes_path(trgt_path,'.mod')
1422 if golem_include is None:
1423 logger.error(
1424 'Could not find the include directory for golem, looking in %s.\n' % str(trg_path)+
1425 'Generation carries on but you will need to edit the include path by hand in the makefiles.')
1426 golem_include = '<Not_found_define_it_yourself>'
1427 tir_include.append('-I %s'%str(golem_include))
1428
1429
1430
1431
1432 ln(golem_include, starting_dir=pjoin(self.dir_path,'lib'),
1433 name='golem95_include',abspath=True)
1434
1435 else :
1436 link_tir_libs.append('-l%s'%tir)
1437 tir_libs.append('$(LIBDIR)lib%s.$(libext)'%tir)
1438
1439 os.remove(os.path.join(self.dir_path,'SubProcesses','makefile'))
1440 cwd = os.getcwd()
1441 dirpath = os.path.join(self.dir_path, 'SubProcesses')
1442 try:
1443 os.chdir(dirpath)
1444 except os.error:
1445 logger.error('Could not cd to directory %s' % dirpath)
1446 return 0
1447 filename = 'makefile'
1448 calls = self.write_makefile_TIR(writers.MakefileWriter(filename),
1449 link_tir_libs,tir_libs,
1450 tir_include=tir_include)
1451
1452 os.chdir(cwd)
1453
1454
1456 """ Does the same as the mother routine except that it also links
1457 coef_specs.inc in the HELAS folder."""
1458
1459 LoopProcessExporterFortranSA.link_files_from_Subprocesses(self,proc_name)
1460
1461
1462
1463 ln(os.path.join(self.dir_path, 'SubProcesses', "P%s" % proc_name,
1464 'coef_specs.inc'),os.path.join(self.dir_path,'Source/DHELAS/'))
1465
1466
1467 - def link_TIR(self, targetPath,libpath,libname,tir_name='TIR'):
1468 """Link the TIR source directory inside the target path given
1469 in argument"""
1470
1471 if tir_name in ['pjfry','golem']:
1472
1473 if (not isinstance(libpath,str)) or (not os.path.exists(libpath)) \
1474 or (not os.path.isfile(pjoin(libpath,libname))):
1475 if isinstance(libpath,str) and libpath != '' and \
1476 (not os.path.isfile(pjoin(libpath,libname))):
1477
1478
1479
1480
1481 logger.warning("The %s tensor integration library could not be found"%tir_name\
1482 +" with PATH:%s specified in mg5_configuration.txt."%libpath\
1483 +" It will not be available.")
1484 self.tir_available_dict[tir_name]=False
1485 return ""
1486 else:
1487
1488 if (not isinstance(libpath,str)) or (not os.path.exists(libpath)):
1489
1490
1491
1492
1493 logger.warning("The %s tensor integration library could not be found"%tir_name\
1494 +" with PATH:%s specified in mg5_configuration.txt."%libpath\
1495 +" It will not be available.")
1496 self.tir_available_dict[tir_name]=False
1497 return ""
1498
1499 if self.dependencies=='internal':
1500 if tir_name in ["pjfry","golem"]:
1501 self.tir_available_dict[tir_name]=False
1502 logger.warning("When using the 'output_dependencies=internal' "+\
1503 " MG5_aMC option, the tensor integral library %s cannot be employed because"%tir_name+\
1504 " it is not distributed with the MG5_aMC code so that it cannot be copied locally.")
1505 return ""
1506 elif tir_name == "iregi":
1507
1508 new_iregi_path = pjoin(targetPath,os.path.pardir,'Source','IREGI')
1509 shutil.copytree(pjoin(libpath,os.path.pardir), new_iregi_path,
1510 symlinks=True)
1511
1512 current = misc.detect_current_compiler(
1513 pjoin(new_iregi_path,'src','makefile_ML5_lib'))
1514 new = 'gfortran' if self.fortran_compiler is None else \
1515 self.fortran_compiler
1516 if current != new:
1517 misc.mod_compilator(pjoin(new_iregi_path,'src'), new,current)
1518 misc.mod_compilator(pjoin(new_iregi_path,'src','oneloop'),
1519 new, current)
1520
1521
1522 ln(pjoin(targetPath,os.path.pardir,'Source','IREGI','src',
1523 libname),targetPath)
1524 else:
1525 logger.info("Tensor integral reduction library "+\
1526 "%s not implemented yet."%tir_name)
1527 return libpath
1528
1529 elif self.dependencies=='external':
1530 if not os.path.exists(pjoin(libpath,libname)) and tir_name=='iregi':
1531 logger.info('Compiling IREGI. This has to be done only once and'+\
1532 ' can take a couple of minutes.','$MG:color:BLACK')
1533
1534 current = misc.detect_current_compiler(os.path.join(\
1535 libpath,'makefile_ML5_lib'))
1536 new = 'gfortran' if self.fortran_compiler is None else \
1537 self.fortran_compiler
1538 if current != new:
1539 misc.mod_compilator(libpath, new,current)
1540 misc.mod_compilator(pjoin(libpath,'oneloop'), new, current)
1541
1542 misc.compile(cwd=libpath, job_specs = False)
1543
1544 if not os.path.exists(pjoin(libpath,libname)):
1545 logger.warning("IREGI could not be compiled. Check"+\
1546 "the compilation errors at %s. The related "%libpath+\
1547 "functionalities are turned off.")
1548 self.tir_available_dict[tir_name]=False
1549 return ""
1550
1551
1552 if not tir_name in ['pjfry','golem']:
1553 ln(os.path.join(libpath,libname),targetPath,abspath=True)
1554
1555 elif self.dependencies=='environment_paths':
1556
1557
1558 newlibpath = misc.which_lib(libname)
1559 if not newlibpath is None:
1560 logger.info('MG5_aMC is using %s installation found at %s.'%\
1561 (tir_name,newlibpath))
1562
1563
1564 if not tir_name in ['pjfry','golem']:
1565 ln(newlibpath,targetPath,abspath=True)
1566 self.tir_available_dict[tir_name]=True
1567 return os.path.dirname(newlibpath)
1568 else:
1569 logger.warning("Could not find the location of the file"+\
1570 " %s in you environment paths. The related "%libname+\
1571 "functionalities are turned off.")
1572 self.tir_available_dict[tir_name]=False
1573 return ""
1574
1575 self.tir_available_dict[tir_name]=True
1576 return libpath
1577
1580 """ Writes loop_matrix.f, CT_interface.f,TIR_interface.f,GOLEM_inteface.f
1581 and loop_num.f only but with the optimized FortranModel"""
1582
1583
1584
1585 if writer:
1586 raise MadGraph5Error, 'Matrix output mode no longer supported.'
1587
1588 if not isinstance(fortran_model,\
1589 helas_call_writers.FortranUFOHelasCallWriter):
1590 raise MadGraph5Error, 'The optimized loop fortran output can only'+\
1591 ' work with a UFO Fortran model'
1592 OptimizedFortranModel=\
1593 helas_call_writers.FortranUFOHelasCallWriterOptimized(\
1594 fortran_model.get('model'),False)
1595
1596
1597
1598
1599
1600 matrix_element.compute_all_analytic_information(
1601 self.get_aloha_model(matrix_element.get('processes')[0].get('model')))
1602
1603
1604
1605 self.general_replace_dict=LoopProcessExporterFortranSA.\
1606 generate_general_replace_dict(self,matrix_element)
1607
1608
1609 self.set_TIR_replace_dict_entries()
1610
1611 self.set_optimized_output_specific_replace_dict_entries(matrix_element)
1612
1613
1614 proc_prefix_writer = writers.FortranWriter('proc_prefix.txt','w')
1615 proc_prefix_writer.write(self.general_replace_dict['proc_prefix'])
1616 proc_prefix_writer.close()
1617
1618 filename = 'loop_matrix.f'
1619 calls = self.write_loopmatrix(writers.FortranWriter(filename),
1620 matrix_element,
1621 OptimizedFortranModel)
1622
1623 filename = 'check_sa.f'
1624 self.write_check_sa(writers.FortranWriter(filename),matrix_element)
1625
1626 filename = 'polynomial.f'
1627 calls = self.write_polynomial_subroutines(
1628 writers.FortranWriter(filename),
1629 matrix_element)
1630
1631 filename = 'improve_ps.f'
1632 calls = self.write_improve_ps(writers.FortranWriter(filename),
1633 matrix_element)
1634
1635 filename = 'CT_interface.f'
1636 self.write_CT_interface(writers.FortranWriter(filename),\
1637 matrix_element)
1638
1639 filename = 'TIR_interface.f'
1640 self.write_TIR_interface(writers.FortranWriter(filename),
1641 matrix_element)
1642
1643 if 'golem' in self.tir_available_dict and self.tir_available_dict['golem']:
1644 filename = 'GOLEM_interface.f'
1645 self.write_GOLEM_interface(writers.FortranWriter(filename),
1646 matrix_element)
1647
1648 filename = 'loop_num.f'
1649 self.write_loop_num(writers.FortranWriter(filename),\
1650 matrix_element,OptimizedFortranModel)
1651
1652 filename = 'mp_compute_loop_coefs.f'
1653 self.write_mp_compute_loop_coefs(writers.FortranWriter(filename),\
1654 matrix_element,OptimizedFortranModel)
1655
1656 return calls
1657
1659 """ Specify the entries of the replacement dictionary which depend on
1660 the choice of Tensor Integral Reduction (TIR) libraries specified by the
1661 user and their availability on the system."""
1662
1663 for tir in self.all_tir:
1664 if self.tir_available_dict[tir]:
1665 if tir=="pjfry":
1666 self.general_replace_dict['pjfry_calling']=\
1667 (" CALL PMLOOP(NLOOPLINE,RANK,PL,PDEN,M2L,MU_R,"\
1668 +"PJCOEFS(0:NLOOPCOEFS-1,1:3),STABLE)\n"\
1669 +"C CONVERT TO MADLOOP CONVENTION\n"\
1670 +" CALL %(proc_prefix)sCONVERT_PJFRY_COEFFS(RANK,PJCOEFS,TIRCOEFS)"\
1671 )%self.general_replace_dict
1672 elif tir=="iregi":
1673 self.general_replace_dict['iregi_calling']=\
1674 (" CALL IMLOOP(CTMODE,IREGIMODE,NLOOPLINE,LOOPMAXCOEFS,"\
1675 +"RANK,PDEN,M2L,MU_R,PJCOEFS,STABLE)\n"\
1676 +"C CONVERT TO MADLOOP CONVENTION\n"\
1677 +" CALL %(proc_prefix)sCONVERT_IREGI_COEFFS(RANK,PJCOEFS,TIRCOEFS)"\
1678 )%self.general_replace_dict
1679 self.general_replace_dict['iregi_free_ps']=\
1680 "IF(IREGIRECY.AND.MLReductionLib(I_LIB).EQ.3)CALL IREGI_FREE_PS"
1681 self.general_replace_dict['initiregi']=\
1682 " CALL INITIREGI(IREGIRECY,LOOPLIB,1d-6)"
1683 elif tir=="golem":
1684 self.general_replace_dict['golem_calling']=\
1685 ("IF(MLReductionLib(I_LIB).EQ.4)THEN\n"\
1686 +"C Using Golem95\n"\
1687 +" CALL %(proc_prefix)sGOLEMLOOP(NLOOPLINE,PL,M2L,RANK,RES,STABLE)\n"\
1688 +" RETURN\n"\
1689 +"ENDIF")%self.general_replace_dict
1690 else:
1691 raise MadGraph5Error,"%s was not a well-defined TIR."%tir_name
1692 else:
1693 if tir=="pjfry":
1694 self.general_replace_dict['pjfry_calling']=\
1695 " WRITE(*,*)'PJFRY is not installed correctly !'\n"\
1696 +" STOP"
1697 elif tir=="iregi":
1698 self.general_replace_dict['iregi_calling']=\
1699 " WRITE(*,*)'IREGI is not installed correctly !'\n"\
1700 +" STOP"
1701 self.general_replace_dict['initiregi']=''
1702 self.general_replace_dict['iregi_free_ps']=''
1703 elif tir=="golem":
1704 self.general_replace_dict['golem_calling']=''
1705
1706 looplibs_av=['.TRUE.']
1707
1708 if "pjfry" in self.all_tir:
1709 if self.tir_available_dict["pjfry"]:
1710 looplibs_av.extend(['.TRUE.'])
1711 else:
1712 looplibs_av.extend(['.FALSE.'])
1713 else:
1714 looplibs_av.extend(['.FALSE.'])
1715 if "iregi" in self.all_tir:
1716 if self.tir_available_dict["iregi"]:
1717 looplibs_av.extend(['.TRUE.'])
1718 else:
1719 looplibs_av.extend(['.FALSE.'])
1720 else:
1721 looplibs_av.extend(['.FALSE.'])
1722
1723 if "golem" in self.all_tir:
1724 if self.tir_available_dict["golem"]:
1725 looplibs_av.extend(['.TRUE.'])
1726 else:
1727 looplibs_av.extend(['.FALSE.'])
1728 else:
1729 looplibs_av.extend(['.FALSE.'])
1730 self.general_replace_dict['data_looplibs_av']="DATA LOOPLIBS_AVAILABLE /"\
1731 +','.join(looplibs_av)+"/"
1732
1733
1735 """ Specify the entries of the replacement dictionary which are specific
1736 to the optimized output and only relevant to it (the more general entries
1737 are set in the the mother class LoopProcessExporterFortranSA."""
1738
1739 max_loop_rank=matrix_element.get_max_loop_rank()
1740 self.general_replace_dict['maxrank']=max_loop_rank
1741 self.general_replace_dict['loop_max_coefs']=\
1742 q_polynomial.get_number_of_coefs_for_rank(max_loop_rank)
1743 max_loop_vertex_rank=matrix_element.get_max_loop_vertex_rank()
1744 self.general_replace_dict['vertex_max_coefs']=\
1745 q_polynomial.get_number_of_coefs_for_rank(max_loop_vertex_rank)
1746 self.general_replace_dict['nloopwavefuncs']=\
1747 matrix_element.get_number_of_loop_wavefunctions()
1748 max_spin=matrix_element.get_max_loop_particle_spin()
1749 if max_spin>3:
1750 raise MadGraph5Error, "ML5 can only handle loop particles with"+\
1751 " spin 1 at most"
1752 self.general_replace_dict['max_lwf_size']=4
1753 self.general_replace_dict['nloops']=len(\
1754 [1 for ldiag in matrix_element.get_loop_diagrams() for \
1755 lamp in ldiag.get_loop_amplitudes()])
1756 if self.group_loops and \
1757 matrix_element.get('processes')[0].get('has_born'):
1758 self.general_replace_dict['nloop_groups']=\
1759 len(matrix_element.get('loop_groups'))
1760 else:
1761 self.general_replace_dict['nloop_groups']=\
1762 self.general_replace_dict['nloops']
1763
1764
1765
1766 if matrix_element.get('processes')[0].get('has_born'):
1767 self.general_replace_dict['dp_born_amps_decl'] = \
1768 self.general_replace_dict['complex_dp_format']+" AMP(NBORNAMPS)"+\
1769 "\n common/%sAMPS/AMP"%self.general_replace_dict['proc_prefix']
1770 self.general_replace_dict['mp_born_amps_decl'] = \
1771 self.general_replace_dict['complex_mp_format']+" AMP(NBORNAMPS)"+\
1772 "\n common/%sMP_AMPS/AMP"%self.general_replace_dict['proc_prefix']
1773
1775 """ Create the file containing the core subroutine called by CutTools
1776 which contains the Helas calls building the loop"""
1777
1778 replace_dict=copy.copy(self.general_replace_dict)
1779
1780 file = open(os.path.join(self.template_dir,'loop_num.inc')).read()
1781 file = file % replace_dict
1782 writer.writelines(file)
1783
1788
1790 """ Create the file TIR_interface.f which does NOT contain the subroutine
1791 defining the loop HELAS-like calls along with the general interfacing
1792 subroutine. """
1793
1794
1795 replace_dict=copy.copy(self.general_replace_dict)
1796
1797
1798
1799 if matrix_element.get('processes')[0].get('has_born'):
1800 replace_dict['finalize_TIR']='\n'.join([\
1801 'RES(%d)=NORMALIZATION*2.0d0*DBLE(RES(%d))'%(i,i) for i in range(1,4)])
1802 else:
1803 replace_dict['finalize_TIR']='\n'.join([\
1804 'RES(%d)=NORMALIZATION*RES(%d)'%(i,i) for i in range(1,4)])
1805
1806 file = open(os.path.join(self.template_dir,'TIR_interface.inc')).read()
1807
1808 file = file % replace_dict
1809
1810
1811 FPR = q_polynomial.FortranPolynomialRoutines(replace_dict['maxrank'],\
1812 coef_format=replace_dict['complex_dp_format'],\
1813 sub_prefix=replace_dict['proc_prefix'])
1814 if self.tir_available_dict['pjfry']:
1815 file += '\n\n'+FPR.write_pjfry_mapping()
1816 if self.tir_available_dict['iregi']:
1817 file += '\n\n'+FPR.write_iregi_mapping()
1818
1819 if writer:
1820 writer.writelines(file)
1821 else:
1822 return file
1823
1825 """ Create the file GOLEM_interface.f which does NOT contain the subroutine
1826 defining the loop HELAS-like calls along with the general interfacing
1827 subroutine. """
1828
1829
1830 replace_dict=copy.copy(self.general_replace_dict)
1831
1832
1833
1834 if matrix_element.get('processes')[0].get('has_born'):
1835 factor='2.0D0'
1836 else:
1837 factor='1.0D0'
1838 replace_dict['finalize_GOLEM']='\n'.join([
1839 'RES(1)=NORMALIZATION*%s*DBLE(RES_GOLEM%%c+'%factor+\
1840 '2.0*LOG(MU_R)*RES_GOLEM%b+2.0*LOG(MU_R)**2*RES_GOLEM%a)',\
1841 'RES(2)=NORMALIZATION*%s*DBLE(RES_GOLEM%%b+2.0*LOG(MU_R)*RES_GOLEM%%a)'%factor,\
1842 'RES(3)=NORMALIZATION*%s*DBLE(RES_GOLEM%%a)'%factor])
1843
1844 file = open(os.path.join(self.template_dir,'GOLEM_interface.inc')).read()
1845
1846 file = file % replace_dict
1847
1848 FPR = q_polynomial.FortranPolynomialRoutines(replace_dict['maxrank'],\
1849 coef_format=replace_dict['complex_dp_format'],\
1850 sub_prefix=replace_dict['proc_prefix'])
1851
1852 file += '\n\n'+FPR.write_golem95_mapping()
1853
1854 if writer:
1855 writer.writelines(file)
1856 else:
1857 return file
1858
1860 """ Subroutine to create all the subroutines relevant for handling
1861 the polynomials representing the loop numerator """
1862
1863
1864 IncWriter=writers.FortranWriter('coef_specs.inc','w')
1865 IncWriter.writelines("""INTEGER MAXLWFSIZE
1866 PARAMETER (MAXLWFSIZE=%(max_lwf_size)d)
1867 INTEGER LOOP_MAXCOEFS
1868 PARAMETER (LOOP_MAXCOEFS=%(loop_max_coefs)d)
1869 INTEGER VERTEXMAXCOEFS
1870 PARAMETER (VERTEXMAXCOEFS=%(vertex_max_coefs)d)"""\
1871 %self.general_replace_dict)
1872 IncWriter.close()
1873
1874
1875 subroutines=[]
1876
1877
1878 replace_dict = copy.copy(self.general_replace_dict)
1879 dp_routine = open(os.path.join(self.template_dir,'polynomial.inc')).read()
1880 mp_routine = open(os.path.join(self.template_dir,'polynomial.inc')).read()
1881
1882
1883 replace_dict['complex_format'] = replace_dict['complex_dp_format']
1884 replace_dict['real_format'] = replace_dict['real_dp_format']
1885 replace_dict['born_amps_decl'] = replace_dict['dp_born_amps_decl']
1886 replace_dict['mp_prefix'] = ''
1887 replace_dict['kind'] = 8
1888 replace_dict['zero_def'] = '0.0d0'
1889 replace_dict['one_def'] = '1.0d0'
1890 dp_routine = dp_routine % replace_dict
1891
1892 replace_dict['complex_format'] = replace_dict['complex_mp_format']
1893 replace_dict['real_format'] = replace_dict['real_mp_format']
1894 replace_dict['born_amps_decl'] = replace_dict['mp_born_amps_decl']
1895 replace_dict['mp_prefix'] = 'MP_'
1896 replace_dict['kind'] = 16
1897 replace_dict['zero_def'] = '0.0e0_16'
1898 replace_dict['one_def'] = '1.0e0_16'
1899 mp_routine = mp_routine % replace_dict
1900 subroutines.append(dp_routine)
1901 subroutines.append(mp_routine)
1902
1903
1904 poly_writer=q_polynomial.FortranPolynomialRoutines(
1905 matrix_element.get_max_loop_rank(),
1906 sub_prefix=replace_dict['proc_prefix'])
1907 mp_poly_writer=q_polynomial.FortranPolynomialRoutines(
1908 matrix_element.get_max_loop_rank(),coef_format='complex*32',
1909 sub_prefix='MP_'+replace_dict['proc_prefix'])
1910
1911 subroutines.append(poly_writer.write_polynomial_evaluator())
1912 subroutines.append(mp_poly_writer.write_polynomial_evaluator())
1913
1914 subroutines.append(poly_writer.write_add_coefs())
1915 subroutines.append(mp_poly_writer.write_add_coefs())
1916
1917 subroutines.append(poly_writer.write_wl_merger())
1918 subroutines.append(mp_poly_writer.write_wl_merger())
1919
1920 for wl_update in matrix_element.get_used_wl_updates():
1921 subroutines.append(poly_writer.write_wl_updater(\
1922 wl_update[0],wl_update[1]))
1923 subroutines.append(mp_poly_writer.write_wl_updater(\
1924 wl_update[0],wl_update[1]))
1925 writer.writelines('\n\n'.join(subroutines))
1926
1929 """Create the write_mp_compute_loop_coefs.f file."""
1930
1931 if not matrix_element.get('processes') or \
1932 not matrix_element.get('diagrams'):
1933 return 0
1934
1935
1936
1937 writers.FortranWriter.downcase = False
1938
1939 replace_dict = copy.copy(self.general_replace_dict)
1940
1941
1942
1943
1944 if not matrix_element.get('processes')[0].get('has_born'):
1945 replace_dict['nctamps_or_nloopamps']='nctamps'
1946 replace_dict['nbornamps_or_nloopamps']='nctamps'
1947 replace_dict['mp_squaring']=\
1948 """ITEMP = %(proc_prefix)sML5SQSOINDEX(%(proc_prefix)sML5SOINDEX_FOR_LOOP_AMP(I),%(proc_prefix)sML5SOINDEX_FOR_LOOP_AMP(J))
1949 TEMP2 = DUMMY*REAL(CFTOT*AMPL(1,I)*CONJG(AMPL(1,J)),KIND=16)
1950 IF (.NOT.FILTER_SO.OR.SQSO_TARGET.EQ.ITEMP) THEN
1951 ANS(1,ITEMP)=ANS(1,ITEMP)+TEMP2
1952 ANS(1,0)=ANS(1,0)+TEMP2
1953 ENDIF"""%self.general_replace_dict
1954 else:
1955 replace_dict['nctamps_or_nloopamps']='nctamps'
1956 replace_dict['nbornamps_or_nloopamps']='nbornamps'
1957 replace_dict['mp_squaring']=\
1958 """ITEMP = %(proc_prefix)sML5SQSOINDEX(%(proc_prefix)sML5SOINDEX_FOR_LOOP_AMP(I),%(proc_prefix)sML5SOINDEX_FOR_BORN_AMP(J))
1959 IF (.NOT.FILTER_SO.OR.SQSO_TARGET.EQ.ITEMP) THEN
1960 DO K=1,3
1961 TEMP2 = DUMMY*2.0e0_16*REAL(CFTOT*AMPL(K,I)*CONJG(AMP(J)),KIND=16)
1962 ANS(K,ITEMP)=ANS(K,ITEMP)+TEMP2
1963 ANS(K,0)=ANS(K,0)+TEMP2
1964 ENDDO
1965 ENDIF"""%self.general_replace_dict
1966
1967 squared_orders = matrix_element.get_squared_order_contribs()
1968 split_orders = matrix_element.get('processes')[0].get('split_orders')
1969
1970 born_ct_helas_calls , uvct_helas_calls = \
1971 fortran_model.get_born_ct_helas_calls(matrix_element,
1972 squared_orders=squared_orders, split_orders=split_orders)
1973 self.turn_to_mp_calls(born_ct_helas_calls)
1974 self.turn_to_mp_calls(uvct_helas_calls)
1975 coef_construction, coef_merging = fortran_model.get_coef_construction_calls(\
1976 matrix_element,group_loops=self.group_loops,
1977 squared_orders=squared_orders,split_orders=split_orders)
1978
1979 coef_construction = [c % self.general_replace_dict for c
1980 in coef_construction]
1981 self.turn_to_mp_calls(coef_construction)
1982 self.turn_to_mp_calls(coef_merging)
1983
1984 file = open(os.path.join(self.template_dir,\
1985 'mp_compute_loop_coefs.inc')).read()
1986
1987
1988
1989 if (not noSplit and (len(matrix_element.get_all_amplitudes())>200)):
1990 file=self.split_HELASCALLS(writer,replace_dict,\
1991 'mp_helas_calls_split.inc',file,born_ct_helas_calls,\
1992 'mp_born_ct_helas_calls','mp_helas_calls_ampb',
1993 required_so_broadcaster = 'MP_CT_REQ_SO_DONE',
1994 continue_label = 2000)
1995 file=self.split_HELASCALLS(writer,replace_dict,\
1996 'mp_helas_calls_split.inc',file,uvct_helas_calls,\
1997 'mp_uvct_helas_calls','mp_helas_calls_uvct',
1998 required_so_broadcaster = 'MP_UVCT_REQ_SO_DONE',
1999 continue_label = 3000)
2000 file=self.split_HELASCALLS(writer,replace_dict,\
2001 'mp_helas_calls_split.inc',file,coef_construction,\
2002 'mp_coef_construction','mp_coef_construction',
2003 required_so_broadcaster = 'MP_LOOP_REQ_SO_DONE',
2004 continue_label = 4000)
2005 else:
2006 replace_dict['mp_born_ct_helas_calls']='\n'.join(born_ct_helas_calls)
2007 replace_dict['mp_uvct_helas_calls']='\n'.join(uvct_helas_calls)
2008 replace_dict['mp_coef_construction']='\n'.join(coef_construction)
2009
2010 replace_dict['mp_coef_merging']='\n'.join(coef_merging)
2011
2012 file = file % replace_dict
2013
2014
2015 writer.writelines(file)
2016
2017 - def fix_coef_specs(self, overall_max_lwf_size, overall_max_loop_vert_rank):
2018 """ If processes with different maximum loop wavefunction size or
2019 different maximum loop vertex rank have to be output together, then
2020 the file 'coef.inc' in the HELAS Source folder must contain the overall
2021 maximum of these quantities. It is not safe though, and the user has
2022 been appropriatly warned at the output stage """
2023
2024
2025 coef_specs_path=os.path.join(self.dir_path,'Source','DHELAS',\
2026 'coef_specs.inc')
2027 os.remove(coef_specs_path)
2028
2029
2030 IncWriter=writers.FortranWriter(coef_specs_path,'w')
2031 IncWriter.writelines("""INTEGER MAXLWFSIZE
2032 PARAMETER (MAXLWFSIZE=%(max_lwf_size)d)
2033 INTEGER VERTEXMAXCOEFS
2034 PARAMETER (VERTEXMAXCOEFS=%(vertex_max_coefs)d)"""\
2035 %{'max_lwf_size':overall_max_lwf_size,
2036 'vertex_max_coefs':overall_max_loop_vert_rank})
2037 IncWriter.close()
2038
2041 """ Sets up the replacement dictionary for the writeout of the steering
2042 file check_sa.f"""
2043 if len(squared_orders)<1:
2044 self.general_replace_dict['print_so_loop_results']=\
2045 "write(*,*) 'No split orders defined.'"
2046 elif len(squared_orders)==1:
2047 self.general_replace_dict['set_coupling_target']=''
2048 self.general_replace_dict['print_so_loop_results']=\
2049 "write(*,*) 'All loop contributions are of split orders (%s)'"%(
2050 ' '.join(['%s=%d'%(split_orders[i],squared_orders[0][i]) \
2051 for i in range(len(split_orders))]))
2052 else:
2053 self.general_replace_dict['set_coupling_target']='\n'.join([
2054 '# Here we leave the default target squared split order to -1, meaning that we'+
2055 ' aim at computing all individual contributions. You can choose otherwise.',
2056 'call %(proc_prefix)sSET_COUPLINGORDERS_TARGET(-1)'%self.general_replace_dict])
2057 self.general_replace_dict['print_so_loop_results'] = '\n'.join([
2058 '\n'.join(["write(*,*) '%dL) Loop ME for orders (%s) :'"%((j+1),(' '.join(
2059 ['%s=%d'%(split_orders[i],so[i]) for i in range(len(split_orders))]))),
2060 "IF (PREC_FOUND(%d).NE.-1.0d0) THEN"%(j+1),
2061 "write(*,*) ' > accuracy = ',PREC_FOUND(%d)"%(j+1),
2062 "ELSE",
2063 "write(*,*) ' > accuracy = NA'",
2064 "ENDIF",
2065 "write(*,*) ' > finite = ',MATELEM(1,%d)"%(j+1),
2066 "write(*,*) ' > 1eps = ',MATELEM(2,%d)"%(j+1),
2067 "write(*,*) ' > 2eps = ',MATELEM(3,%d)"%(j+1)
2068 ]) for j, so in enumerate(squared_orders)])
2069 self.general_replace_dict['write_so_loop_results'] = '\n'.join(
2070 ["write (69,*) 'Split_Orders_Names %s'"%(' '.join(split_orders))]+
2071 ['\n'.join([
2072 "write (69,*) 'Loop_SO_Results %s'"%(' '.join(
2073 ['%d'%so_value for so_value in so])),
2074 "write (69,*) 'SO_Loop ACC ',PREC_FOUND(%d)"%(j+1),
2075 "write (69,*) 'SO_Loop FIN ',MATELEM(1,%d)"%(j+1),
2076 "write (69,*) 'SO_Loop 1EPS ',MATELEM(2,%d)"%(j+1),
2077 "write (69,*) 'SO_Loop 2EPS ',MATELEM(3,%d)"%(j+1),
2078 ]) for j, so in enumerate(squared_orders)])
2079
2080
2081 squared_born_so_orders = []
2082 for i, amp_order in enumerate(amps_orders['born_amp_orders']):
2083 for j in range(0,i+1):
2084 key = tuple([ord1 + ord2 for ord1,ord2 in \
2085 zip(amp_order[0],amps_orders['born_amp_orders'][j][0])])
2086 if not key in squared_born_so_orders:
2087 squared_born_so_orders.append(key)
2088 if len(squared_born_so_orders)<1:
2089 self.general_replace_dict['print_so_born_results'] = ''
2090 elif len(squared_born_so_orders)==1:
2091 self.general_replace_dict['print_so_born_results'] = \
2092 "write(*,*) 'All Born contributions are of split orders (%s)'"%(
2093 ' '.join(['%s=%d'%(split_orders[i],squared_born_so_orders[0][i])
2094 for i in range(len(split_orders))]))
2095 else:
2096 self.general_replace_dict['print_so_born_results'] = '\n'.join([
2097 "write(*,*) '%dB) Born ME for orders (%s) = ',MATELEM(0,%d)"%(j+1,' '.join(
2098 ['%s=%d'%(split_orders[i],so[i]) for i in range(len(split_orders))]),j+1)
2099 for j, so in enumerate(squared_born_so_orders)])
2100 self.general_replace_dict['write_so_born_results'] = '\n'.join(
2101 ['\n'.join([
2102 "write (69,*) 'Born_SO_Results %s'"%(' '.join(
2103 ['%d'%so_value for so_value in so])),
2104 "write (69,*) 'SO_Born BORN ',MATELEM(0,%d)"%(j+1),
2105 ]) for j, so in enumerate(squared_born_so_orders)])
2106
2107
2108 self.general_replace_dict['print_so_born_results'] += \
2109 '\nwrite (*,*) "---------------------------------"'
2110 self.general_replace_dict['print_so_loop_results'] += \
2111 '\nwrite (*,*) "---------------------------------"'
2112
2113 - def write_loopmatrix(self, writer, matrix_element, fortran_model, \
2114 noSplit=False, write_auxiliary_files=True,):
2115 """Create the loop_matrix.f file."""
2116
2117 if not matrix_element.get('processes') or \
2118 not matrix_element.get('diagrams'):
2119 return 0
2120
2121
2122
2123 writers.FortranWriter.downcase = False
2124
2125
2126
2127
2128
2129
2130
2131 squared_orders, amps_orders = matrix_element.get_split_orders_mapping()
2132
2133
2134
2135 sqso_contribs = [sqso[0] for sqso in squared_orders]
2136 split_orders = matrix_element.get('processes')[0].get('split_orders')
2137
2138
2139
2140 self.setup_check_sa_replacement_dictionary(\
2141 split_orders,sqso_contribs,amps_orders)
2142
2143
2144
2145 overall_so_basis = list(set(
2146 [born_so[0] for born_so in amps_orders['born_amp_orders']]+
2147 [born_so[0] for born_so in amps_orders['loop_amp_orders']]))
2148
2149 order_hierarchy = matrix_element.get('processes')[0]\
2150 .get('model').get('order_hierarchy')
2151 if set(order_hierarchy.keys()).union(set(split_orders))==\
2152 set(order_hierarchy.keys()):
2153 overall_so_basis.sort(key= lambda so:
2154 sum([order_hierarchy[split_orders[i]]*order_power for \
2155 i, order_power in enumerate(so)]))
2156
2157
2158
2159 self.general_replace_dict['split_order_str_list'] = str(split_orders)
2160 self.general_replace_dict['nSO'] = len(split_orders)
2161 self.general_replace_dict['nSquaredSO'] = len(sqso_contribs)
2162 self.general_replace_dict['nAmpSO'] = len(overall_so_basis)
2163
2164 writers.FortranWriter('nsquaredSO.inc').writelines(
2165 """INTEGER NSQUAREDSO
2166 PARAMETER (NSQUAREDSO=%d)"""%self.general_replace_dict['nSquaredSO'])
2167
2168 replace_dict = copy.copy(self.general_replace_dict)
2169
2170
2171 replace_dict['ampsplitorders'] = '\n'.join(self.get_split_orders_lines(\
2172 overall_so_basis,'AMPSPLITORDERS'))
2173 replace_dict['SquaredSO'] = '\n'.join(self.get_split_orders_lines(\
2174 sqso_contribs,'SQPLITORDERS'))
2175
2176
2177 replace_dict['chosen_so_configs'] = self.set_chosen_SO_index(
2178 matrix_element.get('processes')[0],sqso_contribs)
2179
2180
2181
2182 ampSO_list=[-1]*sum(len(el[1]) for el in amps_orders['loop_amp_orders'])
2183 for SO in amps_orders['loop_amp_orders']:
2184 for amp_number in SO[1]:
2185 ampSO_list[amp_number-1]=overall_so_basis.index(SO[0])+1
2186
2187 replace_dict['loopAmpSO'] = '\n'.join(self.format_integer_list(
2188 ampSO_list,'LOOPAMPORDERS'))
2189 ampSO_list=[-1]*sum(len(el[1]) for el in amps_orders['born_amp_orders'])
2190 for SO in amps_orders['born_amp_orders']:
2191 for amp_number in SO[1]:
2192 ampSO_list[amp_number-1]=overall_so_basis.index(SO[0])+1
2193 replace_dict['BornAmpSO'] = '\n'.join(self.format_integer_list(
2194 ampSO_list,'BORNAMPORDERS'))
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204 replace_dict['hel_offset'] = 10000
2205
2206
2207
2208 den_factor_line = self.get_den_factor_line(matrix_element)
2209 replace_dict['den_factor_line'] = den_factor_line
2210
2211
2212
2213 replace_dict['hel_avg_factor'] = matrix_element.get_hel_avg_factor()
2214
2215
2216
2217
2218 if not matrix_element.get('processes')[0].get('has_born'):
2219 replace_dict['compute_born']=\
2220 """
2221 C The born is of course 0 for loop-induced processes.
2222 DO I=0,NSQUAREDSO
2223 ANS(0,I)=0.0d0
2224 ENDDO
2225 """
2226 replace_dict['set_reference']='\n'.join([
2227 'C Chose the arbitrary scale of reference to use for comparisons'+\
2228 ' for this loop-induced process.','ref=1.0d-50',
2229 'DO I=0,NSQUAREDSO','ANS(I,0)=0.0d0','ENDDO'])
2230 replace_dict['nctamps_or_nloopamps']='nctamps'
2231 replace_dict['nbornamps_or_nloopamps']='nctamps'
2232 replace_dict['squaring']='\n'.join([\
2233 'ITEMP = %(proc_prefix)sML5SQSOINDEX(%(proc_prefix)sML5SOINDEX_FOR_LOOP_AMP(I),%(proc_prefix)sML5SOINDEX_FOR_LOOP_AMP(J))'%self.general_replace_dict,
2234 'TEMP2 = DUMMY*DBLE(CFTOT*AMPL(1,I)*DCONJG(AMPL(1,J)))',
2235 'IF (.NOT.FILTER_SO.OR.SQSO_TARGET.EQ.ITEMP) THEN',
2236 'ANS(1,ITEMP)=ANS(1,ITEMP)+TEMP2',
2237 'ANS(1,0)=ANS(1,0)+TEMP2',
2238 'ENDIF'])
2239 else:
2240 replace_dict['compute_born']=\
2241 """
2242 C First compute the borns, it will store them in ANS(0,I)
2243 C It is left untouched for the rest of MadLoop evaluation.
2244 C Notice that the squared split order index I does NOT
2245 C correspond to the same ordering of J for the loop ME
2246 C results stored in ANS(K,J), with K in [1-3].The ordering
2247 C of each can be obtained with ML5SOINDEX_FOR_SQUARED_ORDERS
2248 C and SQSOINDEX_FROM_ORDERS for the loop ME and born ME
2249 C respectively. For this to work, we assume that there is
2250 C always more squared split orders in the loop ME than in the
2251 C born ME, which is practically always true. In any case, only
2252 C the split_order summed value I=0 is used in ML5 code.
2253 DO I=0,NSQSO_BORN
2254 BORNBUFF(I)=0.0d0
2255 ENDDO
2256 CALL %(proc_prefix)sSMATRIXHEL_SPLITORDERS(P_USER,USERHEL,BORNBUFF(0))
2257 DO I=0,NSQSO_BORN
2258 ANS(0,I)=BORNBUFF(I)
2259 ENDDO
2260 """%self.general_replace_dict
2261 replace_dict['set_reference']='\n'.join(
2262 ['C We set here the reference to the born summed over all split orders',
2263 'REF=0.0d0','DO I=1,NSQSO_BORN','REF=REF+ANS(0,I)','ENDDO'])
2264 replace_dict['nctamps_or_nloopamps']='nctamps'
2265 replace_dict['nbornamps_or_nloopamps']='nbornamps'
2266 replace_dict['squaring']='\n'.join([
2267 'ITEMP = %(proc_prefix)sML5SQSOINDEX(%(proc_prefix)sML5SOINDEX_FOR_LOOP_AMP(I),%(proc_prefix)sML5SOINDEX_FOR_BORN_AMP(J))'%self.general_replace_dict,
2268 'IF (.NOT.FILTER_SO.OR.SQSO_TARGET.EQ.ITEMP) THEN',
2269 'DO K=1,3',
2270 'TEMP2 = 2.0d0*DUMMY*DBLE(CFTOT*AMPL(K,I)*DCONJG(AMP(J)))',
2271 'ANS(K,ITEMP)=ANS(K,ITEMP)+TEMP2',
2272 'ANS(K,0)=ANS(K,0)+TEMP2',
2273 'ENDDO',
2274 'ENDIF'])
2275
2276
2277
2278 actualize_ans=[]
2279 if matrix_element.get('processes')[0].get('has_born'):
2280 actualize_ans.append(
2281 """DO I=1,NLOOPGROUPS
2282 LTEMP=.TRUE.
2283 DO K=1,NSQUAREDSO
2284 IF (.NOT.FILTER_SO.OR.SQSO_TARGET.EQ.K) THEN
2285 IF (.NOT.S(K,I)) LTEMP=.FALSE.
2286 DO J=1,3
2287 ANS(J,K)=ANS(J,K)+LOOPRES(J,K,I)
2288 ANS(J,0)=ANS(J,0)+LOOPRES(J,K,I)
2289 ENDDO
2290 ENDIF
2291 ENDDO""")
2292 actualize_ans.append(\
2293 "IF((CTMODERUN.NE.-1).AND..NOT.CHECKPHASE.AND.(.NOT.LTEMP)) THEN")
2294 actualize_ans.append(\
2295 "WRITE(*,*) '##W03 WARNING Contribution ',I,' is unstable.'")
2296 actualize_ans.extend(["ENDIF","ENDDO"])
2297 replace_dict['actualize_ans']='\n'.join(actualize_ans)
2298
2299 if write_auxiliary_files:
2300
2301 (CMNum,CMDenom) = self.get_color_matrix(matrix_element)
2302 CMWriter=open(pjoin('..','MadLoop5_resources',
2303 '%(proc_prefix)sColorNumFactors.dat'%self.general_replace_dict),'w')
2304 for ColorLine in CMNum:
2305 CMWriter.write(' '.join(['%d'%C for C in ColorLine])+'\n')
2306 CMWriter.close()
2307 CMWriter=open(pjoin('..','MadLoop5_resources',
2308 '%(proc_prefix)sColorDenomFactors.dat'%self.general_replace_dict),'w')
2309 for ColorLine in CMDenom:
2310 CMWriter.write(' '.join(['%d'%C for C in ColorLine])+'\n')
2311 CMWriter.close()
2312
2313
2314 HelConfigs=matrix_element.get_helicity_matrix()
2315 HelConfigWriter=open(pjoin('..','MadLoop5_resources',
2316 '%(proc_prefix)sHelConfigs.dat'%self.general_replace_dict),'w')
2317 for HelConfig in HelConfigs:
2318 HelConfigWriter.write(' '.join(['%d'%H for H in HelConfig])+'\n')
2319 HelConfigWriter.close()
2320
2321
2322 born_ct_helas_calls, uvct_helas_calls = \
2323 fortran_model.get_born_ct_helas_calls(matrix_element,
2324 squared_orders=squared_orders,split_orders=split_orders)
2325 coef_construction, coef_merging = fortran_model.get_coef_construction_calls(\
2326 matrix_element,group_loops=self.group_loops,
2327 squared_orders=squared_orders,split_orders=split_orders)
2328
2329 loop_CT_calls = fortran_model.get_loop_CT_calls(matrix_element,\
2330 group_loops=self.group_loops,
2331 squared_orders=squared_orders, split_orders=split_orders)
2332
2333 coef_construction = [c % self.general_replace_dict for c
2334 in coef_construction]
2335 loop_CT_calls = [lc % self.general_replace_dict for lc in loop_CT_calls]
2336
2337 file = open(os.path.join(self.template_dir,\
2338 'loop_matrix_standalone.inc')).read()
2339
2340
2341
2342 if (not noSplit and (len(matrix_element.get_all_amplitudes())>200)):
2343 file=self.split_HELASCALLS(writer,replace_dict,\
2344 'helas_calls_split.inc',file,born_ct_helas_calls,\
2345 'born_ct_helas_calls','helas_calls_ampb',
2346 required_so_broadcaster = 'CT_REQ_SO_DONE',
2347 continue_label = 2000)
2348 file=self.split_HELASCALLS(writer,replace_dict,\
2349 'helas_calls_split.inc',file,uvct_helas_calls,\
2350 'uvct_helas_calls','helas_calls_uvct',
2351 required_so_broadcaster = 'UVCT_REQ_SO_DONE',
2352 continue_label = 3000)
2353 file=self.split_HELASCALLS(writer,replace_dict,\
2354 'helas_calls_split.inc',file,coef_construction,\
2355 'coef_construction','coef_construction',
2356 required_so_broadcaster = 'LOOP_REQ_SO_DONE',
2357 continue_label = 4000)
2358 file=self.split_HELASCALLS(writer,replace_dict,\
2359 'helas_calls_split.inc',file,loop_CT_calls,\
2360 'loop_CT_calls','loop_CT_calls',
2361 required_so_broadcaster = 'CTCALL_REQ_SO_DONE',
2362 continue_label = 5000)
2363 else:
2364 replace_dict['born_ct_helas_calls']='\n'.join(born_ct_helas_calls)
2365 replace_dict['uvct_helas_calls']='\n'.join(uvct_helas_calls)
2366 replace_dict['coef_construction']='\n'.join(coef_construction)
2367 replace_dict['loop_CT_calls']='\n'.join(loop_CT_calls)
2368
2369 replace_dict['coef_merging']='\n'.join(coef_merging)
2370 replace_dict['iregi_free_ps']=self.general_replace_dict['iregi_free_ps']
2371 replace_dict['data_looplibs_av']=self.general_replace_dict['data_looplibs_av']
2372 file = file % replace_dict
2373 number_of_calls = len(filter(lambda call: call.find('CALL LOOP') != 0, \
2374 loop_CT_calls))
2375 if writer:
2376
2377 writer.writelines(file)
2378 return number_of_calls
2379 else:
2380
2381 return number_of_calls, file
2382