Package madgraph :: Package iolibs :: Module export_v4
[hide private]
[frames] | no frames]

Source Code for Module madgraph.iolibs.export_v4

   1  ################################################################################ 
   2  # 
   3  # Copyright (c) 2009 The MadGraph5_aMC@NLO Development team and Contributors 
   4  # 
   5  # This file is a part of the MadGraph5_aMC@NLO project, an application which  
   6  # automatically generates Feynman diagrams and matrix elements for arbitrary 
   7  # high-energy processes in the Standard Model and beyond. 
   8  # 
   9  # It is subject to the MadGraph5_aMC@NLO license which should accompany this  
  10  # distribution. 
  11  # 
  12  # For more information, visit madgraph.phys.ucl.ac.be and amcatnlo.web.cern.ch 
  13  # 
  14  ################################################################################ 
  15  """Methods and classes to export matrix elements to v4 format.""" 
  16   
  17  import copy 
  18  from cStringIO import StringIO 
  19  from distutils import dir_util 
  20  import itertools 
  21  import fractions 
  22  import glob 
  23  import logging 
  24  import math 
  25  import os 
  26  import re 
  27  import shutil 
  28  import subprocess 
  29  import sys 
  30   
  31   
  32  import aloha 
  33   
  34  import madgraph.core.base_objects as base_objects 
  35  import madgraph.core.color_algebra as color 
  36  import madgraph.core.helas_objects as helas_objects 
  37  import madgraph.iolibs.drawing_eps as draw 
  38  import madgraph.iolibs.files as files 
  39  import madgraph.iolibs.group_subprocs as group_subprocs 
  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.helas_call_writers as helas_call_writers 
  45  import madgraph.various.diagram_symmetry as diagram_symmetry 
  46  import madgraph.various.misc as misc 
  47  import madgraph.various.process_checks as process_checks 
  48  import aloha.create_aloha as create_aloha 
  49  import models.import_ufo as import_ufo 
  50  import models.write_param_card as param_writer 
  51  import models.check_param_card as check_param_card 
  52   
  53  from madgraph import MadGraph5Error, MG5DIR, ReadWrite 
  54  from madgraph.iolibs.files import cp, ln, mv 
  55   
  56  pjoin = os.path.join 
  57   
  58  _file_path = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0] + '/' 
  59  logger = logging.getLogger('madgraph.export_v4') 
  60   
  61  #=============================================================================== 
  62  # ProcessExporterFortran 
  63  #=============================================================================== 
64 -class ProcessExporterFortran(object):
65 """Class to take care of exporting a set of matrix elements to 66 Fortran (v4) format.""" 67
68 - def __init__(self, mgme_dir = "", dir_path = "", opt=None):
69 """Initiate the ProcessExporterFortran with directory information""" 70 self.mgme_dir = mgme_dir 71 self.dir_path = dir_path 72 self.model = None 73 74 if opt: 75 self.opt = opt 76 else: 77 self.opt = {'clean': False, 'complex_mass':False, 78 'export_format':'madevent', 'mp': False}
79 80 #=========================================================================== 81 # copy the Template in a new directory. 82 #===========================================================================
83 - def copy_v4template(self, modelname):
84 """create the directory run_name as a copy of the MadEvent 85 Template, and clean the directory 86 """ 87 88 #First copy the full template tree if dir_path doesn't exit 89 if not os.path.isdir(self.dir_path): 90 assert self.mgme_dir, \ 91 "No valid MG_ME path given for MG4 run directory creation." 92 logger.info('initialize a new directory: %s' % \ 93 os.path.basename(self.dir_path)) 94 shutil.copytree(pjoin(self.mgme_dir, 'Template/LO'), 95 self.dir_path, True) 96 # distutils.dir_util.copy_tree since dir_path already exists 97 dir_util.copy_tree(pjoin(self.mgme_dir, 'Template/Common'), 98 self.dir_path) 99 # Duplicate run_card and plot_card 100 for card in ['run_card', 'plot_card']: 101 try: 102 shutil.copy(pjoin(self.dir_path, 'Cards', 103 card + '.dat'), 104 pjoin(self.dir_path, 'Cards', 105 card + '_default.dat')) 106 except IOError: 107 logger.warning("Failed to copy " + card + ".dat to default") 108 elif os.getcwd() == os.path.realpath(self.dir_path): 109 logger.info('working in local directory: %s' % \ 110 os.path.realpath(self.dir_path)) 111 # distutils.dir_util.copy_tree since dir_path already exists 112 dir_util.copy_tree(pjoin(self.mgme_dir, 'Template/LO'), 113 self.dir_path) 114 # for name in glob.glob(pjoin(self.mgme_dir, 'Template/LO/*')): 115 # name = os.path.basename(name) 116 # filname = pjoin(self.mgme_dir, 'Template','LO',name) 117 # if os.path.isfile(filename): 118 # files.cp(filename, pjoin(self.dir_path,name)) 119 # elif os.path.isdir(filename): 120 # shutil.copytree(filename, pjoin(self.dir_path,name), True) 121 # distutils.dir_util.copy_tree since dir_path already exists 122 dir_util.copy_tree(pjoin(self.mgme_dir, 'Template/Common'), 123 self.dir_path) 124 # Duplicate run_card and plot_card 125 for card in ['run_card', 'plot_card']: 126 try: 127 shutil.copy(pjoin(self.dir_path, 'Cards', 128 card + '.dat'), 129 pjoin(self.dir_path, 'Cards', 130 card + '_default.dat')) 131 except IOError: 132 logger.warning("Failed to copy " + card + ".dat to default") 133 elif not os.path.isfile(pjoin(self.dir_path, 'TemplateVersion.txt')): 134 assert self.mgme_dir, \ 135 "No valid MG_ME path given for MG4 run directory creation." 136 try: 137 shutil.copy(pjoin(self.mgme_dir, 'MGMEVersion.txt'), self.dir_path) 138 except IOError: 139 MG5_version = misc.get_pkg_info() 140 open(pjoin(self.dir_path, 'MGMEVersion.txt'), 'w').write( \ 141 "5." + MG5_version['version']) 142 143 #Ensure that the Template is clean 144 if self.opt['clean']: 145 logger.info('remove old information in %s' % \ 146 os.path.basename(self.dir_path)) 147 if os.environ.has_key('MADGRAPH_BASE'): 148 misc.call([pjoin('bin', 'internal', 'clean_template'), 149 '--web'], cwd=self.dir_path) 150 else: 151 try: 152 misc.call([pjoin('bin', 'internal', 'clean_template')], \ 153 cwd=self.dir_path) 154 except Exception, why: 155 raise MadGraph5Error('Failed to clean correctly %s: \n %s' \ 156 % (os.path.basename(self.dir_path),why)) 157 158 #Write version info 159 MG_version = misc.get_pkg_info() 160 open(pjoin(self.dir_path, 'SubProcesses', 'MGVersion.txt'), 'w').write( 161 MG_version['version']) 162 163 164 # add the makefile in Source directory 165 filename = pjoin(self.dir_path,'Source','makefile') 166 self.write_source_makefile(writers.FileWriter(filename))
167 168 #=========================================================================== 169 # write a procdef_mg5 (an equivalent of the MG4 proc_card.dat) 170 #===========================================================================
171 - def write_procdef_mg5(self, file_pos, modelname, process_str):
172 """ write an equivalent of the MG4 proc_card in order that all the Madevent 173 Perl script of MadEvent4 are still working properly for pure MG5 run.""" 174 175 proc_card_template = template_files.mg4_proc_card.mg4_template 176 process_template = template_files.mg4_proc_card.process_template 177 process_text = '' 178 coupling = '' 179 new_process_content = [] 180 181 182 # First find the coupling and suppress the coupling from process_str 183 #But first ensure that coupling are define whithout spaces: 184 process_str = process_str.replace(' =', '=') 185 process_str = process_str.replace('= ', '=') 186 process_str = process_str.replace(',',' , ') 187 #now loop on the element and treat all the coupling 188 for info in process_str.split(): 189 if '=' in info: 190 coupling += info + '\n' 191 else: 192 new_process_content.append(info) 193 # Recombine the process_str (which is the input process_str without coupling 194 #info) 195 process_str = ' '.join(new_process_content) 196 197 #format the SubProcess 198 process_text += process_template.substitute({'process': process_str, \ 199 'coupling': coupling}) 200 201 text = proc_card_template.substitute({'process': process_text, 202 'model': modelname, 203 'multiparticle':''}) 204 ff = open(file_pos, 'w') 205 ff.write(text) 206 ff.close()
207 208 #=========================================================================== 209 # Create jpeg diagrams, html pages,proc_card_mg5.dat and madevent.tar.gz 210 #===========================================================================
211 - def finalize_v4_directory(self, matrix_elements, history = "", makejpg = False, 212 online = False, compiler='g77'):
213 """Function to finalize v4 directory, for inheritance. 214 """ 215 pass
216 217 #=========================================================================== 218 # write_matrix_element_v4 219 #===========================================================================
220 - def write_matrix_element_v4(self):
221 """Function to write a matrix.f file, for inheritance. 222 """ 223 pass
224 225 #=========================================================================== 226 # write_maxparticles_file 227 #===========================================================================
228 - def write_maxparticles_file(self, writer, matrix_elements):
229 """Write the maxparticles.inc file for MadEvent""" 230 231 if isinstance(matrix_elements, helas_objects.HelasMultiProcess): 232 maxparticles = max([me.get_nexternal_ninitial()[0] for me in \ 233 matrix_elements.get('matrix_elements')]) 234 else: 235 maxparticles = max([me.get_nexternal_ninitial()[0] \ 236 for me in matrix_elements]) 237 238 lines = "integer max_particles\n" 239 lines += "parameter(max_particles=%d)" % maxparticles 240 241 # Write the file 242 writer.writelines(lines) 243 244 return True
245 246 247 #=========================================================================== 248 # export the model 249 #===========================================================================
250 - def export_model_files(self, model_path):
251 """Configure the files/link of the process according to the model""" 252 253 # Import the model 254 for file in os.listdir(model_path): 255 if os.path.isfile(pjoin(model_path, file)): 256 shutil.copy2(pjoin(model_path, file), \ 257 pjoin(self.dir_path, 'Source', 'MODEL'))
258 259 273 279 280 #=========================================================================== 281 # export the helas routine 282 #===========================================================================
283 - def export_helas(self, helas_path):
284 """Configure the files/link of the process according to the model""" 285 286 # Import helas routine 287 for filename in os.listdir(helas_path): 288 filepos = pjoin(helas_path, filename) 289 if os.path.isfile(filepos): 290 if filepos.endswith('Makefile.template'): 291 cp(filepos, self.dir_path + '/Source/DHELAS/Makefile') 292 elif filepos.endswith('Makefile'): 293 pass 294 else: 295 cp(filepos, self.dir_path + '/Source/DHELAS')
296 # following lines do the same but whithout symbolic link 297 # 298 #def export_helas(mgme_dir, dir_path): 299 # 300 # # Copy the HELAS directory 301 # helas_dir = pjoin(mgme_dir, 'HELAS') 302 # for filename in os.listdir(helas_dir): 303 # if os.path.isfile(pjoin(helas_dir, filename)): 304 # shutil.copy2(pjoin(helas_dir, filename), 305 # pjoin(dir_path, 'Source', 'DHELAS')) 306 # shutil.move(pjoin(dir_path, 'Source', 'DHELAS', 'Makefile.template'), 307 # pjoin(dir_path, 'Source', 'DHELAS', 'Makefile')) 308 # 309 310 #=========================================================================== 311 # generate_subprocess_directory_v4 312 #===========================================================================
313 - def generate_subprocess_directory_v4(self, matrix_element, 314 fortran_model, 315 me_number):
316 """Routine to generate a subprocess directory (for inheritance)""" 317 318 pass
319 320 #=========================================================================== 321 # write_source_makefile 322 #===========================================================================
323 - def write_source_makefile(self, writer):
324 """Write the nexternal.inc file for MG4""" 325 326 327 path = pjoin(_file_path,'iolibs','template_files','madevent_makefile_source') 328 set_of_lib = '$(LIBRARIES) $(LIBDIR)libdhelas.$(libext) $(LIBDIR)libpdf.$(libext) $(LIBDIR)libmodel.$(libext) $(LIBDIR)libcernlib.$(libext)' 329 if self.opt['model'] == 'mssm' or self.opt['model'].startswith('mssm-'): 330 model_line='''$(LIBDIR)libmodel.$(libext): MODEL param_card.inc\n\tcd MODEL; make 331 MODEL/MG5_param.dat: ../Cards/param_card.dat\n\t../bin/madevent treatcards param 332 param_card.inc: MODEL/MG5_param.dat\n\t../bin/madevent treatcards param\n''' 333 else: 334 model_line='''$(LIBDIR)libmodel.$(libext): MODEL param_card.inc\n\tcd MODEL; make 335 param_card.inc: ../Cards/param_card.dat\n\t../bin/madevent treatcards param\n''' 336 text = open(path).read() % {'libraries': set_of_lib, 'model':model_line} 337 writer.write(text) 338 339 return True
340 341 #=========================================================================== 342 # write_nexternal_madspin 343 #===========================================================================
344 - def write_nexternal_madspin(self, writer, nexternal, ninitial):
345 """Write the nexternal_prod.inc file for madspin""" 346 347 replace_dict = {} 348 349 replace_dict['nexternal'] = nexternal 350 replace_dict['ninitial'] = ninitial 351 352 file = """ \ 353 integer nexternal_prod 354 parameter (nexternal_prod=%(nexternal)d) 355 integer nincoming_prod 356 parameter (nincoming_prod=%(ninitial)d)""" % replace_dict 357 358 # Write the file 359 writer.writelines(file) 360 361 return True
362 363 #=========================================================================== 364 # write_helamp_madspin 365 #===========================================================================
366 - def write_helamp_madspin(self, writer, ncomb):
367 """Write the helamp.inc file for madspin""" 368 369 replace_dict = {} 370 371 replace_dict['ncomb'] = ncomb 372 373 file = """ \ 374 integer ncomb1 375 parameter (ncomb1=%(ncomb)d) 376 double precision helamp(ncomb1) 377 common /to_helamp/helamp """ % replace_dict 378 379 # Write the file 380 writer.writelines(file) 381 382 return True
383 384 385 #=========================================================================== 386 # write_nexternal_file 387 #===========================================================================
388 - def write_nexternal_file(self, writer, nexternal, ninitial):
389 """Write the nexternal.inc file for MG4""" 390 391 replace_dict = {} 392 393 replace_dict['nexternal'] = nexternal 394 replace_dict['ninitial'] = ninitial 395 396 file = """ \ 397 integer nexternal 398 parameter (nexternal=%(nexternal)d) 399 integer nincoming 400 parameter (nincoming=%(ninitial)d)""" % replace_dict 401 402 # Write the file 403 writer.writelines(file) 404 405 return True
406 407 #=========================================================================== 408 # write_pmass_file 409 #===========================================================================
410 - def write_pmass_file(self, writer, matrix_element):
411 """Write the pmass.inc file for MG4""" 412 413 model = matrix_element.get('processes')[0].get('model') 414 415 lines = [] 416 for wf in matrix_element.get_external_wavefunctions(): 417 mass = model.get('particle_dict')[wf.get('pdg_code')].get('mass') 418 if mass.lower() != "zero": 419 mass = "abs(%s)" % mass 420 421 lines.append("pmass(%d)=%s" % \ 422 (wf.get('number_external'), mass)) 423 424 # Write the file 425 writer.writelines(lines) 426 427 return True
428 429 #=========================================================================== 430 # write_ngraphs_file 431 #===========================================================================
432 - def write_ngraphs_file(self, writer, nconfigs):
433 """Write the ngraphs.inc file for MG4. Needs input from 434 write_configs_file.""" 435 436 file = " integer n_max_cg\n" 437 file = file + "parameter (n_max_cg=%d)" % nconfigs 438 439 # Write the file 440 writer.writelines(file) 441 442 return True
443 444 #=========================================================================== 445 # write_leshouche_file 446 #===========================================================================
447 - def write_leshouche_file(self, writer, matrix_element):
448 """Write the leshouche.inc file for MG4""" 449 450 # Write the file 451 writer.writelines(self.get_leshouche_lines(matrix_element, 0)) 452 453 return True
454 455 #=========================================================================== 456 # get_leshouche_lines 457 #===========================================================================
458 - def get_leshouche_lines(self, matrix_element, numproc):
459 """Write the leshouche.inc file for MG4""" 460 461 # Extract number of external particles 462 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial() 463 464 lines = [] 465 for iproc, proc in enumerate(matrix_element.get('processes')): 466 legs = proc.get_legs_with_decays() 467 lines.append("DATA (IDUP(i,%d,%d),i=1,%d)/%s/" % \ 468 (iproc + 1, numproc+1, nexternal, 469 ",".join([str(l.get('id')) for l in legs]))) 470 if iproc == 0 and numproc == 0: 471 for i in [1, 2]: 472 lines.append("DATA (MOTHUP(%d,i),i=1,%2r)/%s/" % \ 473 (i, nexternal, 474 ",".join([ "%3r" % 0 ] * ninitial + \ 475 [ "%3r" % i ] * (nexternal - ninitial)))) 476 477 # Here goes the color connections corresponding to the JAMPs 478 # Only one output, for the first subproc! 479 if iproc == 0: 480 # If no color basis, just output trivial color flow 481 if not matrix_element.get('color_basis'): 482 for i in [1, 2]: 483 lines.append("DATA (ICOLUP(%d,i,1,%d),i=1,%2r)/%s/" % \ 484 (i, numproc+1,nexternal, 485 ",".join([ "%3r" % 0 ] * nexternal))) 486 487 else: 488 # First build a color representation dictionnary 489 repr_dict = {} 490 for l in legs: 491 repr_dict[l.get('number')] = \ 492 proc.get('model').get_particle(l.get('id')).get_color()\ 493 * (-1)**(1+l.get('state')) 494 # Get the list of color flows 495 color_flow_list = \ 496 matrix_element.get('color_basis').color_flow_decomposition(repr_dict, 497 ninitial) 498 # And output them properly 499 for cf_i, color_flow_dict in enumerate(color_flow_list): 500 for i in [0, 1]: 501 lines.append("DATA (ICOLUP(%d,i,%d,%d),i=1,%2r)/%s/" % \ 502 (i + 1, cf_i + 1, numproc+1, nexternal, 503 ",".join(["%3r" % color_flow_dict[l.get('number')][i] \ 504 for l in legs]))) 505 506 return lines
507 508 509 510 511 #=========================================================================== 512 # write_maxamps_file 513 #===========================================================================
514 - def write_maxamps_file(self, writer, maxamps, maxflows, 515 maxproc,maxsproc):
516 """Write the maxamps.inc file for MG4.""" 517 518 file = " integer maxamps, maxflow, maxproc, maxsproc\n" 519 file = file + "parameter (maxamps=%d, maxflow=%d)\n" % \ 520 (maxamps, maxflows) 521 file = file + "parameter (maxproc=%d, maxsproc=%d)" % \ 522 (maxproc, maxsproc) 523 524 # Write the file 525 writer.writelines(file) 526 527 return True
528 529 #=========================================================================== 530 # write_props_file 531 #===========================================================================
532 - def write_props_file(self, writer, matrix_element, s_and_t_channels):
533 """Write the props.inc file for MadEvent. Needs input from 534 write_configs_file.""" 535 536 lines = [] 537 538 particle_dict = matrix_element.get('processes')[0].get('model').\ 539 get('particle_dict') 540 541 for iconf, configs in enumerate(s_and_t_channels): 542 for vertex in configs[0] + configs[1][:-1]: 543 leg = vertex.get('legs')[-1] 544 if leg.get('id') not in particle_dict: 545 # Fake propagator used in multiparticle vertices 546 mass = 'zero' 547 width = 'zero' 548 pow_part = 0 549 else: 550 particle = particle_dict[leg.get('id')] 551 # Get mass 552 if particle.get('mass').lower() == 'zero': 553 mass = particle.get('mass') 554 else: 555 mass = "abs(%s)" % particle.get('mass') 556 # Get width 557 if particle.get('width').lower() == 'zero': 558 width = particle.get('width') 559 else: 560 width = "abs(%s)" % particle.get('width') 561 562 pow_part = 1 + int(particle.is_boson()) 563 564 lines.append("prmass(%d,%d) = %s" % \ 565 (leg.get('number'), iconf + 1, mass)) 566 lines.append("prwidth(%d,%d) = %s" % \ 567 (leg.get('number'), iconf + 1, width)) 568 lines.append("pow(%d,%d) = %d" % \ 569 (leg.get('number'), iconf + 1, pow_part)) 570 571 # Write the file 572 writer.writelines(lines) 573 574 return True
575 576 #=========================================================================== 577 # Routines to output UFO models in MG4 format 578 #=========================================================================== 579
580 - def convert_model_to_mg4(self, model, wanted_lorentz = [], 581 wanted_couplings = []):
582 """ Create a full valid MG4 model from a MG5 model (coming from UFO)""" 583 584 # Make sure aloha is in quadruple precision if needed 585 old_aloha_mp=aloha.mp_precision 586 aloha.mp_precision=self.opt['mp'] 587 588 # create the MODEL 589 write_dir=pjoin(self.dir_path, 'Source', 'MODEL') 590 model_builder = UFO_model_to_mg4(model, write_dir, self.opt) 591 model_builder.build(wanted_couplings) 592 593 # Backup the loop mode, because it can be changed in what follows. 594 old_loop_mode = aloha.loop_mode 595 596 # Create the aloha model or use the existing one (for loop exporters 597 # this is useful as the aloha model will be used again in the 598 # LoopHelasMatrixElements generated). We do not save the model generated 599 # here if it didn't exist already because it would be a waste of 600 # memory for tree level applications since aloha is only needed at the 601 # time of creating the aloha fortran subroutines. 602 if hasattr(self, 'aloha_model'): 603 aloha_model = self.aloha_model 604 else: 605 aloha_model = create_aloha.AbstractALOHAModel(model.get('name')) 606 aloha_model.add_Lorentz_object(model.get('lorentz')) 607 608 # Compute the subroutines 609 if wanted_lorentz: 610 aloha_model.compute_subset(wanted_lorentz) 611 else: 612 aloha_model.compute_all(save=False) 613 614 # Write them out 615 write_dir=pjoin(self.dir_path, 'Source', 'DHELAS') 616 aloha_model.write(write_dir, 'Fortran') 617 618 # Revert the original aloha loop mode 619 aloha.loop_mode = old_loop_mode 620 621 #copy Helas Template 622 cp(MG5DIR + '/aloha/template_files/Makefile_F', write_dir+'/makefile') 623 if any([any(['L' in tag for tag in d[1]]) for d in wanted_lorentz]): 624 cp(MG5DIR + '/aloha/template_files/aloha_functions_loop.f', write_dir+'/aloha_functions.f') 625 aloha_model.loop_mode = False 626 else: 627 cp(MG5DIR + '/aloha/template_files/aloha_functions.f', write_dir+'/aloha_functions.f') 628 create_aloha.write_aloha_file_inc(write_dir, '.f', '.o') 629 630 # Make final link in the Process 631 self.make_model_symbolic_link() 632 633 # Re-establish original aloha mode 634 aloha.mp_precision=old_aloha_mp
635 636 #=========================================================================== 637 # Helper functions 638 #===========================================================================
639 - def get_mg5_info_lines(self):
640 """Return info lines for MG5, suitable to place at beginning of 641 Fortran files""" 642 643 info = misc.get_pkg_info() 644 info_lines = "" 645 if info and info.has_key('version') and info.has_key('date'): 646 info_lines = "# Generated by MadGraph5_aMC@NLO v. %s, %s\n" % \ 647 (info['version'], info['date']) 648 info_lines = info_lines + \ 649 "# By the MadGraph5_aMC@NLO Development Team\n" + \ 650 "# Visit launchpad.net/madgraph5 and amcatnlo.web.cern.ch" 651 else: 652 info_lines = "# Generated by MadGraph5_aMC@NLO\n" + \ 653 "# By the MadGraph5_aMC@NLO Development Team\n" + \ 654 "# Visit launchpad.net/madgraph5 and amcatnlo.web.cern.ch" 655 656 return info_lines
657
658 - def get_process_info_lines(self, matrix_element):
659 """Return info lines describing the processes for this matrix element""" 660 661 return"\n".join([ "C " + process.nice_string().replace('\n', '\nC * ') \ 662 for process in matrix_element.get('processes')])
663 664
665 - def get_helicity_lines(self, matrix_element,array_name='NHEL'):
666 """Return the Helicity matrix definition lines for this matrix element""" 667 668 helicity_line_list = [] 669 i = 0 670 for helicities in matrix_element.get_helicity_matrix(): 671 i = i + 1 672 int_list = [i, len(helicities)] 673 int_list.extend(helicities) 674 helicity_line_list.append(\ 675 ("DATA ("+array_name+"(I,%4r),I=1,%d) /" + \ 676 ",".join(['%2r'] * len(helicities)) + "/") % tuple(int_list)) 677 678 return "\n".join(helicity_line_list)
679
680 - def get_ic_line(self, matrix_element):
681 """Return the IC definition line coming after helicities, required by 682 switchmom in madevent""" 683 684 nexternal = matrix_element.get_nexternal_ninitial()[0] 685 int_list = range(1, nexternal + 1) 686 687 return "DATA (IC(I,1),I=1,%i) /%s/" % (nexternal, 688 ",".join([str(i) for \ 689 i in int_list]))
690
691 - def set_chosen_SO_index(self, process, squared_orders):
692 """ From the squared order constraints set by the user, this function 693 finds what indices of the squared_orders list the user intends to pick. 694 It returns this as a string of comma-separated successive '.true.' or 695 '.false.' for each index.""" 696 697 user_squared_orders = process.get('squared_orders') 698 split_orders = process.get('split_orders') 699 700 if len(user_squared_orders)==0: 701 return ','.join(['.true.']*len(squared_orders)) 702 703 res = [] 704 for sqsos in squared_orders: 705 is_a_match = True 706 for user_sqso, value in user_squared_orders.items(): 707 if (process.get_squared_order_type(user_sqso) =='==' and \ 708 value!=sqsos[split_orders.index(user_sqso)]) or \ 709 (process.get_squared_order_type(user_sqso) in ['<=','='] and \ 710 value<sqsos[split_orders.index(user_sqso)]) or \ 711 (process.get_squared_order_type(user_sqso) == '>' and \ 712 value>=sqsos[split_orders.index(user_sqso)]): 713 is_a_match = False 714 break 715 res.append('.true.' if is_a_match else '.false.') 716 717 return ','.join(res)
718
719 - def get_split_orders_lines(self, orders, array_name, n=5):
720 """ Return the split orders definition as defined in the list orders and 721 for the name of the array 'array_name'. Split rows in chunks of size n.""" 722 723 ret_list = [] 724 for index, order in enumerate(orders): 725 for k in xrange(0, len(order), n): 726 ret_list.append("DATA (%s(%3r,i),i=%3r,%3r) /%s/" % \ 727 (array_name,index + 1, k + 1, min(k + n, len(order)), 728 ','.join(["%5r" % i for i in order[k:k + n]]))) 729 return ret_list
730
731 - def format_integer_list(self, list, name, n=5):
732 """ Return an initialization of the python list in argument following 733 the fortran syntax using the data keyword assignment, filling an array 734 of name 'name'. It splits rows in chunks of size n.""" 735 736 ret_list = [] 737 for k in xrange(0, len(list), n): 738 ret_list.append("DATA (%s(i),i=%3r,%3r) /%s/" % \ 739 (name, k + 1, min(k + n, len(list)), 740 ','.join(["%5r" % i for i in list[k:k + n]]))) 741 return ret_list
742
743 - def get_color_data_lines(self, matrix_element, n=6):
744 """Return the color matrix definition lines for this matrix element. Split 745 rows in chunks of size n.""" 746 747 if not matrix_element.get('color_matrix'): 748 return ["DATA Denom(1)/1/", "DATA (CF(i,1),i=1,1) /1/"] 749 else: 750 ret_list = [] 751 my_cs = color.ColorString() 752 for index, denominator in \ 753 enumerate(matrix_element.get('color_matrix').\ 754 get_line_denominators()): 755 # First write the common denominator for this color matrix line 756 ret_list.append("DATA Denom(%i)/%i/" % (index + 1, denominator)) 757 # Then write the numerators for the matrix elements 758 num_list = matrix_element.get('color_matrix').\ 759 get_line_numerators(index, denominator) 760 761 for k in xrange(0, len(num_list), n): 762 ret_list.append("DATA (CF(i,%3r),i=%3r,%3r) /%s/" % \ 763 (index + 1, k + 1, min(k + n, len(num_list)), 764 ','.join(["%5r" % i for i in num_list[k:k + n]]))) 765 my_cs.from_immutable(sorted(matrix_element.get('color_basis').keys())[index]) 766 ret_list.append("C %s" % repr(my_cs)) 767 return ret_list
768 769
770 - def get_den_factor_line(self, matrix_element):
771 """Return the denominator factor line for this matrix element""" 772 773 return "DATA IDEN/%2r/" % \ 774 matrix_element.get_denominator_factor()
775
776 - def get_icolamp_lines(self, mapconfigs, matrix_element, num_matrix_element):
777 """Return the ICOLAMP matrix, showing which JAMPs contribute to 778 which configs (diagrams).""" 779 780 ret_list = [] 781 782 booldict = {False: ".false.", True: ".true."} 783 784 if not matrix_element.get('color_basis'): 785 # No color, so only one color factor. Simply write a ".true." 786 # for each config (i.e., each diagram with only 3 particle 787 # vertices 788 configs = len(mapconfigs) 789 ret_list.append("DATA(icolamp(1,i,%d),i=1,%d)/%s/" % \ 790 (num_matrix_element, configs, 791 ','.join([".true." for i in range(configs)]))) 792 return ret_list 793 794 # There is a color basis - create a list showing which JAMPs have 795 # contributions to which configs 796 797 # Only want to include leading color flows, so find max_Nc 798 color_basis = matrix_element.get('color_basis') 799 max_Nc = max(sum([[v[4] for v in val] for val in color_basis.values()], 800 [])) 801 802 # Crate dictionary between diagram number and JAMP number 803 diag_jamp = {} 804 for ijamp, col_basis_elem in \ 805 enumerate(sorted(matrix_element.get('color_basis').keys())): 806 for diag_tuple in matrix_element.get('color_basis')[col_basis_elem]: 807 # Only use color flows with Nc == max_Nc 808 if diag_tuple[4] == max_Nc: 809 diag_num = diag_tuple[0] + 1 810 # Add this JAMP number to this diag_num 811 diag_jamp[diag_num] = diag_jamp.setdefault(diag_num, []) + \ 812 [ijamp+1] 813 814 colamps = ijamp + 1 815 816 for iconfig, num_diag in enumerate(mapconfigs): 817 if num_diag == 0: 818 continue 819 820 # List of True or False 821 bool_list = [(i + 1 in diag_jamp[num_diag]) for i in \ 822 range(colamps)] 823 # Add line 824 ret_list.append("DATA(icolamp(i,%d,%d),i=1,%d)/%s/" % \ 825 (iconfig+1, num_matrix_element, colamps, 826 ','.join(["%s" % booldict[b] for b in \ 827 bool_list]))) 828 829 return ret_list
830
831 - def get_amp2_lines(self, matrix_element, config_map = []):
832 """Return the amp2(i) = sum(amp for diag(i))^2 lines""" 833 834 nexternal, ninitial = matrix_element.get_nexternal_ninitial() 835 # Get minimum legs in a vertex 836 minvert = min([max(diag.get_vertex_leg_numbers()) for diag in \ 837 matrix_element.get('diagrams')]) 838 839 ret_lines = [] 840 if config_map: 841 # In this case, we need to sum up all amplitudes that have 842 # identical topologies, as given by the config_map (which 843 # gives the topology/config for each of the diagrams 844 diagrams = matrix_element.get('diagrams') 845 # Combine the diagrams with identical topologies 846 config_to_diag_dict = {} 847 for idiag, diag in enumerate(matrix_element.get('diagrams')): 848 if config_map[idiag] == 0: 849 continue 850 try: 851 config_to_diag_dict[config_map[idiag]].append(idiag) 852 except KeyError: 853 config_to_diag_dict[config_map[idiag]] = [idiag] 854 # Write out the AMP2s summing squares of amplitudes belonging 855 # to eiher the same diagram or different diagrams with 856 # identical propagator properties. Note that we need to use 857 # AMP2 number corresponding to the first diagram number used 858 # for that AMP2. 859 for config in sorted(config_to_diag_dict.keys()): 860 861 line = "AMP2(%(num)d)=AMP2(%(num)d)+" % \ 862 {"num": (config_to_diag_dict[config][0] + 1)} 863 864 amp = "+".join(["AMP(%(num)d)" % {"num": a.get('number')} for a in \ 865 sum([diagrams[idiag].get('amplitudes') for \ 866 idiag in config_to_diag_dict[config]], [])]) 867 868 # Not using \sum |M|^2 anymore since this creates troubles 869 # when ckm is not diagonal due to the JIM mechanism. 870 if '+' in amp: 871 line += "(%s)*dconjg(%s)" % (amp, amp) 872 else: 873 line += "%s*dconjg(%s)" % (amp, amp) 874 ret_lines.append(line) 875 else: 876 for idiag, diag in enumerate(matrix_element.get('diagrams')): 877 # Ignore any diagrams with 4-particle vertices. 878 if max(diag.get_vertex_leg_numbers()) > minvert: 879 continue 880 # Now write out the expression for AMP2, meaning the sum of 881 # squared amplitudes belonging to the same diagram 882 line = "AMP2(%(num)d)=AMP2(%(num)d)+" % {"num": (idiag + 1)} 883 line += "+".join(["AMP(%(num)d)*dconjg(AMP(%(num)d))" % \ 884 {"num": a.get('number')} for a in \ 885 diag.get('amplitudes')]) 886 ret_lines.append(line) 887 888 return ret_lines
889 890 #=========================================================================== 891 # Returns the data statements initializing the coeffictients for the JAMP 892 # decomposition. It is used when the JAMP initialization is decided to be 893 # done through big arrays containing the projection coefficients. 894 #===========================================================================
895 - def get_JAMP_coefs(self, color_amplitudes, color_basis=None, tag_letter="",\ 896 n=50, Nc_value=3):
897 """This functions return the lines defining the DATA statement setting 898 the coefficients building the JAMPS out of the AMPS. Split rows in 899 bunches of size n. 900 One can specify the color_basis from which the color amplitudes originates 901 so that there are commentaries telling what color structure each JAMP 902 corresponds to.""" 903 904 if(not isinstance(color_amplitudes,list) or 905 not (color_amplitudes and isinstance(color_amplitudes[0],list))): 906 raise MadGraph5Error, "Incorrect col_amps argument passed to get_JAMP_coefs" 907 908 res_list = [] 909 my_cs = color.ColorString() 910 for index, coeff_list in enumerate(color_amplitudes): 911 # Create the list of the complete numerical coefficient. 912 coefs_list=[coefficient[0][0]*coefficient[0][1]*\ 913 (fractions.Fraction(Nc_value)**coefficient[0][3]) for \ 914 coefficient in coeff_list] 915 # Create the list of the numbers of the contributing amplitudes. 916 # Mutliply by -1 for those which have an imaginary coefficient. 917 ampnumbers_list=[coefficient[1]*(-1 if coefficient[0][2] else 1) \ 918 for coefficient in coeff_list] 919 # Find the common denominator. 920 commondenom=abs(reduce(fractions.gcd, coefs_list).denominator) 921 num_list=[(coefficient*commondenom).numerator \ 922 for coefficient in coefs_list] 923 res_list.append("DATA NCONTRIBAMPS%s(%i)/%i/"%(tag_letter,\ 924 index+1,len(num_list))) 925 res_list.append("DATA DENOMCCOEF%s(%i)/%i/"%(tag_letter,\ 926 index+1,commondenom)) 927 if color_basis: 928 my_cs.from_immutable(sorted(color_basis.keys())[index]) 929 res_list.append("C %s" % repr(my_cs)) 930 for k in xrange(0, len(num_list), n): 931 res_list.append("DATA (NUMCCOEF%s(%3r,i),i=%6r,%6r) /%s/" % \ 932 (tag_letter,index + 1, k + 1, min(k + n, len(num_list)), 933 ','.join(["%6r" % i for i in num_list[k:k + n]]))) 934 res_list.append("DATA (AMPNUMBERS%s(%3r,i),i=%6r,%6r) /%s/" % \ 935 (tag_letter,index + 1, k + 1, min(k + n, len(num_list)), 936 ','.join(["%6r" % i for i in ampnumbers_list[k:k + n]]))) 937 pass 938 return res_list
939
940 - def get_JAMP_lines_split_order(self, col_amps, split_order_amps, 941 split_order_names=None, JAMP_format="JAMP(%s)", AMP_format="AMP(%s)"):
942 """Return the JAMP = sum(fermionfactor * AMP(i)) lines from col_amps 943 defined as a matrix element or directly as a color_amplitudes dictionary. 944 The split_order_amps specifies the group of amplitudes sharing the same 945 amplitude orders which should be put in together in a given set of JAMPS. 946 The split_order_amps is supposed to have the format of the second output 947 of the function get_split_orders_mapping function in helas_objects.py. 948 The split_order_names is optional (it should correspond to the process 949 'split_orders' attribute) and only present to provide comments in the 950 JAMP definitions in the code.""" 951 952 # Let the user call get_JAMP_lines_split_order directly from a 953 error_msg="Malformed '%s' argument passed to the "+\ 954 "get_JAMP_lines_split_order function: %s"%str(split_order_amps) 955 if(isinstance(col_amps,helas_objects.HelasMatrixElement)): 956 color_amplitudes=col_amps.get_color_amplitudes() 957 elif(isinstance(col_amps,list)): 958 if(col_amps and isinstance(col_amps[0],list)): 959 color_amplitudes=col_amps 960 else: 961 raise MadGraph5Error, error_msg%'col_amps' 962 else: 963 raise MadGraph5Error, error_msg%'col_amps' 964 965 # Verify the sanity of the split_order_amps and split_order_names args 966 if isinstance(split_order_amps,list): 967 for elem in split_order_amps: 968 if len(elem)!=2: 969 raise MadGraph5Error, error_msg%'split_order_amps' 970 # Check the first element of the two lists to make sure they are 971 # integers, although in principle they should all be integers. 972 if not isinstance(elem[0],tuple) or \ 973 not isinstance(elem[1],tuple) or \ 974 not isinstance(elem[0][0],int) or \ 975 not isinstance(elem[1][0],int): 976 raise MadGraph5Error, error_msg%'split_order_amps' 977 else: 978 raise MadGraph5Error, error_msg%'split_order_amps' 979 980 if not split_order_names is None: 981 if isinstance(split_order_names,list): 982 # Should specify the same number of names as there are elements 983 # in the key of the split_order_amps. 984 if len(split_order_names)!=len(split_order_amps[0][0]): 985 raise MadGraph5Error, error_msg%'split_order_names' 986 # Check the first element of the list to be a string 987 if not isinstance(split_order_names[0],str): 988 raise MadGraph5Error, error_msg%'split_order_names' 989 else: 990 raise MadGraph5Error, error_msg%'split_order_names' 991 992 # Now scan all contributing orders to be individually computed and 993 # construct the list of color_amplitudes for JAMP to be constructed 994 # accordingly. 995 res_list=[] 996 for i, amp_order in enumerate(split_order_amps): 997 col_amps_order = [] 998 for jamp in color_amplitudes: 999 col_amps_order.append(filter(lambda col_amp: 1000 col_amp[1] in amp_order[1],jamp)) 1001 if split_order_names: 1002 res_list.append('C JAMPs contributing to orders '+' '.join( 1003 ['%s=%i'%order for order in zip(split_order_names, 1004 amp_order[0])])) 1005 res_list.extend(self.get_JAMP_lines(col_amps_order, 1006 JAMP_format="JAMP(%s,{0})".format(str(i+1)))) 1007 1008 return res_list
1009
1010 - def get_JAMP_lines(self, col_amps, JAMP_format="JAMP(%s)", 1011 AMP_format="AMP(%s)", split=-1):
1012 """Return the JAMP = sum(fermionfactor * AMP(i)) lines from col_amps 1013 defined as a matrix element or directly as a color_amplitudes dictionary. 1014 The split argument defines how the JAMP lines should be split in order 1015 not to be too long.""" 1016 1017 # Let the user call get_JAMP_lines directly from a MatrixElement or from 1018 # the color amplitudes lists. 1019 if(isinstance(col_amps,helas_objects.HelasMatrixElement)): 1020 color_amplitudes=col_amps.get_color_amplitudes() 1021 elif(isinstance(col_amps,list)): 1022 if(col_amps and isinstance(col_amps[0],list)): 1023 color_amplitudes=col_amps 1024 else: 1025 raise MadGraph5Error, "Incorrect col_amps argument passed to get_JAMP_lines" 1026 else: 1027 raise MadGraph5Error, "Incorrect col_amps argument passed to get_JAMP_lines" 1028 1029 1030 res_list = [] 1031 for i, coeff_list in enumerate(color_amplitudes): 1032 # It might happen that coeff_list is empty if this function was 1033 # called from get_JAMP_lines_split_order (i.e. if some color flow 1034 # does not contribute at all for a given order). 1035 # In this case we simply set it to 0. 1036 if coeff_list==[]: 1037 res_list.append(((JAMP_format+"=0D0") % str(i + 1))) 1038 continue 1039 # Break the JAMP definition into 'n=split' pieces to avoid having 1040 # arbitrarly long lines. 1041 first=True 1042 n = (len(coeff_list)+1 if split<=0 else split) 1043 while coeff_list!=[]: 1044 coefs=coeff_list[:n] 1045 coeff_list=coeff_list[n:] 1046 res = ((JAMP_format+"=") % str(i + 1)) + \ 1047 ((JAMP_format % str(i + 1)) if not first and split>0 else '') 1048 first=False 1049 # Optimization: if all contributions to that color basis element have 1050 # the same coefficient (up to a sign), put it in front 1051 list_fracs = [abs(coefficient[0][1]) for coefficient in coefs] 1052 common_factor = False 1053 diff_fracs = list(set(list_fracs)) 1054 if len(diff_fracs) == 1 and abs(diff_fracs[0]) != 1: 1055 common_factor = True 1056 global_factor = diff_fracs[0] 1057 res = res + '%s(' % self.coeff(1, global_factor, False, 0) 1058 1059 for (coefficient, amp_number) in coefs: 1060 if common_factor: 1061 res = (res + "%s" + AMP_format) % \ 1062 (self.coeff(coefficient[0], 1063 coefficient[1] / abs(coefficient[1]), 1064 coefficient[2], 1065 coefficient[3]), 1066 str(amp_number)) 1067 else: 1068 res = (res + "%s" + AMP_format) % (self.coeff(coefficient[0], 1069 coefficient[1], 1070 coefficient[2], 1071 coefficient[3]), 1072 str(amp_number)) 1073 1074 if common_factor: 1075 res = res + ')' 1076 1077 res_list.append(res) 1078 1079 return res_list
1080
1081 - def get_pdf_lines(self, matrix_element, ninitial, subproc_group = False):
1082 """Generate the PDF lines for the auto_dsig.f file""" 1083 1084 processes = matrix_element.get('processes') 1085 model = processes[0].get('model') 1086 1087 pdf_definition_lines = "" 1088 pdf_data_lines = "" 1089 pdf_lines = "" 1090 1091 if ninitial == 1: 1092 pdf_lines = "PD(0) = 0d0\nIPROC = 0\n" 1093 for i, proc in enumerate(processes): 1094 process_line = proc.base_string() 1095 pdf_lines = pdf_lines + "IPROC=IPROC+1 ! " + process_line 1096 pdf_lines = pdf_lines + "\nPD(IPROC)=1d0\n" 1097 pdf_lines = pdf_lines + "\nPD(0)=PD(0)+PD(IPROC)\n" 1098 else: 1099 # Pick out all initial state particles for the two beams 1100 initial_states = [sorted(list(set([p.get_initial_pdg(1) for \ 1101 p in processes]))), 1102 sorted(list(set([p.get_initial_pdg(2) for \ 1103 p in processes])))] 1104 1105 # Prepare all variable names 1106 pdf_codes = dict([(p, model.get_particle(p).get_name()) for p in \ 1107 sum(initial_states,[])]) 1108 for key,val in pdf_codes.items(): 1109 pdf_codes[key] = val.replace('~','x').replace('+','p').replace('-','m') 1110 1111 # Set conversion from PDG code to number used in PDF calls 1112 pdgtopdf = {21: 0, 22: 7} 1113 1114 # Fill in missing entries of pdgtopdf 1115 for pdg in sum(initial_states,[]): 1116 if not pdg in pdgtopdf and not pdg in pdgtopdf.values(): 1117 pdgtopdf[pdg] = pdg 1118 elif pdg not in pdgtopdf and pdg in pdgtopdf.values(): 1119 # If any particle has pdg code 7, we need to use something else 1120 pdgtopdf[pdg] = 6000000 + pdg 1121 1122 # Get PDF variable declarations for all initial states 1123 for i in [0,1]: 1124 pdf_definition_lines += "DOUBLE PRECISION " + \ 1125 ",".join(["%s%d" % (pdf_codes[pdg],i+1) \ 1126 for pdg in \ 1127 initial_states[i]]) + \ 1128 "\n" 1129 1130 # Get PDF data lines for all initial states 1131 for i in [0,1]: 1132 pdf_data_lines += "DATA " + \ 1133 ",".join(["%s%d" % (pdf_codes[pdg],i+1) \ 1134 for pdg in initial_states[i]]) + \ 1135 "/%d*1D0/" % len(initial_states[i]) + \ 1136 "\n" 1137 1138 # Get PDF lines for all different initial states 1139 for i, init_states in enumerate(initial_states): 1140 if subproc_group: 1141 pdf_lines = pdf_lines + \ 1142 "IF (ABS(LPP(IB(%d))).GE.1) THEN\nLP=SIGN(1,LPP(IB(%d)))\n" \ 1143 % (i + 1, i + 1) 1144 else: 1145 pdf_lines = pdf_lines + \ 1146 "IF (ABS(LPP(%d)) .GE. 1) THEN\nLP=SIGN(1,LPP(%d))\n" \ 1147 % (i + 1, i + 1) 1148 1149 for initial_state in init_states: 1150 if initial_state in pdf_codes.keys(): 1151 if subproc_group: 1152 pdf_lines = pdf_lines + \ 1153 ("%s%d=PDG2PDF(ABS(LPP(IB(%d))),%d*LP," + \ 1154 "XBK(IB(%d)),DSQRT(Q2FACT(%d)))\n") % \ 1155 (pdf_codes[initial_state], 1156 i + 1, i + 1, pdgtopdf[initial_state], 1157 i + 1, i + 1) 1158 else: 1159 pdf_lines = pdf_lines + \ 1160 ("%s%d=PDG2PDF(ABS(LPP(%d)),%d*LP," + \ 1161 "XBK(%d),DSQRT(Q2FACT(%d)))\n") % \ 1162 (pdf_codes[initial_state], 1163 i + 1, i + 1, pdgtopdf[initial_state], 1164 i + 1, i + 1) 1165 pdf_lines = pdf_lines + "ENDIF\n" 1166 1167 # Add up PDFs for the different initial state particles 1168 pdf_lines = pdf_lines + "PD(0) = 0d0\nIPROC = 0\n" 1169 for proc in processes: 1170 process_line = proc.base_string() 1171 pdf_lines = pdf_lines + "IPROC=IPROC+1 ! " + process_line 1172 pdf_lines = pdf_lines + "\nPD(IPROC)=" 1173 for ibeam in [1, 2]: 1174 initial_state = proc.get_initial_pdg(ibeam) 1175 if initial_state in pdf_codes.keys(): 1176 pdf_lines = pdf_lines + "%s%d*" % \ 1177 (pdf_codes[initial_state], ibeam) 1178 else: 1179 pdf_lines = pdf_lines + "1d0*" 1180 # Remove last "*" from pdf_lines 1181 pdf_lines = pdf_lines[:-1] + "\n" 1182 pdf_lines = pdf_lines + "PD(0)=PD(0)+DABS(PD(IPROC))\n" 1183 1184 # Remove last line break from the return variables 1185 return pdf_definition_lines[:-1], pdf_data_lines[:-1], pdf_lines[:-1]
1186 1187 #=========================================================================== 1188 # write_props_file 1189 #===========================================================================
1190 - def write_props_file(self, writer, matrix_element, s_and_t_channels):
1191 """Write the props.inc file for MadEvent. Needs input from 1192 write_configs_file.""" 1193 1194 lines = [] 1195 1196 particle_dict = matrix_element.get('processes')[0].get('model').\ 1197 get('particle_dict') 1198 1199 for iconf, configs in enumerate(s_and_t_channels): 1200 for vertex in configs[0] + configs[1][:-1]: 1201 leg = vertex.get('legs')[-1] 1202 if leg.get('id') not in particle_dict: 1203 # Fake propagator used in multiparticle vertices 1204 mass = 'zero' 1205 width = 'zero' 1206 pow_part = 0 1207 else: 1208 particle = particle_dict[leg.get('id')] 1209 # Get mass 1210 if particle.get('mass').lower() == 'zero': 1211 mass = particle.get('mass') 1212 else: 1213 mass = "abs(%s)" % particle.get('mass') 1214 # Get width 1215 if particle.get('width').lower() == 'zero': 1216 width = particle.get('width') 1217 else: 1218 width = "abs(%s)" % particle.get('width') 1219 1220 pow_part = 1 + int(particle.is_boson()) 1221 1222 lines.append("prmass(%d,%d) = %s" % \ 1223 (leg.get('number'), iconf + 1, mass)) 1224 lines.append("prwidth(%d,%d) = %s" % \ 1225 (leg.get('number'), iconf + 1, width)) 1226 lines.append("pow(%d,%d) = %d" % \ 1227 (leg.get('number'), iconf + 1, pow_part)) 1228 1229 # Write the file 1230 writer.writelines(lines) 1231 1232 return True
1233 1234 #=========================================================================== 1235 # write_configs_file 1236 #===========================================================================
1237 - def write_configs_file(self, writer, matrix_element):
1238 """Write the configs.inc file for MadEvent""" 1239 1240 # Extract number of external particles 1241 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial() 1242 1243 configs = [(i+1, d) for i,d in enumerate(matrix_element.get('diagrams'))] 1244 mapconfigs = [c[0] for c in configs] 1245 model = matrix_element.get('processes')[0].get('model') 1246 return mapconfigs, self.write_configs_file_from_diagrams(writer, 1247 [[c[1]] for c in configs], 1248 mapconfigs, 1249 nexternal, ninitial, 1250 model)
1251 1252 #=========================================================================== 1253 # write_configs_file_from_diagrams 1254 #===========================================================================
1255 - def write_configs_file_from_diagrams(self, writer, configs, mapconfigs, 1256 nexternal, ninitial, model):
1257 """Write the actual configs.inc file. 1258 1259 configs is the diagrams corresponding to configs (each 1260 diagrams is a list of corresponding diagrams for all 1261 subprocesses, with None if there is no corresponding diagrams 1262 for a given process). 1263 mapconfigs gives the diagram number for each config. 1264 1265 For s-channels, we need to output one PDG for each subprocess in 1266 the subprocess group, in order to be able to pick the right 1267 one for multiprocesses.""" 1268 1269 lines = [] 1270 1271 s_and_t_channels = [] 1272 1273 minvert = min([max([d for d in config if d][0].get_vertex_leg_numbers()) \ 1274 for config in configs]) 1275 1276 # Number of subprocesses 1277 nsubprocs = len(configs[0]) 1278 1279 nconfigs = 0 1280 1281 new_pdg = model.get_first_non_pdg() 1282 1283 for iconfig, helas_diags in enumerate(configs): 1284 if any([vert > minvert for vert in 1285 [d for d in helas_diags if d][0].get_vertex_leg_numbers()]): 1286 # Only 3-vertices allowed in configs.inc 1287 continue 1288 nconfigs += 1 1289 1290 # Need s- and t-channels for all subprocesses, including 1291 # those that don't contribute to this config 1292 empty_verts = [] 1293 stchannels = [] 1294 for h in helas_diags: 1295 if h: 1296 # get_s_and_t_channels gives vertices starting from 1297 # final state external particles and working inwards 1298 stchannels.append(h.get('amplitudes')[0].\ 1299 get_s_and_t_channels(ninitial, model, new_pdg)) 1300 else: 1301 stchannels.append((empty_verts, None)) 1302 1303 # For t-channels, just need the first non-empty one 1304 tchannels = [t for s,t in stchannels if t != None][0] 1305 1306 # For s_and_t_channels (to be used later) use only first config 1307 s_and_t_channels.append([[s for s,t in stchannels if t != None][0], 1308 tchannels]) 1309 1310 # Make sure empty_verts is same length as real vertices 1311 if any([s for s,t in stchannels]): 1312 empty_verts[:] = [None]*max([len(s) for s,t in stchannels]) 1313 1314 # Reorganize s-channel vertices to get a list of all 1315 # subprocesses for each vertex 1316 schannels = zip(*[s for s,t in stchannels]) 1317 else: 1318 schannels = [] 1319 1320 allchannels = schannels 1321 if len(tchannels) > 1: 1322 # Write out tchannels only if there are any non-trivial ones 1323 allchannels = schannels + tchannels 1324 1325 # Write out propagators for s-channel and t-channel vertices 1326 1327 lines.append("# Diagram %d" % (mapconfigs[iconfig])) 1328 # Correspondance between the config and the diagram = amp2 1329 lines.append("data mapconfig(%d)/%d/" % (nconfigs, 1330 mapconfigs[iconfig])) 1331 1332 for verts in allchannels: 1333 if verts in schannels: 1334 vert = [v for v in verts if v][0] 1335 else: 1336 vert = verts 1337 daughters = [leg.get('number') for leg in vert.get('legs')[:-1]] 1338 last_leg = vert.get('legs')[-1] 1339 lines.append("data (iforest(i,%d,%d),i=1,%d)/%s/" % \ 1340 (last_leg.get('number'), nconfigs, len(daughters), 1341 ",".join([str(d) for d in daughters]))) 1342 if verts in schannels: 1343 pdgs = [] 1344 for v in verts: 1345 if v: 1346 pdgs.append(v.get('legs')[-1].get('id')) 1347 else: 1348 pdgs.append(0) 1349 lines.append("data (sprop(i,%d,%d),i=1,%d)/%s/" % \ 1350 (last_leg.get('number'), nconfigs, nsubprocs, 1351 ",".join([str(d) for d in pdgs]))) 1352 lines.append("data tprid(%d,%d)/0/" % \ 1353 (last_leg.get('number'), nconfigs)) 1354 elif verts in tchannels[:-1]: 1355 lines.append("data tprid(%d,%d)/%d/" % \ 1356 (last_leg.get('number'), nconfigs, 1357 abs(last_leg.get('id')))) 1358 lines.append("data (sprop(i,%d,%d),i=1,%d)/%s/" % \ 1359 (last_leg.get('number'), nconfigs, nsubprocs, 1360 ",".join(['0'] * nsubprocs))) 1361 1362 # Write out number of configs 1363 lines.append("# Number of configs") 1364 lines.append("data mapconfig(0)/%d/" % nconfigs) 1365 1366 # Write the file 1367 writer.writelines(lines) 1368 1369 return s_and_t_channels
1370 1371 #=========================================================================== 1372 # Global helper methods 1373 #=========================================================================== 1374
1375 - def coeff(self, ff_number, frac, is_imaginary, Nc_power, Nc_value=3):
1376 """Returns a nicely formatted string for the coefficients in JAMP lines""" 1377 1378 total_coeff = ff_number * frac * fractions.Fraction(Nc_value) ** Nc_power 1379 1380 if total_coeff == 1: 1381 if is_imaginary: 1382 return '+imag1*' 1383 else: 1384 return '+' 1385 elif total_coeff == -1: 1386 if is_imaginary: 1387 return '-imag1*' 1388 else: 1389 return '-' 1390 1391 res_str = '%+iD0' % total_coeff.numerator 1392 1393 if total_coeff.denominator != 1: 1394 # Check if total_coeff is an integer 1395 res_str = res_str + '/%iD0' % total_coeff.denominator 1396 1397 if is_imaginary: 1398 res_str = res_str + '*imag1' 1399 1400 return res_str + '*'
1401 1402
1403 - def set_fortran_compiler(self, default_compiler, force=False):
1404 """Set compiler based on what's available on the system""" 1405 1406 # Check for compiler 1407 if default_compiler and misc.which(default_compiler): 1408 compiler = default_compiler 1409 elif misc.which('gfortran'): 1410 compiler = 'gfortran' 1411 elif misc.which('g77'): 1412 compiler = 'g77' 1413 elif misc.which('f77'): 1414 compiler = 'f77' 1415 elif default_compiler: 1416 logger.warning('No Fortran Compiler detected! Please install one') 1417 compiler = default_compiler # maybe misc fail so try with it 1418 else: 1419 raise MadGraph5Error, 'No Fortran Compiler detected! Please install one' 1420 logger.info('Use Fortran compiler ' + compiler) 1421 self.replace_make_opt_f_compiler(compiler) 1422 # Replace also for Template but not for cluster 1423 if not os.environ.has_key('MADGRAPH_DATA') and ReadWrite: 1424 self.replace_make_opt_f_compiler(compiler, pjoin(MG5DIR, 'Template', 'LO')) 1425 1426 return compiler
1427 1428 # an alias for backward compatibility 1429 set_compiler = set_fortran_compiler 1430 1431
1432 - def set_cpp_compiler(self, default_compiler, force=False):
1433 """Set compiler based on what's available on the system""" 1434 1435 # Check for compiler 1436 if default_compiler and misc.which(default_compiler): 1437 compiler = default_compiler 1438 elif misc.which('g++'): 1439 compiler = 'g++' 1440 elif misc.which('c++'): 1441 compiler = 'c++' 1442 elif misc.which('clang'): 1443 compiler = 'clang' 1444 elif default_compiler: 1445 logger.warning('No c++ Compiler detected! Please install one') 1446 compiler = default_compiler # maybe misc fail so try with it 1447 else: 1448 raise MadGraph5Error, 'No c++ Compiler detected! Please install one' 1449 logger.info('Use c++ compiler ' + compiler) 1450 self.replace_make_opt_c_compiler(compiler) 1451 # Replace also for Template but not for cluster 1452 if not os.environ.has_key('MADGRAPH_DATA') and ReadWrite: 1453 self.replace_make_opt_c_compiler(compiler, pjoin(MG5DIR, 'Template', 'LO')) 1454 1455 return compiler
1456 1457
1458 - def replace_make_opt_f_compiler(self, compiler, root_dir = ""):
1459 """Set FC=compiler in Source/make_opts""" 1460 1461 mod = False #avoid to rewrite the file if not needed 1462 if not root_dir: 1463 root_dir = self.dir_path 1464 1465 make_opts = pjoin(root_dir, 'Source', 'make_opts') 1466 lines = open(make_opts).read().split('\n') 1467 FC_re = re.compile('^(\s*)FC\s*=\s*(.+)\s*$') 1468 for iline, line in enumerate(lines): 1469 FC_result = FC_re.match(line) 1470 if FC_result: 1471 if compiler != FC_result.group(2): 1472 mod = True 1473 lines[iline] = FC_result.group(1) + "FC=" + compiler 1474 if not mod: 1475 return 1476 try: 1477 outfile = open(make_opts, 'w') 1478 except IOError: 1479 if root_dir == self.dir_path: 1480 logger.info('Fail to set compiler. Trying to continue anyway.') 1481 return 1482 outfile.write('\n'.join(lines))
1483 1484
1485 - def replace_make_opt_c_compiler(self, compiler, root_dir = ""):
1486 """Set CXX=compiler in Source/make_opts. 1487 The version is also checked, in order to set some extra flags 1488 if the compiler is clang (on MACOS)""" 1489 1490 1491 p = misc.Popen([compiler, '--version'], stdout=subprocess.PIPE, 1492 stderr=subprocess.PIPE) 1493 output, error = p.communicate() 1494 is_clang = 'LLVM' in output 1495 1496 mod = False #avoid to rewrite the file if not needed 1497 if not root_dir: 1498 root_dir = self.dir_path 1499 make_opts = pjoin(root_dir, 'Source', 'make_opts') 1500 lines = open(make_opts).read().split('\n') 1501 CC_re = re.compile('^(\s*)CXX\s*=\s*(.+)\s*$') 1502 for iline, line in enumerate(lines): 1503 CC_result = CC_re.match(line) 1504 if CC_result: 1505 if compiler != CC_result.group(2): 1506 mod = True 1507 lines[iline] = CC_result.group(1) + "CXX=" + compiler 1508 1509 if is_clang: 1510 CFLAGS_re=re.compile('^(\s*)CFLAGS\s*=\s*(.+)\s*$') 1511 CXXFLAGS_re=re.compile('^(\s*)CXXFLAGS\s*=\s*(.+)\s*$') 1512 flags= '-O -stdlib=libstdc++ -mmacosx-version-min=10.6' 1513 for iline, line in enumerate(lines): 1514 CF_result = CFLAGS_re.match(line) 1515 CXXF_result = CXXFLAGS_re.match(line) 1516 if CF_result: 1517 lines[iline] = CF_result.group(1) + "CFLAGS= " + flags 1518 if CXXF_result: 1519 lines[iline] = CXXF_result.group(1) + "CXXFLAGS= " + flags 1520 if not mod: 1521 return 1522 try: 1523 outfile = open(make_opts, 'w') 1524 except IOError: 1525 if root_dir == self.dir_path: 1526 logger.info('Fail to set compiler. Trying to continue anyway.') 1527 return 1528 outfile.write('\n'.join(lines))
1529 1530 #=============================================================================== 1531 # ProcessExporterFortranSA 1532 #===============================================================================
1533 -class ProcessExporterFortranSA(ProcessExporterFortran):
1534 """Class to take care of exporting a set of matrix elements to 1535 MadGraph v4 StandAlone format.""" 1536
1537 - def __init__(self, *args, **opts):
1538 """add the format information compare to standard init""" 1539 1540 if 'format' in opts: 1541 self.format = opts['format'] 1542 del opts['format'] 1543 else: 1544 self.format = 'standalone' 1545 ProcessExporterFortran.__init__(self, *args, **opts)
1546
1547 - def copy_v4template(self, modelname):
1548 """Additional actions needed for setup of Template 1549 """ 1550 1551 #First copy the full template tree if dir_path doesn't exit 1552 if os.path.isdir(self.dir_path): 1553 return 1554 1555 logger.info('initialize a new standalone directory: %s' % \ 1556 os.path.basename(self.dir_path)) 1557 temp_dir = pjoin(self.mgme_dir, 'Template/LO') 1558 1559 # Create the directory structure 1560 os.mkdir(self.dir_path) 1561 os.mkdir(pjoin(self.dir_path, 'Source')) 1562 os.mkdir(pjoin(self.dir_path, 'Source', 'MODEL')) 1563 os.mkdir(pjoin(self.dir_path, 'Source', 'DHELAS')) 1564 os.mkdir(pjoin(self.dir_path, 'SubProcesses')) 1565 os.mkdir(pjoin(self.dir_path, 'bin')) 1566 os.mkdir(pjoin(self.dir_path, 'bin', 'internal')) 1567 os.mkdir(pjoin(self.dir_path, 'lib')) 1568 os.mkdir(pjoin(self.dir_path, 'Cards')) 1569 1570 # Information at top-level 1571 #Write version info 1572 shutil.copy(pjoin(temp_dir, 'TemplateVersion.txt'), self.dir_path) 1573 try: 1574 shutil.copy(pjoin(self.mgme_dir, 'MGMEVersion.txt'), self.dir_path) 1575 except IOError: 1576 MG5_version = misc.get_pkg_info() 1577 open(pjoin(self.dir_path, 'MGMEVersion.txt'), 'w').write( \ 1578 "5." + MG5_version['version']) 1579 1580 # Add file in bin directory 1581 #shutil.copy(pjoin(temp_dir, 'bin', 'change_compiler.py'), 1582 # pjoin(self.dir_path, 'bin')) 1583 1584 # Add file in SubProcesses 1585 shutil.copy(pjoin(self.mgme_dir, 'madgraph', 'iolibs', 'template_files', 'makefile_sa_f_sp'), 1586 pjoin(self.dir_path, 'SubProcesses', 'makefile')) 1587 1588 if self.format == 'standalone': 1589 shutil.copy(pjoin(self.mgme_dir, 'madgraph', 'iolibs', 'template_files', 'check_sa.f'), 1590 pjoin(self.dir_path, 'SubProcesses', 'check_sa.f')) 1591 elif self.format == 'standalone_rw': 1592 shutil.copy(pjoin(self.mgme_dir, 'madgraph', 'iolibs', 'template_files', 'driver_reweight.f'), 1593 pjoin(self.dir_path, 'SubProcesses', 'check_sa.f')) 1594 1595 # Add file in Source 1596 shutil.copy(pjoin(temp_dir, 'Source', 'make_opts'), 1597 pjoin(self.dir_path, 'Source')) 1598 # add the makefile 1599 filename = pjoin(self.dir_path,'Source','makefile') 1600 self.write_source_makefile(writers.FileWriter(filename))
1601 1602 #=========================================================================== 1603 # export model files 1604 #===========================================================================
1605 - def export_model_files(self, model_path):
1606 """export the model dependent files for V4 model""" 1607 1608 super(ProcessExporterFortranSA,self).export_model_files(model_path) 1609 # Add the routine update_as_param in v4 model 1610 # This is a function created in the UFO 1611 1612 1613 text = open(pjoin(self.dir_path,'SubProcesses','check_sa.f')).read() 1614 text = text.replace('call setpara(\'param_card.dat\')', 'call setpara(\'param_card.dat\', .true.)') 1615 fsock = open(pjoin(self.dir_path,'SubProcesses','check_sa.f'), 'w') 1616 fsock.write(text) 1617 fsock.close() 1618 1619 self.make_model_symbolic_link()
1620 1621 #=========================================================================== 1622 # Make the Helas and Model directories for Standalone directory 1623 #===========================================================================
1624 - def make(self):
1625 """Run make in the DHELAS and MODEL directories, to set up 1626 everything for running standalone 1627 """ 1628 1629 source_dir = pjoin(self.dir_path, "Source") 1630 logger.info("Running make for Helas") 1631 misc.compile(arg=['../lib/libdhelas.a'], cwd=source_dir, mode='fortran') 1632 logger.info("Running make for Model") 1633 misc.compile(arg=['../lib/libmodel.a'], cwd=source_dir, mode='fortran')
1634 1635 #=========================================================================== 1636 # Create proc_card_mg5.dat for Standalone directory 1637 #===========================================================================
1638 - def finalize_v4_directory(self, matrix_elements, history, makejpg = False, 1639 online = False, compiler='gfortran'):
1640 """Finalize Standalone MG4 directory by generation proc_card_mg5.dat""" 1641 1642 self.compiler_choice(compiler) 1643 self.make() 1644 1645 # Write command history as proc_card_mg5 1646 if history and os.path.isdir(pjoin(self.dir_path, 'Cards')): 1647 output_file = pjoin(self.dir_path, 'Cards', 'proc_card_mg5.dat') 1648 history.write(output_file)
1649
1650 - def compiler_choice(self, compiler):
1651 """ Different daughter classes might want different compilers. 1652 So this function is meant to be overloaded if desired.""" 1653 1654 self.set_compiler(compiler)
1655 1656 #=========================================================================== 1657 # generate_subprocess_directory_v4 1658 #===========================================================================
1659 - def generate_subprocess_directory_v4(self, matrix_element, 1660 fortran_model):
1661 """Generate the Pxxxxx directory for a subprocess in MG4 standalone, 1662 including the necessary matrix.f and nexternal.inc files""" 1663 1664 cwd = os.getcwd() 1665 1666 # Create the directory PN_xx_xxxxx in the specified path 1667 dirpath = pjoin(self.dir_path, 'SubProcesses', \ 1668 "P%s" % matrix_element.get('processes')[0].shell_string()) 1669 1670 if self.opt['sa_symmetry']: 1671 # avoid symmetric output 1672 for i,proc in enumerate(matrix_element.get('processes')): 1673 1674 initial = [] #filled in the next line 1675 final = [l.get('id') for l in proc.get('legs')\ 1676 if l.get('state') or initial.append(l.get('id'))] 1677 decay_finals = proc.get_final_ids_after_decay() 1678 decay_finals.sort() 1679 tag = (tuple(initial), tuple(decay_finals)) 1680 legs = proc.get('legs')[:] 1681 leg0 = proc.get('legs')[0] 1682 leg1 = proc.get('legs')[1] 1683 if not leg1.get('state'): 1684 proc.get('legs')[0] = leg1 1685 proc.get('legs')[1] = leg0 1686 flegs = proc.get('legs')[2:] 1687 for perm in itertools.permutations(flegs): 1688 for i,p in enumerate(perm): 1689 proc.get('legs')[i+2] = p 1690 dirpath2 = pjoin(self.dir_path, 'SubProcesses', \ 1691 "P%s" % proc.shell_string()) 1692 #restore original order 1693 proc.get('legs')[2:] = legs[2:] 1694 if os.path.exists(dirpath2): 1695 proc.get('legs')[:] = legs 1696 return 0 1697 proc.get('legs')[:] = legs 1698 1699 try: 1700 os.mkdir(dirpath) 1701 except os.error as error: 1702 logger.warning(error.strerror + " " + dirpath) 1703 1704 #try: 1705 # os.chdir(dirpath) 1706 #except os.error: 1707 # logger.error('Could not cd to directory %s' % dirpath) 1708 # return 0 1709 1710 logger.info('Creating files in directory %s' % dirpath) 1711 1712 # Extract number of external particles 1713 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial() 1714 1715 # Create the matrix.f file and the nexternal.inc file 1716 if self.opt['export_format']=='standalone_msP': 1717 filename = pjoin(dirpath, 'matrix_prod.f') 1718 else: 1719 filename = pjoin(dirpath, 'matrix.f') 1720 calls = self.write_matrix_element_v4( 1721 writers.FortranWriter(filename), 1722 matrix_element, 1723 fortran_model) 1724 1725 if self.opt['export_format'] == 'standalone_msP': 1726 filename = pjoin(dirpath,'configs_production.inc') 1727 mapconfigs, s_and_t_channels = self.write_configs_file(\ 1728 writers.FortranWriter(filename), 1729 matrix_element) 1730 1731 filename = pjoin(dirpath,'props_production.inc') 1732 self.write_props_file(writers.FortranWriter(filename), 1733 matrix_element, 1734 s_and_t_channels) 1735 1736 filename = pjoin(dirpath,'nexternal_prod.inc') 1737 self.write_nexternal_madspin(writers.FortranWriter(filename), 1738 nexternal, ninitial) 1739 1740 if self.opt['export_format']=='standalone_msF': 1741 filename = pjoin(dirpath, 'helamp.inc') 1742 ncomb=matrix_element.get_helicity_combinations() 1743 self.write_helamp_madspin(writers.FortranWriter(filename), 1744 ncomb) 1745 1746 filename = pjoin(dirpath, 'nexternal.inc') 1747 self.write_nexternal_file(writers.FortranWriter(filename), 1748 nexternal, ninitial) 1749 1750 filename = pjoin(dirpath, 'pmass.inc') 1751 self.write_pmass_file(writers.FortranWriter(filename), 1752 matrix_element) 1753 1754 filename = pjoin(dirpath, 'ngraphs.inc') 1755 self.write_ngraphs_file(writers.FortranWriter(filename), 1756 len(matrix_element.get_all_amplitudes())) 1757 1758 # Generate diagrams 1759 filename = pjoin(dirpath, "matrix.ps") 1760 plot = draw.MultiEpsDiagramDrawer(matrix_element.get('base_amplitude').\ 1761 get('diagrams'), 1762 filename, 1763 model=matrix_element.get('processes')[0].\ 1764 get('model'), 1765 amplitude=True) 1766 logger.info("Generating Feynman diagrams for " + \ 1767 matrix_element.get('processes')[0].nice_string()) 1768 plot.draw() 1769 1770 linkfiles = ['check_sa.f', 'coupl.inc', 'makefile'] 1771 1772 for file in linkfiles: 1773 ln('../%s' % file, cwd=dirpath) 1774 1775 # Return to original PWD 1776 #os.chdir(cwd) 1777 1778 if not calls: 1779 calls = 0 1780 return calls
1781 1782 1783 #=========================================================================== 1784 # write_source_makefile 1785 #===========================================================================
1786 - def write_source_makefile(self, writer):
1787 """Write the nexternal.inc file for MG4""" 1788 1789 1790 path = pjoin(_file_path,'iolibs','template_files','madevent_makefile_source') 1791 set_of_lib = '$(LIBDIR)libdhelas.$(libext) $(LIBDIR)libmodel.$(libext)' 1792 model_line='''$(LIBDIR)libmodel.$(libext): MODEL\n\t cd MODEL; make\n''' 1793 text = open(path).read() % {'libraries': set_of_lib, 'model':model_line} 1794 writer.write(text) 1795 1796 return True
1797 1798 #=========================================================================== 1799 # write_matrix_element_v4 1800 #===========================================================================
1801 - def write_matrix_element_v4(self, writer, matrix_element, fortran_model, 1802 proc_prefix=''):
1803 """Export a matrix element to a matrix.f file in MG4 standalone format""" 1804 1805 if not matrix_element.get('processes') or \ 1806 not matrix_element.get('diagrams'): 1807 return 0 1808 1809 if not isinstance(writer, writers.FortranWriter): 1810 raise writers.FortranWriter.FortranWriterError(\ 1811 "writer not FortranWriter") 1812 1813 if not self.opt.has_key('sa_symmetry'): 1814 self.opt['sa_symmetry']=False 1815 1816 # Set lowercase/uppercase Fortran code 1817 writers.FortranWriter.downcase = False 1818 1819 # The proc_id is for MadEvent grouping which is never used in SA. 1820 replace_dict = {'global_variable':'', 'amp2_lines':'', 1821 'proc_prefix':proc_prefix, 'proc_id':''} 1822 1823 # Extract helas calls 1824 helas_calls = fortran_model.get_matrix_element_calls(\ 1825 matrix_element) 1826 1827 replace_dict['helas_calls'] = "\n".join(helas_calls) 1828 1829 # Extract version number and date from VERSION file 1830 info_lines = self.get_mg5_info_lines() 1831 replace_dict['info_lines'] = info_lines 1832 1833 # Extract process info lines 1834 process_lines = self.get_process_info_lines(matrix_element) 1835 replace_dict['process_lines'] = process_lines 1836 1837 # Extract number of external particles 1838 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial() 1839 replace_dict['nexternal'] = nexternal 1840 1841 # Extract ncomb 1842 ncomb = matrix_element.get_helicity_combinations() 1843 replace_dict['ncomb'] = ncomb 1844 1845 # Extract helicity lines 1846 helicity_lines = self.get_helicity_lines(matrix_element) 1847 replace_dict['helicity_lines'] = helicity_lines 1848 1849 # Extract overall denominator 1850 # Averaging initial state color, spin, and identical FS particles 1851 replace_dict['den_factor_line'] = self.get_den_factor_line(matrix_element) 1852 1853 # Extract ngraphs 1854 ngraphs = matrix_element.get_number_of_amplitudes() 1855 replace_dict['ngraphs'] = ngraphs 1856 1857 # Extract nwavefuncs 1858 nwavefuncs = matrix_element.get_number_of_wavefunctions() 1859 replace_dict['nwavefuncs'] = nwavefuncs 1860 1861 # Extract ncolor 1862 ncolor = max(1, len(matrix_element.get('color_basis'))) 1863 replace_dict['ncolor'] = ncolor 1864 1865 replace_dict['hel_avg_factor'] = matrix_element.get_hel_avg_factor() 1866 1867 # Extract color data lines 1868 color_data_lines = self.get_color_data_lines(matrix_element) 1869 replace_dict['color_data_lines'] = "\n".join(color_data_lines) 1870 1871 if self.opt['export_format']=='standalone_msP': 1872 # For MadSpin need to return the AMP2 1873 amp2_lines = self.get_amp2_lines(matrix_element, [] ) 1874 replace_dict['amp2_lines'] = '\n'.join(amp2_lines) 1875 replace_dict['global_variable'] = \ 1876 " Double Precision amp2(NGRAPHS)\n common/to_amps/ amp2\n" 1877 1878 # JAMP definition, depends on the number of independent split orders 1879 split_orders=matrix_element.get('processes')[0].get('split_orders') 1880 1881 if len(split_orders)==0: 1882 replace_dict['nSplitOrders']='' 1883 # Extract JAMP lines 1884 jamp_lines = self.get_JAMP_lines(matrix_element) 1885 # Consider the output of a dummy order 'ALL_ORDERS' for which we 1886 # set all amplitude order to weight 1 and only one squared order 1887 # contribution which is of course ALL_ORDERS=2. 1888 squared_orders = [(2,),] 1889 amp_orders = [((1,),tuple(range(1,ngraphs+1)))] 1890 replace_dict['chosen_so_configs'] = '.TRUE.' 1891 replace_dict['nSqAmpSplitOrders']=1 1892 replace_dict['split_order_str_list']='' 1893 else: 1894 squared_orders, amp_orders = matrix_element.get_split_orders_mapping() 1895 replace_dict['nAmpSplitOrders']=len(amp_orders) 1896 replace_dict['nSqAmpSplitOrders']=len(squared_orders) 1897 replace_dict['nSplitOrders']=len(split_orders) 1898 replace_dict['split_order_str_list']=str(split_orders) 1899 amp_so = self.get_split_orders_lines( 1900 [amp_order[0] for amp_order in amp_orders],'AMPSPLITORDERS') 1901 sqamp_so = self.get_split_orders_lines(squared_orders,'SQSPLITORDERS') 1902 replace_dict['ampsplitorders']='\n'.join(amp_so) 1903 replace_dict['sqsplitorders']='\n'.join(sqamp_so) 1904 jamp_lines = self.get_JAMP_lines_split_order(\ 1905 matrix_element,amp_orders,split_order_names=split_orders) 1906 1907 # Now setup the array specifying what squared split order is chosen 1908 replace_dict['chosen_so_configs']=self.set_chosen_SO_index( 1909 matrix_element.get('processes')[0],squared_orders) 1910 1911 # For convenience we also write the driver check_sa_splitOrders.f 1912 # that explicitely writes out the contribution from each squared order. 1913 # The original driver still works and is compiled with 'make' while 1914 # the splitOrders one is compiled with 'make check_sa_born_splitOrders' 1915 check_sa_writer=writers.FortranWriter('check_sa_born_splitOrders.f') 1916 self.write_check_sa_splitOrders(\ 1917 squared_orders,split_orders,check_sa_writer) 1918 1919 writers.FortranWriter('nsqso_born.inc').writelines( 1920 """INTEGER NSQSO_BORN 1921 PARAMETER (NSQSO_BORN=%d)"""%replace_dict['nSqAmpSplitOrders']) 1922 1923 replace_dict['jamp_lines'] = '\n'.join(jamp_lines) 1924 if len(split_orders)>0: 1925 if self.opt['export_format']=='standalone_msP' : 1926 logger.debug("Warning: The export format standalone_msP is not "+\ 1927 " available for individual ME evaluation of given coupl. orders."+\ 1928 " Only the total ME will be computed.") 1929 file = open(pjoin(_file_path, \ 1930 'iolibs/template_files/matrix_standalone_msP_v4.inc')).read() 1931 1932 elif self.opt['export_format']=='standalone_msF': 1933 logger.debug("Warning: The export format standalone_msF is not "+\ 1934 " available for individual ME evaluation of given coupl. orders."+\ 1935 " Only the total ME will be computed.") 1936 file = open(pjoin(_file_path, \ 1937 'iolibs/template_files/matrix_standalone_msF_v4.inc')).read() 1938 else: 1939 file = open(pjoin(_file_path, \ 1940 'iolibs/template_files/matrix_standalone_splitOrders_v4.inc')).read() 1941 else: 1942 if self.opt['export_format']=='standalone_msP' : 1943 file = open(pjoin(_file_path, \ 1944 'iolibs/template_files/matrix_standalone_msP_v4.inc')).read() 1945 1946 elif self.opt['export_format']=='standalone_msF': 1947 file = open(pjoin(_file_path, \ 1948 'iolibs/template_files/matrix_standalone_msF_v4.inc')).read() 1949 else: 1950 file = open(pjoin(_file_path, \ 1951 'iolibs/template_files/matrix_standalone_v4.inc')).read() 1952 1953 file = file % replace_dict 1954 1955 # Add the helper functions. 1956 if len(split_orders)>0: 1957 file = file + '\n' + open(pjoin(_file_path, \ 1958 'iolibs/template_files/split_orders_helping_functions.inc'))\ 1959 .read()%replace_dict 1960 1961 # Write the file 1962 writer.writelines(file) 1963 1964 return len(filter(lambda call: call.find('#') != 0, helas_calls))
1965
1966 - def write_check_sa_splitOrders(self,squared_orders, split_orders, writer):
1967 """ Write out a more advanced version of the check_sa drivers that 1968 individually returns the matrix element for each contributing squared 1969 order.""" 1970 1971 check_sa_content = open(pjoin(self.mgme_dir, 'madgraph', 'iolibs', \ 1972 'template_files', 'check_sa_splitOrders.f')).read() 1973 printout_sq_orders=[] 1974 for i, squared_order in enumerate(squared_orders): 1975 sq_orders=[] 1976 for j, sqo in enumerate(squared_order): 1977 sq_orders.append('%s=%d'%(split_orders[j],sqo)) 1978 printout_sq_orders.append(\ 1979 "write(*,*) '%d) Matrix element for (%s) = ',MATELEMS(%d)"\ 1980 %(i+1,' '.join(sq_orders),i+1)) 1981 printout_sq_orders='\n'.join(printout_sq_orders) 1982 writer.writelines(check_sa_content%{\ 1983 'printout_sqorders':printout_sq_orders, 1984 'nSplitOrders':len(squared_orders)})
1985 1986 #=============================================================================== 1987 # ProcessExporterFortranMW 1988 #===============================================================================
1989 -class ProcessExporterFortranMW(ProcessExporterFortran):
1990 """Class to take care of exporting a set of matrix elements to 1991 MadGraph v4 - MadWeight format.""" 1992 1993 matrix_file="matrix_standalone_v4.inc" 1994
1995 - def copy_v4template(self, modelname):
1996 """Additional actions needed for setup of Template 1997 """ 1998 1999 super(ProcessExporterFortranMW, self).copy_v4template(modelname) 2000 2001 # Add the MW specific file 2002 shutil.copytree(pjoin(MG5DIR,'Template','MadWeight'), 2003 pjoin(self.dir_path, 'Source','MadWeight'), True) 2004 shutil.copytree(pjoin(MG5DIR,'madgraph','madweight'), 2005 pjoin(self.dir_path, 'bin','internal','madweight'), True) 2006 files.mv(pjoin(self.dir_path, 'Source','MadWeight','src','setrun.f'), 2007 pjoin(self.dir_path, 'Source','setrun.f')) 2008 files.mv(pjoin(self.dir_path, 'Source','MadWeight','src','run.inc'), 2009 pjoin(self.dir_path, 'Source','run.inc')) 2010 # File created from Template (Different in some child class) 2011 filename = os.path.join(self.dir_path,'Source','run_config.inc') 2012 self.write_run_config_file(writers.FortranWriter(filename)) 2013 2014 try: 2015 subprocess.call([os.path.join(self.dir_path, 'Source','MadWeight','bin','internal','pass_to_madweight')], 2016 stdout = os.open(os.devnull, os.O_RDWR), 2017 stderr = os.open(os.devnull, os.O_RDWR), 2018 cwd=self.dir_path) 2019 except OSError: 2020 # Probably madweight already called 2021 pass 2022 2023 # Copy the different python file in the Template 2024 self.copy_python_file() 2025 # create the appropriate cuts.f 2026 self.get_mw_cuts_version() 2027 2028 # add the makefile in Source directory 2029 filename = os.path.join(self.dir_path,'Source','makefile') 2030 self.write_source_makefile(writers.FortranWriter(filename))
2031 2032 #=========================================================================== 2033 # convert_model_to_mg4 2034 #===========================================================================
2035 - def convert_model_to_mg4(self, model, wanted_lorentz = [], 2036 wanted_couplings = []):
2037 2038 super(ProcessExporterFortranMW,self).convert_model_to_mg4(model, 2039 wanted_lorentz, wanted_couplings) 2040 2041 IGNORE_PATTERNS = ('*.pyc','*.dat','*.py~') 2042 try: 2043 shutil.rmtree(pjoin(self.dir_path,'bin','internal','ufomodel')) 2044 except OSError as error: 2045 pass 2046 model_path = model.get('modelpath') 2047 # This is not safe if there is a '##' or '-' in the path. 2048 shutil.copytree(model_path, 2049 pjoin(self.dir_path,'bin','internal','ufomodel'), 2050 ignore=shutil.ignore_patterns(*IGNORE_PATTERNS)) 2051 if hasattr(model, 'restrict_card'): 2052 out_path = pjoin(self.dir_path, 'bin', 'internal','ufomodel', 2053 'restrict_default.dat') 2054 if isinstance(model.restrict_card, check_param_card.ParamCard): 2055 model.restrict_card.write(out_path) 2056 else: 2057 files.cp(model.restrict_card, out_path)
2058 2059 #=========================================================================== 2060 # generate_subprocess_directory_v4 2061 #===========================================================================
2062 - def copy_python_file(self):
2063 """copy the python file require for the Template""" 2064 2065 # madevent interface 2066 cp(_file_path+'/interface/madweight_interface.py', 2067 self.dir_path+'/bin/internal/madweight_interface.py') 2068 cp(_file_path+'/interface/extended_cmd.py', 2069 self.dir_path+'/bin/internal/extended_cmd.py') 2070 cp(_file_path+'/interface/common_run_interface.py', 2071 self.dir_path+'/bin/internal/common_run_interface.py') 2072 cp(_file_path+'/various/misc.py', self.dir_path+'/bin/internal/misc.py') 2073 cp(_file_path+'/iolibs/files.py', self.dir_path+'/bin/internal/files.py') 2074 #cp(_file_path+'/iolibs/save_load_object.py', 2075 # self.dir_path+'/bin/internal/save_load_object.py') 2076 cp(_file_path+'/iolibs/file_writers.py', 2077 self.dir_path+'/bin/internal/file_writers.py') 2078 #model file 2079 cp(_file_path+'../models/check_param_card.py', 2080 self.dir_path+'/bin/internal/check_param_card.py') 2081 2082 #madevent file 2083 cp(_file_path+'/__init__.py', self.dir_path+'/bin/internal/__init__.py') 2084 cp(_file_path+'/various/lhe_parser.py', 2085 self.dir_path+'/bin/internal/lhe_parser.py') 2086 #cp(_file_path+'/various/gen_crossxhtml.py', 2087 # self.dir_path+'/bin/internal/gen_crossxhtml.py') 2088 cp(_file_path+'/various/banner.py', 2089 self.dir_path+'/bin/internal/banner.py') 2090 cp(_file_path+'/various/cluster.py', 2091 self.dir_path+'/bin/internal/cluster.py') 2092 #cp(_file_path+'/various/sum_html.py', 2093 # self.dir_path+'/bin/internal/sum_html.py') 2094 #cp(_file_path+'/various/combine_runs.py', 2095 # self.dir_path+'/bin/internal/combine_runs.py') 2096 2097 # logging configuration 2098 cp(_file_path+'/interface/.mg5_logging.conf', 2099 self.dir_path+'/bin/internal/me5_logging.conf') 2100 cp(_file_path+'/interface/coloring_logging.py', 2101 self.dir_path+'/bin/internal/coloring_logging.py')
2102 2103 2104 #=========================================================================== 2105 # Make the Helas and Model directories for Standalone directory 2106 #===========================================================================
2107 - def get_mw_cuts_version(self, outpath=None):
2108 """create the appropriate cuts.f 2109 This is based on the one associated to ME output but: 2110 1) No clustering (=> remove initcluster/setclscales) 2111 2) Adding the definition of cut_bw at the file. 2112 """ 2113 2114 template = open(pjoin(MG5DIR,'Template','LO','SubProcesses','cuts.f')) 2115 2116 text = StringIO() 2117 #1) remove all dependencies in ickkw >1: 2118 nb_if = 0 2119 for line in template: 2120 if 'if(xqcut.gt.0d0' in line: 2121 nb_if = 1 2122 if nb_if == 0: 2123 text.write(line) 2124 continue 2125 if re.search(r'if\(.*\)\s*then', line): 2126 nb_if += 1 2127 elif 'endif' in line: 2128 nb_if -= 1 2129 2130 #2) add fake cut_bw (have to put the true one later) 2131 text.write(""" 2132 logical function cut_bw(p) 2133 include 'madweight_param.inc' 2134 double precision p(*) 2135 if (bw_cut) then 2136 cut_bw = .true. 2137 else 2138 stop 1 2139 endif 2140 return 2141 end 2142 """) 2143 2144 final = text.getvalue() 2145 #3) remove the call to initcluster: 2146 template = final.replace('call initcluster', '! Remove for MW!call initcluster') 2147 template = template.replace('genps.inc', 'maxparticles.inc') 2148 #Now we can write it 2149 if not outpath: 2150 fsock = open(pjoin(self.dir_path, 'SubProcesses', 'cuts.f'), 'w') 2151 elif isinstance(outpath, str): 2152 fsock = open(outpath, 'w') 2153 else: 2154 fsock = outpath 2155 fsock.write(template)
2156 2157 2158 2159 #=========================================================================== 2160 # Make the Helas and Model directories for Standalone directory 2161 #===========================================================================
2162 - def make(self):
2163 """Run make in the DHELAS, MODEL, PDF and CERNLIB directories, to set up 2164 everything for running madweight 2165 """ 2166 2167 source_dir = os.path.join(self.dir_path, "Source") 2168 logger.info("Running make for Helas") 2169 misc.compile(arg=['../lib/libdhelas.a'], cwd=source_dir, mode='fortran') 2170 logger.info("Running make for Model") 2171 misc.compile(arg=['../lib/libmodel.a'], cwd=source_dir, mode='fortran') 2172 logger.info("Running make for PDF") 2173 misc.compile(arg=['../lib/libpdf.a'], cwd=source_dir, mode='fortran') 2174 logger.info("Running make for CERNLIB") 2175 misc.compile(arg=['../lib/libcernlib.a'], cwd=source_dir, mode='fortran') 2176 logger.info("Running make for GENERIC") 2177 misc.compile(arg=['../lib/libgeneric.a'], cwd=source_dir, mode='fortran') 2178 logger.info("Running make for blocks") 2179 misc.compile(arg=['../lib/libblocks.a'], cwd=source_dir, mode='fortran') 2180 logger.info("Running make for tools") 2181 misc.compile(arg=['../lib/libtools.a'], cwd=source_dir, mode='fortran')
2182 2183 #=========================================================================== 2184 # Create proc_card_mg5.dat for MadWeight directory 2185 #===========================================================================
2186 - def finalize_v4_directory(self, matrix_elements, history, makejpg = False, 2187 online = False, compiler='g77'):
2188 """Finalize Standalone MG4 directory by generation proc_card_mg5.dat""" 2189 2190 # Write maxparticles.inc based on max of ME's/subprocess groups 2191 filename = pjoin(self.dir_path,'Source','maxparticles.inc') 2192 self.write_maxparticles_file(writers.FortranWriter(filename), 2193 matrix_elements) 2194 ln(pjoin(self.dir_path, 'Source', 'maxparticles.inc'), 2195 pjoin(self.dir_path, 'Source','MadWeight','blocks')) 2196 ln(pjoin(self.dir_path, 'Source', 'maxparticles.inc'), 2197 pjoin(self.dir_path, 'Source','MadWeight','tools')) 2198 2199 self.set_compiler(compiler) 2200 self.make() 2201 2202 # Write command history as proc_card_mg5 2203 if os.path.isdir(os.path.join(self.dir_path, 'Cards')): 2204 output_file = os.path.join(self.dir_path, 'Cards', 'proc_card_mg5.dat') 2205 history.write(output_file)
2206 2207 #=========================================================================== 2208 # export model files 2209 #===========================================================================
2210 - def export_model_files(self, model_path):
2211 """export the model dependent files for V4 model""" 2212 2213 super(ProcessExporterFortranMW,self).export_model_files(model_path) 2214 # Add the routine update_as_param in v4 model 2215 # This is a function created in the UFO 2216 text=""" 2217 subroutine update_as_param() 2218 call setpara('param_card.dat',.false.) 2219 return 2220 end 2221 """ 2222 ff = open(os.path.join(self.dir_path, 'Source', 'MODEL', 'couplings.f'),'a') 2223 ff.write(text) 2224 ff.close() 2225 2226 # Modify setrun.f 2227 text = open(os.path.join(self.dir_path,'Source','setrun.f')).read() 2228 text = text.replace('call setpara(param_card_name)', 'call setpara(param_card_name, .true.)') 2229 fsock = open(os.path.join(self.dir_path,'Source','setrun.f'), 'w') 2230 fsock.write(text) 2231 fsock.close() 2232 2233 # Modify initialization.f 2234 text = open(os.path.join(self.dir_path,'SubProcesses','initialization.f')).read() 2235 text = text.replace('call setpara(param_name)', 'call setpara(param_name, .true.)') 2236 fsock = open(os.path.join(self.dir_path,'SubProcesses','initialization.f'), 'w') 2237 fsock.write(text) 2238 fsock.close() 2239 2240 2241 self.make_model_symbolic_link()
2242 2243 #=========================================================================== 2244 # generate_subprocess_directory_v4 2245 #===========================================================================
2246 - def generate_subprocess_directory_v4(self, matrix_element, 2247 fortran_model,number):
2248 """Generate the Pxxxxx directory for a subprocess in MG4 MadWeight format, 2249 including the necessary matrix.f and nexternal.inc files""" 2250 2251 cwd = os.getcwd() 2252 2253 # Create the directory PN_xx_xxxxx in the specified path 2254 dirpath = os.path.join(self.dir_path, 'SubProcesses', \ 2255 "P%s" % matrix_element.get('processes')[0].shell_string()) 2256 2257 try: 2258 os.mkdir(dirpath) 2259 except os.error as error: 2260 logger.warning(error.strerror + " " + dirpath) 2261 2262 #try: 2263 # os.chdir(dirpath) 2264 #except os.error: 2265 # logger.error('Could not cd to directory %s' % dirpath) 2266 # return 0 2267 2268 logger.info('Creating files in directory %s' % dirpath) 2269 2270 # Extract number of external particles 2271 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial() 2272 2273 # Create the matrix.f file and the nexternal.inc file 2274 filename = pjoin(dirpath,'matrix.f') 2275 calls,ncolor = self.write_matrix_element_v4( 2276 writers.FortranWriter(filename), 2277 matrix_element, 2278 fortran_model) 2279 2280 filename = pjoin(dirpath, 'auto_dsig.f') 2281 self.write_auto_dsig_file(writers.FortranWriter(filename), 2282 matrix_element) 2283 2284 filename = pjoin(dirpath, 'configs.inc') 2285 mapconfigs, s_and_t_channels = self.write_configs_file(\ 2286 writers.FortranWriter(filename), 2287 matrix_element) 2288 2289 filename = pjoin(dirpath, 'nexternal.inc') 2290 self.write_nexternal_file(writers.FortranWriter(filename), 2291 nexternal, ninitial) 2292 2293 filename = pjoin(dirpath, 'leshouche.inc') 2294 self.write_leshouche_file(writers.FortranWriter(filename), 2295 matrix_element) 2296 2297 filename = pjoin(dirpath, 'props.inc') 2298 self.write_props_file(writers.FortranWriter(filename), 2299 matrix_element, 2300 s_and_t_channels) 2301 2302 filename = pjoin(dirpath, 'pmass.inc') 2303 self.write_pmass_file(writers.FortranWriter(filename), 2304 matrix_element) 2305 2306 filename = pjoin(dirpath, 'ngraphs.inc') 2307 self.write_ngraphs_file(writers.FortranWriter(filename), 2308 len(matrix_element.get_all_amplitudes())) 2309 2310 filename = pjoin(dirpath, 'maxamps.inc') 2311 self.write_maxamps_file(writers.FortranWriter(filename), 2312 len(matrix_element.get('diagrams')), 2313 ncolor, 2314 len(matrix_element.get('processes')), 2315 1) 2316 2317 filename = pjoin(dirpath, 'phasespace.inc') 2318 self.write_phasespace_file(writers.FortranWriter(filename), 2319 len(matrix_element.get('diagrams')), 2320 ) 2321 2322 # Generate diagrams 2323 filename = pjoin(dirpath, "matrix.ps") 2324 plot = draw.MultiEpsDiagramDrawer(matrix_element.get('base_amplitude').\ 2325 get('diagrams'), 2326 filename, 2327 model=matrix_element.get('processes')[0].\ 2328 get('model'), 2329 amplitude='') 2330 logger.info("Generating Feynman diagrams for " + \ 2331 matrix_element.get('processes')[0].nice_string()) 2332 plot.draw() 2333 2334 #import genps.inc and maxconfigs.inc into Subprocesses 2335 ln(self.dir_path + '/Source/genps.inc', self.dir_path + '/SubProcesses', log=False) 2336 #ln(self.dir_path + '/Source/maxconfigs.inc', self.dir_path + '/SubProcesses', log=False) 2337 2338 linkfiles = ['driver.f', 'cuts.f', 'initialization.f','gen_ps.f', 'makefile', 'coupl.inc','madweight_param.inc', 'run.inc', 'setscales.f', 'genps.inc'] 2339 2340 for file in linkfiles: 2341 ln('../%s' % file, starting_dir=cwd) 2342 2343 ln('nexternal.inc', '../../Source', log=False, cwd=dirpath) 2344 ln('leshouche.inc', '../../Source', log=False, cwd=dirpath) 2345 ln('maxamps.inc', '../../Source', log=False, cwd=dirpath) 2346 ln('phasespace.inc', '../', log=True, cwd=dirpath) 2347 # Return to original PWD 2348 #os.chdir(cwd) 2349 2350 if not calls: 2351 calls = 0 2352 return calls
2353 2354 #=========================================================================== 2355 # write_matrix_element_v4 2356 #===========================================================================
2357 - def write_matrix_element_v4(self, writer, matrix_element, fortran_model,proc_id = "", config_map = []):
2358 """Export a matrix element to a matrix.f file in MG4 MadWeight format""" 2359 2360 if not matrix_element.get('processes') or \ 2361 not matrix_element.get('diagrams'): 2362 return 0 2363 2364 if not isinstance(writer, writers.FortranWriter): 2365 raise writers.FortranWriter.FortranWriterError(\ 2366 "writer not FortranWriter") 2367 2368 # Set lowercase/uppercase Fortran code 2369 writers.FortranWriter.downcase = False 2370 2371 replace_dict = {} 2372 2373 # Extract version number and date from VERSION file 2374 info_lines = self.get_mg5_info_lines() 2375 replace_dict['info_lines'] = info_lines 2376 2377 # Extract process info lines 2378 process_lines = self.get_process_info_lines(matrix_element) 2379 replace_dict['process_lines'] = process_lines 2380 2381 # Set proc_id 2382 replace_dict['proc_id'] = proc_id 2383 2384 # Extract number of external particles 2385 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial() 2386 replace_dict['nexternal'] = nexternal 2387 2388 # Extract ncomb 2389 ncomb = matrix_element.get_helicity_combinations() 2390 replace_dict['ncomb'] = ncomb 2391 2392 # Extract helicity lines 2393 helicity_lines = self.get_helicity_lines(matrix_element) 2394 replace_dict['helicity_lines'] = helicity_lines 2395 2396 # Extract overall denominator 2397 # Averaging initial state color, spin, and identical FS particles 2398 den_factor_line = self.get_den_factor_line(matrix_element) 2399 replace_dict['den_factor_line'] = den_factor_line 2400 2401 # Extract ngraphs 2402 ngraphs = matrix_element.get_number_of_amplitudes() 2403 replace_dict['ngraphs'] = ngraphs 2404 2405 # Extract nwavefuncs 2406 nwavefuncs = matrix_element.get_number_of_wavefunctions() 2407 replace_dict['nwavefuncs'] = nwavefuncs 2408 2409 # Extract ncolor 2410 ncolor = max(1, len(matrix_element.get('color_basis'))) 2411 replace_dict['ncolor'] = ncolor 2412 2413 # Extract color data lines 2414 color_data_lines = self.get_color_data_lines(matrix_element) 2415 replace_dict['color_data_lines'] = "\n".join(color_data_lines) 2416 2417 # Extract helas calls 2418 helas_calls = fortran_model.get_matrix_element_calls(\ 2419 matrix_element) 2420 2421 replace_dict['helas_calls'] = "\n".join(helas_calls) 2422 2423 # Extract JAMP lines 2424 jamp_lines = self.get_JAMP_lines(matrix_element) 2425 replace_dict['jamp_lines'] = '\n'.join(jamp_lines) 2426 2427 file = open(os.path.join(_file_path, \ 2428 'iolibs/template_files/%s' % self.matrix_file)).read() 2429 file = file % replace_dict 2430 2431 2432 # Write the file 2433 writer.writelines(file) 2434 2435 return len(filter(lambda call: call.find('#') != 0, helas_calls)),ncolor
2436 2437 #=========================================================================== 2438 # write_source_makefile 2439 #===========================================================================
2440 - def write_source_makefile(self, writer):
2441 """Write the nexternal.inc file for madweight""" 2442 2443 2444 path = os.path.join(_file_path,'iolibs','template_files','madweight_makefile_source') 2445 set_of_lib = '$(LIBRARIES) $(LIBDIR)libdhelas.$(libext) $(LIBDIR)libpdf.$(libext) $(LIBDIR)libmodel.$(libext) $(LIBDIR)libcernlib.$(libext) $(LIBDIR)libtf.$(libext)' 2446 text = open(path).read() % {'libraries': set_of_lib} 2447 writer.write(text) 2448 2449 return True
2450
2451 - def write_phasespace_file(self, writer, nb_diag):
2452 """ """ 2453 2454 template = """ include 'maxparticles.inc' 2455 integer max_branches 2456 parameter (max_branches=max_particles-1) 2457 integer max_configs 2458 parameter (max_configs=%(nb_diag)s) 2459 2460 c channel position 2461 integer config_pos,perm_pos 2462 common /to_config/config_pos,perm_pos 2463 2464 """ 2465 2466 writer.write(template % {'nb_diag': nb_diag})
2467 2468 2469 #=========================================================================== 2470 # write_auto_dsig_file 2471 #===========================================================================
2472 - def write_auto_dsig_file(self, writer, matrix_element, proc_id = ""):
2473 """Write the auto_dsig.f file for the differential cross section 2474 calculation, includes pdf call information (MadWeight format)""" 2475 2476 if not matrix_element.get('processes') or \ 2477 not matrix_element.get('diagrams'): 2478 return 0 2479 2480 nexternal, ninitial = matrix_element.get_nexternal_ninitial() 2481 2482 if ninitial < 1 or ninitial > 2: 2483 raise writers.FortranWriter.FortranWriterError, \ 2484 """Need ninitial = 1 or 2 to write auto_dsig file""" 2485 2486 replace_dict = {} 2487 2488 # Extract version number and date from VERSION file 2489 info_lines = self.get_mg5_info_lines() 2490 replace_dict['info_lines'] = info_lines 2491 2492 # Extract process info lines 2493 process_lines = self.get_process_info_lines(matrix_element) 2494 replace_dict['process_lines'] = process_lines 2495 2496 # Set proc_id 2497 replace_dict['proc_id'] = proc_id 2498 replace_dict['numproc'] = 1 2499 2500 # Set dsig_line 2501 if ninitial == 1: 2502 # No conversion, since result of decay should be given in GeV 2503 dsig_line = "pd(0)*dsiguu" 2504 else: 2505 # Convert result (in GeV) to pb 2506 dsig_line = "pd(0)*conv*dsiguu" 2507 2508 replace_dict['dsig_line'] = dsig_line 2509 2510 # Extract pdf lines 2511 pdf_vars, pdf_data, pdf_lines = \ 2512 self.get_pdf_lines(matrix_element, ninitial, proc_id != "") 2513 replace_dict['pdf_vars'] = pdf_vars 2514 replace_dict['pdf_data'] = pdf_data 2515 replace_dict['pdf_lines'] = pdf_lines 2516 2517 # Lines that differ between subprocess group and regular 2518 if proc_id: 2519 replace_dict['numproc'] = int(proc_id) 2520 replace_dict['passcuts_begin'] = "" 2521 replace_dict['passcuts_end'] = "" 2522 # Set lines for subprocess group version 2523 # Set define_iconfigs_lines 2524 replace_dict['define_subdiag_lines'] = \ 2525 """\nINTEGER SUBDIAG(MAXSPROC),IB(2) 2526 COMMON/TO_SUB_DIAG/SUBDIAG,IB""" 2527 else: 2528 replace_dict['passcuts_begin'] = "IF (PASSCUTS(PP)) THEN" 2529 replace_dict['passcuts_end'] = "ENDIF" 2530 replace_dict['define_subdiag_lines'] = "" 2531 2532 file = open(os.path.join(_file_path, \ 2533 'iolibs/template_files/auto_dsig_mw.inc')).read() 2534 2535 file = file % replace_dict 2536 2537 2538 # Write the file 2539 writer.writelines(file)
2540 2541 #=========================================================================== 2542 # write_configs_file 2543 #===========================================================================
2544 - def write_configs_file(self, writer, matrix_element):
2545 """Write the configs.inc file for MadEvent""" 2546 2547 # Extract number of external particles 2548 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial() 2549 2550 configs = [(i+1, d) for i,d in enumerate(matrix_element.get('diagrams'))] 2551 mapconfigs = [c[0] for c in configs] 2552 model = matrix_element.get('processes')[0].get('model') 2553 return mapconfigs, self.write_configs_file_from_diagrams(writer, 2554 [[c[1]] for c in configs], 2555 mapconfigs, 2556 nexternal, ninitial,matrix_element, model)
2557 2558 #=========================================================================== 2559 # write_run_configs_file 2560 #===========================================================================
2561 - def write_run_config_file(self, writer):
2562 """Write the run_configs.inc file for MadWeight""" 2563 2564 path = os.path.join(_file_path,'iolibs','template_files','madweight_run_config.inc') 2565 text = open(path).read() % {'chanperjob':'5'} 2566 writer.write(text) 2567 return True
2568 2569 #=========================================================================== 2570 # write_configs_file_from_diagrams 2571 #===========================================================================
2572 - def write_configs_file_from_diagrams(self, writer, configs, mapconfigs, 2573 nexternal, ninitial, matrix_element, model):
2574 """Write the actual configs.inc file. 2575 2576 configs is the diagrams corresponding to configs (each 2577 diagrams is a list of corresponding diagrams for all 2578 subprocesses, with None if there is no corresponding diagrams 2579 for a given process). 2580 mapconfigs gives the diagram number for each config. 2581 2582 For s-channels, we need to output one PDG for each subprocess in 2583 the subprocess group, in order to be able to pick the right 2584 one for multiprocesses.""" 2585 2586 lines = [] 2587 2588 particle_dict = matrix_element.get('processes')[0].get('model').\ 2589 get('particle_dict') 2590 2591 s_and_t_channels = [] 2592 2593 minvert = min([max([d for d in config if d][0].get_vertex_leg_numbers()) \ 2594 for config in configs]) 2595 2596 # Number of subprocesses 2597 nsubprocs = len(configs[0]) 2598 2599 nconfigs = 0 2600 2601 new_pdg = model.get_first_non_pdg() 2602 2603 for iconfig, helas_diags in enumerate(configs): 2604 if any([vert > minvert for vert in 2605 [d for d in helas_diags if d][0].get_vertex_leg_numbers()]): 2606 # Only 3-vertices allowed in configs.inc 2607 continue 2608 nconfigs += 1 2609 2610 # Need s- and t-channels for all subprocesses, including 2611 # those that don't contribute to this config 2612 empty_verts = [] 2613 stchannels = [] 2614 for h in helas_diags: 2615 if h: 2616 # get_s_and_t_channels gives vertices starting from 2617 # final state external particles and working inwards 2618 stchannels.append(h.get('amplitudes')[0].\ 2619 get_s_and_t_channels(ninitial,model,new_pdg)) 2620 else: 2621 stchannels.append((empty_verts, None)) 2622 2623 # For t-channels, just need the first non-empty one 2624 tchannels = [t for s,t in stchannels if t != None][0] 2625 2626 # For s_and_t_channels (to be used later) use only first config 2627 s_and_t_channels.append([[s for s,t in stchannels if t != None][0], 2628 tchannels]) 2629 2630 # Make sure empty_verts is same length as real vertices 2631 if any([s for s,t in stchannels]): 2632 empty_verts[:] = [None]*max([len(s) for s,t in stchannels]) 2633 2634 # Reorganize s-channel vertices to get a list of all 2635 # subprocesses for each vertex 2636 schannels = zip(*[s for s,t in stchannels]) 2637 else: 2638 schannels = [] 2639 2640 allchannels = schannels 2641 if len(tchannels) > 1: 2642 # Write out tchannels only if there are any non-trivial ones 2643 allchannels = schannels + tchannels 2644 2645 # Write out propagators for s-channel and t-channel vertices 2646 2647 #lines.append("# Diagram %d" % (mapconfigs[iconfig])) 2648 # Correspondance between the config and the diagram = amp2 2649 lines.append("* %d %d " % (nconfigs, 2650 mapconfigs[iconfig])) 2651 2652 for verts in allchannels: 2653 if verts in schannels: 2654 vert = [v for v in verts if v][0] 2655 else: 2656 vert = verts 2657 daughters = [leg.get('number') for leg in vert.get('legs')[:-1]] 2658 last_leg = vert.get('legs')[-1] 2659 line=str(last_leg.get('number'))+" "+str(daughters[0])+" "+str(daughters[1]) 2660 # lines.append("data (iforest(i,%d,%d),i=1,%d)/%s/" % \ 2661 # (last_leg.get('number'), nconfigs, len(daughters), 2662 # ",".join([str(d) for d in daughters]))) 2663 2664 if last_leg.get('id') == 21 and 21 not in particle_dict: 2665 # Fake propagator used in multiparticle vertices 2666 mass = 'zero' 2667 width = 'zero' 2668 pow_part = 0 2669 else: 2670 if (last_leg.get('id')!=7): 2671 particle = particle_dict[last_leg.get('id')] 2672 # Get mass 2673 mass = particle.get('mass') 2674 # Get width 2675 width = particle.get('width') 2676 else : # fake propagator used in multiparticle vertices 2677 mass= 'zero' 2678 width= 'zero' 2679 2680 line=line+" "+mass+" "+width+" " 2681 2682 if verts in schannels: 2683 pdgs = [] 2684 for v in verts: 2685 if v: 2686 pdgs.append(v.get('legs')[-1].get('id')) 2687 else: 2688 pdgs.append(0) 2689 lines.append(line+" S "+str(last_leg.get('id'))) 2690 # lines.append("data (sprop(i,%d,%d),i=1,%d)/%s/" % \ 2691 # (last_leg.get('number'), nconfigs, nsubprocs, 2692 # ",".join([str(d) for d in pdgs]))) 2693 # lines.append("data tprid(%d,%d)/0/" % \ 2694 # (last_leg.get('number'), nconfigs)) 2695 elif verts in tchannels[:-1]: 2696 lines.append(line+" T "+str(last_leg.get('id'))) 2697 # lines.append("data tprid(%d,%d)/%d/" % \ 2698 # (last_leg.get('number'), nconfigs, 2699 # abs(last_leg.get('id')))) 2700 # lines.append("data (sprop(i,%d,%d),i=1,%d)/%s/" % \ 2701 # (last_leg.get('number'), nconfigs, nsubprocs, 2702 # ",".join(['0'] * nsubprocs))) 2703 2704 # Write out number of configs 2705 # lines.append("# Number of configs") 2706 # lines.append("data mapconfig(0)/%d/" % nconfigs) 2707 lines.append(" * ") # a line with just a star indicates this is the end of file 2708 # Write the file 2709 writer.writelines(lines) 2710 2711 return s_and_t_channels
2712 2713 2714 #=============================================================================== 2715 # ProcessExporterFortranME 2716 #===============================================================================
2717 -class ProcessExporterFortranME(ProcessExporterFortran):
2718 """Class to take care of exporting a set of matrix elements to 2719 MadEvent format.""" 2720 2721 matrix_file = "matrix_madevent_v4.inc" 2722
2723 - def copy_v4template(self, modelname):
2724 """Additional actions needed for setup of Template 2725 """ 2726 2727 super(ProcessExporterFortranME, self).copy_v4template(modelname) 2728 2729 # File created from Template (Different in some child class) 2730 filename = pjoin(self.dir_path,'Source','run_config.inc') 2731 self.write_run_config_file(writers.FortranWriter(filename)) 2732 2733 # The next file are model dependant (due to SLAH convention) 2734 self.model_name = modelname 2735 # Add the symmetry.f 2736 filename = pjoin(self.dir_path,'SubProcesses','symmetry.f') 2737 self.write_symmetry(writers.FortranWriter(filename)) 2738 # Add the driver.f 2739 filename = pjoin(self.dir_path,'SubProcesses','driver.f') 2740 self.write_driver(writers.FortranWriter(filename)) 2741 # 2742 filename = pjoin(self.dir_path,'SubProcesses','addmothers.f') 2743 self.write_addmothers(writers.FortranWriter(filename)) 2744 # Copy the different python file in the Template 2745 self.copy_python_file()
2746 2747 2748 2749 2750 2751 #=========================================================================== 2752 # generate_subprocess_directory_v4 2753 #===========================================================================
2754 - def copy_python_file(self):
2755 """copy the python file require for the Template""" 2756 2757 # madevent interface 2758 cp(_file_path+'/interface/madevent_interface.py', 2759 self.dir_path+'/bin/internal/madevent_interface.py') 2760 cp(_file_path+'/interface/extended_cmd.py', 2761 self.dir_path+'/bin/internal/extended_cmd.py') 2762 cp(_file_path+'/interface/common_run_interface.py', 2763 self.dir_path+'/bin/internal/common_run_interface.py') 2764 cp(_file_path+'/various/misc.py', self.dir_path+'/bin/internal/misc.py') 2765 cp(_file_path+'/iolibs/files.py', self.dir_path+'/bin/internal/files.py') 2766 cp(_file_path+'/iolibs/save_load_object.py', 2767 self.dir_path+'/bin/internal/save_load_object.py') 2768 cp(_file_path+'/iolibs/file_writers.py', 2769 self.dir_path+'/bin/internal/file_writers.py') 2770 #model file 2771 cp(_file_path+'../models/check_param_card.py', 2772 self.dir_path+'/bin/internal/check_param_card.py') 2773 2774 #madevent file 2775 cp(_file_path+'/__init__.py', self.dir_path+'/bin/internal/__init__.py') 2776 cp(_file_path+'/various/lhe_parser.py', 2777 self.dir_path+'/bin/internal/lhe_parser.py') 2778 cp(_file_path+'/various/gen_crossxhtml.py', 2779 self.dir_path+'/bin/internal/gen_crossxhtml.py') 2780 cp(_file_path+'/various/banner.py', 2781 self.dir_path+'/bin/internal/banner.py') 2782 cp(_file_path+'/various/cluster.py', 2783 self.dir_path+'/bin/internal/cluster.py') 2784 cp(_file_path+'/various/sum_html.py', 2785 self.dir_path+'/bin/internal/sum_html.py') 2786 cp(_file_path+'/various/combine_runs.py', 2787 self.dir_path+'/bin/internal/combine_runs.py') 2788 # logging configuration 2789 cp(_file_path+'/interface/.mg5_logging.conf', 2790 self.dir_path+'/bin/internal/me5_logging.conf') 2791 cp(_file_path+'/interface/coloring_logging.py', 2792 self.dir_path+'/bin/internal/coloring_logging.py') 2793 # shower card and FO_analyse_card. 2794 # Although not needed, it is imported by banner.py 2795 cp(_file_path+'/various/shower_card.py', 2796 self.dir_path+'/bin/internal/shower_card.py') 2797 cp(_file_path+'/various/FO_analyse_card.py', 2798 self.dir_path+'/bin/internal/FO_analyse_card.py')
2799 2800
2801 - def convert_model_to_mg4(self, model, wanted_lorentz = [], 2802 wanted_couplings = []):
2803 2804 super(ProcessExporterFortranME,self).convert_model_to_mg4(model, 2805 wanted_lorentz, wanted_couplings) 2806 2807 IGNORE_PATTERNS = ('*.pyc','*.dat','*.py~') 2808 try: 2809 shutil.rmtree(pjoin(self.dir_path,'bin','internal','ufomodel')) 2810 except OSError as error: 2811 pass 2812 model_path = model.get('modelpath') 2813 # This is not safe if there is a '##' or '-' in the path. 2814 shutil.copytree(model_path, 2815 pjoin(self.dir_path,'bin','internal','ufomodel'), 2816 ignore=shutil.ignore_patterns(*IGNORE_PATTERNS)) 2817 if hasattr(model, 'restrict_card'): 2818 out_path = pjoin(self.dir_path, 'bin', 'internal','ufomodel', 2819 'restrict_default.dat') 2820 if isinstance(model.restrict_card, check_param_card.ParamCard): 2821 model.restrict_card.write(out_path) 2822 else: 2823 files.cp(model.restrict_card, out_path)
2824 2825 #=========================================================================== 2826 # export model files 2827 #===========================================================================
2828 - def export_model_files(self, model_path):
2829 """export the model dependent files""" 2830 2831 super(ProcessExporterFortranME,self).export_model_files(model_path) 2832 2833 # Add the routine update_as_param in v4 model 2834 # This is a function created in the UFO 2835 text=""" 2836 subroutine update_as_param() 2837 call setpara('param_card.dat',.false.) 2838 return 2839 end 2840 """ 2841 ff = open(pjoin(self.dir_path, 'Source', 'MODEL', 'couplings.f'),'a') 2842 ff.write(text) 2843 ff.close() 2844 2845 # Add the symmetry.f 2846 filename = pjoin(self.dir_path,'SubProcesses','symmetry.f') 2847 self.write_symmetry(writers.FortranWriter(filename), v5=False) 2848 2849 # Add the driver.f 2850 filename = pjoin(self.dir_path,'SubProcesses','driver.f') 2851 self.write_driver(writers.FortranWriter(filename), v5=False) 2852 2853 # Modify setrun.f 2854 text = open(pjoin(self.dir_path,'Source','setrun.f')).read() 2855 text = text.replace('call setpara(param_card_name)', 'call setpara(param_card_name, .true.)') 2856 fsock = open(pjoin(self.dir_path,'Source','setrun.f'), 'w') 2857 fsock.write(text) 2858 fsock.close() 2859 2860 self.make_model_symbolic_link()
2861 2862 2863 #=========================================================================== 2864 # generate_subprocess_directory_v4 2865 #===========================================================================
2866 - def generate_subprocess_directory_v4(self, matrix_element, 2867 fortran_model, 2868 me_number):
2869 """Generate the Pxxxxx directory for a subprocess in MG4 madevent, 2870 including the necessary matrix.f and various helper files""" 2871 2872 cwd = os.getcwd() 2873 path = pjoin(self.dir_path, 'SubProcesses') 2874 2875 2876 if not self.model: 2877 self.model = matrix_element.get('processes')[0].get('model') 2878 2879 2880 2881 #os.chdir(path) 2882 # Create the directory PN_xx_xxxxx in the specified path 2883 subprocdir = "P%s" % matrix_element.get('processes')[0].shell_string() 2884 try: 2885 os.mkdir(pjoin(path,subprocdir)) 2886 except os.error as error: 2887 logger.warning(error.strerror + " " + subprocdir) 2888 2889 #try: 2890 # os.chdir(subprocdir) 2891 #except os.error: 2892 # logger.error('Could not cd to directory %s' % subprocdir) 2893 # return 0 2894 2895 logger.info('Creating files in directory %s' % subprocdir) 2896 Ppath = pjoin(path, subprocdir) 2897 2898 # Extract number of external particles 2899 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial() 2900 2901 # Create the matrix.f file, auto_dsig.f file and all inc files 2902 filename = pjoin(Ppath, 'matrix.f') 2903 calls, ncolor = \ 2904 self.write_matrix_element_v4(writers.FortranWriter(filename), 2905 matrix_element, 2906 fortran_model) 2907 2908 filename = pjoin(Ppath, 'auto_dsig.f') 2909 self.write_auto_dsig_file(writers.FortranWriter(filename), 2910 matrix_element) 2911 2912 filename = pjoin(Ppath, 'configs.inc') 2913 mapconfigs, (s_and_t_channels, nqcd_list) = self.write_configs_file(\ 2914 writers.FortranWriter(filename), 2915 matrix_element) 2916 2917 filename = pjoin(Ppath, 'config_nqcd.inc') 2918 self.write_config_nqcd_file(writers.FortranWriter(filename), 2919 nqcd_list) 2920 2921 filename = pjoin(Ppath, 'config_subproc_map.inc') 2922 self.write_config_subproc_map_file(writers.FortranWriter(filename), 2923 s_and_t_channels) 2924 2925 filename = pjoin(Ppath, 'coloramps.inc') 2926 self.write_coloramps_file(writers.FortranWriter(filename), 2927 mapconfigs, 2928 matrix_element) 2929 2930 filename = pjoin(Ppath, 'get_color.f') 2931 self.write_colors_file(writers.FortranWriter(filename), 2932 matrix_element) 2933 2934 filename = pjoin(Ppath, 'decayBW.inc') 2935 self.write_decayBW_file(writers.FortranWriter(filename), 2936 s_and_t_channels) 2937 2938 filename = pjoin(Ppath, 'dname.mg') 2939 self.write_dname_file(writers.FileWriter(filename), 2940 "P"+matrix_element.get('processes')[0].shell_string()) 2941 2942 filename = pjoin(Ppath, 'iproc.dat') 2943 self.write_iproc_file(writers.FortranWriter(filename), 2944 me_number) 2945 2946 filename = pjoin(Ppath, 'leshouche.inc') 2947 self.write_leshouche_file(writers.FortranWriter(filename), 2948 matrix_element) 2949 2950 filename = pjoin(Ppath, 'maxamps.inc') 2951 self.write_maxamps_file(writers.FortranWriter(filename), 2952 len(matrix_element.get('diagrams')), 2953 ncolor, 2954 len(matrix_element.get('processes')), 2955 1) 2956 2957 filename = pjoin(Ppath, 'mg.sym') 2958 self.write_mg_sym_file(writers.FortranWriter(filename), 2959 matrix_element) 2960 2961 filename = pjoin(Ppath, 'ncombs.inc') 2962 self.write_ncombs_file(writers.FortranWriter(filename), 2963 nexternal) 2964 2965 filename = pjoin(Ppath, 'nexternal.inc') 2966 self.write_nexternal_file(writers.FortranWriter(filename), 2967 nexternal, ninitial) 2968 2969 filename = pjoin(Ppath, 'ngraphs.inc') 2970 self.write_ngraphs_file(writers.FortranWriter(filename), 2971 len(mapconfigs)) 2972 2973 2974 filename = pjoin(Ppath, 'pmass.inc') 2975 self.write_pmass_file(writers.FortranWriter(filename), 2976 matrix_element) 2977 2978 filename = pjoin(Ppath, 'props.inc') 2979 self.write_props_file(writers.FortranWriter(filename), 2980 matrix_element, 2981 s_and_t_channels) 2982 2983 # Find config symmetries and permutations 2984 symmetry, perms, ident_perms = \ 2985 diagram_symmetry.find_symmetry(matrix_element) 2986 2987 filename = pjoin(Ppath, 'symswap.inc') 2988 self.write_symswap_file(writers.FortranWriter(filename), 2989 ident_perms) 2990 2991 filename = pjoin(Ppath, 'symfact_orig.dat') 2992 self.write_symfact_file(open(filename, 'w'), symmetry) 2993 2994 # Generate diagrams 2995 filename = pjoin(Ppath, "matrix.ps") 2996 plot = draw.MultiEpsDiagramDrawer(matrix_element.get('base_amplitude').\ 2997 get('diagrams'), 2998 filename, 2999 model=matrix_element.get('processes')[0].\ 3000 get('model'), 3001 amplitude=True) 3002 logger.info("Generating Feynman diagrams for " + \ 3003 matrix_element.get('processes')[0].nice_string()) 3004 plot.draw() 3005 3006 #import genps.inc and maxconfigs.inc into Subprocesses 3007 ln(self.dir_path + '/Source/genps.inc', self.dir_path + '/SubProcesses', log=False) 3008 ln(self.dir_path + '/Source/maxconfigs.inc', self.dir_path + '/SubProcesses', log=False) 3009 3010 linkfiles = ['addmothers.f', 3011 'cluster.f', 3012 'cluster.inc', 3013 'coupl.inc', 3014 'cuts.f', 3015 'cuts.inc', 3016 'driver.f', 3017 'genps.f', 3018 'genps.inc', 3019 'idenparts.f', 3020 'initcluster.f', 3021 'makefile', 3022 'message.inc', 3023 'myamp.f', 3024 'reweight.f', 3025 'run.inc', 3026 'maxconfigs.inc', 3027 'maxparticles.inc', 3028 'run_config.inc', 3029 'setcuts.f', 3030 'setscales.f', 3031 'sudakov.inc', 3032 'symmetry.f', 3033 'unwgt.f'] 3034 3035 for file in linkfiles: 3036 ln('../' + file , cwd=Ppath) 3037 3038 #import nexternal/leshouche in Source 3039 ln(pjoin(Ppath,'nexternal.inc'), pjoin(self.dir_path,'Source'), log=False) 3040 ln(pjoin(Ppath,'leshouche.inc'), pjoin(self.dir_path,'Source'), log=False) 3041 ln(pjoin(Ppath,'maxamps.inc'), pjoin(self.dir_path,'Source'), log=False) 3042 # Return to SubProcesses dir 3043 #os.chdir(os.path.pardir) 3044 3045 # Add subprocess to subproc.mg 3046 filename = pjoin(path, 'subproc.mg') 3047 files.append_to_file(filename, 3048 self.write_subproc, 3049 subprocdir) 3050 3051 # Return to original dir 3052 #os.chdir(cwd) 3053 3054 # Generate info page 3055 gen_infohtml.make_info_html(self.dir_path) 3056 3057 3058 if not calls: 3059 calls = 0 3060 return calls
3061
3062 - def finalize_v4_directory(self, matrix_elements, history, makejpg = False, 3063 online = False, compiler='gfortran'):
3064 """Finalize ME v4 directory by creating jpeg diagrams, html 3065 pages,proc_card_mg5.dat and madevent.tar.gz.""" 3066 3067 modelname = self.opt['model'] 3068 if modelname == 'mssm' or modelname.startswith('mssm-'): 3069 param_card = pjoin(self.dir_path, 'Cards','param_card.dat') 3070 mg5_param = pjoin(self.dir_path, 'Source', 'MODEL', 'MG5_param.dat') 3071 check_param_card.convert_to_mg5card(param_card, mg5_param) 3072 check_param_card.check_valid_param_card(mg5_param) 3073 3074 # Add the combine_events.f modify param_card path/number of @X 3075 filename = pjoin(self.dir_path,'Source','combine_events.f') 3076 try: 3077 nb_proc =[p.get('id') for me in matrix_elements for m in me.get('matrix_elements') for p in m.get('processes')] 3078 except AttributeError: 3079 nb_proc =[p.get('id') for m in matrix_elements.get('matrix_elements') for p in m.get('processes')] 3080 nb_proc = len(set(nb_proc)) 3081 self.write_combine_events(writers.FortranWriter(filename), nb_proc) # already formatted 3082 # Write maxconfigs.inc based on max of ME's/subprocess groups 3083 filename = pjoin(self.dir_path,'Source','maxconfigs.inc') 3084 self.write_maxconfigs_file(writers.FortranWriter(filename), 3085 matrix_elements) 3086 3087 # Write maxparticles.inc based on max of ME's/subprocess groups 3088 filename = pjoin(self.dir_path,'Source','maxparticles.inc') 3089 self.write_maxparticles_file(writers.FortranWriter(filename), 3090 matrix_elements) 3091 3092 # Touch "done" file 3093 os.system('touch %s/done' % pjoin(self.dir_path,'SubProcesses')) 3094 3095 # Check for compiler 3096 self.set_compiler(compiler) 3097 3098 old_pos = os.getcwd() 3099 subpath = pjoin(self.dir_path, 'SubProcesses') 3100 3101 P_dir_list = [proc for proc in os.listdir(subpath) 3102 if os.path.isdir(pjoin(subpath,proc)) and proc[0] == 'P'] 3103 3104 devnull = os.open(os.devnull, os.O_RDWR) 3105 # Convert the poscript in jpg files (if authorize) 3106 if makejpg: 3107 try: 3108 os.remove(pjoin(self.dir_path,'HTML','card.jpg')) 3109 except Exception, error: 3110 pass 3111 logger.info("Generate jpeg diagrams") 3112 for Pdir in P_dir_list: 3113 misc.call([pjoin(self.dir_path, 'bin', 'internal', 'gen_jpeg-pl')], 3114 stdout = devnull, cwd=pjoin(subpath, Pdir)) 3115 3116 logger.info("Generate web pages") 3117 # Create the WebPage using perl script 3118 3119 misc.call([pjoin(self.dir_path, 'bin', 'internal', 'gen_cardhtml-pl')], \ 3120 stdout = devnull,cwd=pjoin(self.dir_path)) 3121 3122 #os.chdir(os.path.pardir) 3123 3124 obj = gen_infohtml.make_info_html(self.dir_path) 3125 3126 if online: 3127 nb_channel = obj.rep_rule['nb_gen_diag'] 3128 open(pjoin(self.dir_path, 'Online'),'w').write(str(nb_channel)) 3129 3130 # Write command history as proc_card_mg5 3131 if os.path.isdir(pjoin(self.dir_path,'Cards')): 3132 output_file = pjoin(self.dir_path,'Cards', 'proc_card_mg5.dat') 3133 history.write(output_file) 3134 3135 misc.call([pjoin(self.dir_path, 'bin', 'internal', 'gen_cardhtml-pl')], 3136 stdout = devnull) 3137 3138 # Run "make" to generate madevent.tar.gz file 3139 if os.path.exists(pjoin(self.dir_path,'SubProcesses', 'subproc.mg')): 3140 if os.path.exists(pjoin(self.dir_path,'madevent.tar.gz')): 3141 os.remove(pjoin(self.dir_path,'madevent.tar.gz')) 3142 misc.call([os.path.join(self.dir_path, 'bin', 'internal', 'make_madevent_tar')], 3143 stdout = devnull, cwd=self.dir_path) 3144 3145 misc.call([pjoin(self.dir_path, 'bin', 'internal', 'gen_cardhtml-pl')], 3146 stdout = devnull)
3147 3148 #return to the initial dir 3149 #os.chdir(old_pos) 3150 3151 #=========================================================================== 3152 # write_matrix_element_v4 3153 #===========================================================================
3154 - def write_matrix_element_v4(self, writer, matrix_element, fortran_model, 3155 proc_id = "", config_map = []):
3156 """Export a matrix element to a matrix.f file in MG4 madevent format""" 3157 3158 if not matrix_element.get('processes') or \ 3159 not matrix_element.get('diagrams'): 3160 return 0 3161 3162 if not isinstance(writer, writers.FortranWriter): 3163 raise writers.FortranWriter.FortranWriterError(\ 3164 "writer not FortranWriter") 3165 3166 3167 # Set lowercase/uppercase Fortran code 3168 writers.FortranWriter.downcase = False 3169 3170 # The proc prefix is not used for MadEvent output so it can safely be set 3171 # to an empty string. 3172 replace_dict = {'proc_prefix':''} 3173 3174 # Extract helas calls 3175 helas_calls = fortran_model.get_matrix_element_calls(\ 3176 matrix_element) 3177 3178 replace_dict['helas_calls'] = "\n".join(helas_calls) 3179 3180 3181 # Extract version number and date from VERSION file 3182 info_lines = self.get_mg5_info_lines() 3183 replace_dict['info_lines'] = info_lines 3184 3185 # Extract process info lines 3186 process_lines = self.get_process_info_lines(matrix_element) 3187 replace_dict['process_lines'] = process_lines 3188 3189 # Set proc_id 3190 replace_dict['proc_id'] = proc_id 3191 3192 # Extract ncomb 3193 ncomb = matrix_element.get_helicity_combinations() 3194 replace_dict['ncomb'] = ncomb 3195 3196 # Extract helicity lines 3197 helicity_lines = self.get_helicity_lines(matrix_element) 3198 replace_dict['helicity_lines'] = helicity_lines 3199 3200 # Extract IC line 3201 ic_line = self.get_ic_line(matrix_element) 3202 replace_dict['ic_line'] = ic_line 3203 3204 # Extract overall denominator 3205 # Averaging initial state color, spin, and identical FS particles 3206 den_factor_line = self.get_den_factor_line(matrix_element) 3207 replace_dict['den_factor_line'] = den_factor_line 3208 3209 # Extract ngraphs 3210 ngraphs = matrix_element.get_number_of_amplitudes() 3211 replace_dict['ngraphs'] = ngraphs 3212 3213 # Extract ndiags 3214 ndiags = len(matrix_element.get('diagrams')) 3215 replace_dict['ndiags'] = ndiags 3216 3217 # Set define_iconfigs_lines 3218 replace_dict['define_iconfigs_lines'] = \ 3219 """INTEGER MAPCONFIG(0:LMAXCONFIGS), ICONFIG 3220 COMMON/TO_MCONFIGS/MAPCONFIG, ICONFIG""" 3221 3222 if proc_id: 3223 # Set lines for subprocess group version 3224 # Set define_iconfigs_lines 3225 replace_dict['define_iconfigs_lines'] += \ 3226 """\nINTEGER SUBDIAG(MAXSPROC),IB(2) 3227 COMMON/TO_SUB_DIAG/SUBDIAG,IB""" 3228 # Set set_amp2_line 3229 replace_dict['set_amp2_line'] = "ANS=ANS*AMP2(SUBDIAG(%s))/XTOT" % \ 3230 proc_id 3231 else: 3232 # Standard running 3233 # Set set_amp2_line 3234 replace_dict['set_amp2_line'] = "ANS=ANS*AMP2(MAPCONFIG(ICONFIG))/XTOT" 3235 3236 # Extract nwavefuncs 3237 nwavefuncs = matrix_element.get_number_of_wavefunctions() 3238 replace_dict['nwavefuncs'] = nwavefuncs 3239 3240 # Extract ncolor 3241 ncolor = max(1, len(matrix_element.get('color_basis'))) 3242 replace_dict['ncolor'] = ncolor 3243 3244 # Extract color data lines 3245 color_data_lines = self.get_color_data_lines(matrix_element) 3246 replace_dict['color_data_lines'] = "\n".join(color_data_lines) 3247 3248 3249 # Set the size of Wavefunction 3250 if not self.model or any([p.get('spin') in [4,5] for p in self.model.get('particles') if p]): 3251 replace_dict['wavefunctionsize'] = 18 3252 else: 3253 replace_dict['wavefunctionsize'] = 6 3254 3255 # Extract amp2 lines 3256 amp2_lines = self.get_amp2_lines(matrix_element, config_map) 3257 replace_dict['amp2_lines'] = '\n'.join(amp2_lines) 3258 3259 # The JAMP definition depends on the splitting order 3260 split_orders=matrix_element.get('processes')[0].get('split_orders') 3261 if len(split_orders)>0: 3262 squared_orders, amp_orders = matrix_element.get_split_orders_mapping() 3263 replace_dict['chosen_so_configs']=self.set_chosen_SO_index( 3264 matrix_element.get('processes')[0],squared_orders) 3265 else: 3266 # Consider the output of a dummy order 'ALL_ORDERS' for which we 3267 # set all amplitude order to weight 1 and only one squared order 3268 # contribution which is of course ALL_ORDERS=2. 3269 squared_orders = [(2,),] 3270 amp_orders = [((1,),tuple(range(1,ngraphs+1)))] 3271 replace_dict['chosen_so_configs'] = '.TRUE.' 3272 3273 replace_dict['nAmpSplitOrders']=len(amp_orders) 3274 replace_dict['nSqAmpSplitOrders']=len(squared_orders) 3275 replace_dict['split_order_str_list']=str(split_orders) 3276 replace_dict['nSplitOrders']=max(len(split_orders),1) 3277 amp_so = self.get_split_orders_lines( 3278 [amp_order[0] for amp_order in amp_orders],'AMPSPLITORDERS') 3279 sqamp_so = self.get_split_orders_lines(squared_orders,'SQSPLITORDERS') 3280 replace_dict['ampsplitorders']='\n'.join(amp_so) 3281 replace_dict['sqsplitorders']='\n'.join(sqamp_so) 3282 # Extract JAMP lines 3283 # If no split_orders then artificiall add one entry called 'ALL_ORDERS' 3284 jamp_lines = self.get_JAMP_lines_split_order(\ 3285 matrix_element,amp_orders,split_order_names= 3286 split_orders if len(split_orders)>0 else ['ALL_ORDERS']) 3287 replace_dict['jamp_lines'] = '\n'.join(jamp_lines) 3288 3289 file = open(pjoin(_file_path, \ 3290 'iolibs/template_files/%s' % self.matrix_file)).read() 3291 file = file % replace_dict 3292 3293 # Add the split orders helper functions. 3294 file = file + '\n' + open(pjoin(_file_path, \ 3295 'iolibs/template_files/split_orders_helping_functions.inc'))\ 3296 .read()%replace_dict 3297 # Write the file 3298 writer.writelines(file) 3299 3300 return len(filter(lambda call: call.find('#') != 0, helas_calls)), ncolor
3301 3302 #=========================================================================== 3303 # write_auto_dsig_file 3304 #===========================================================================
3305 - def write_auto_dsig_file(self, writer, matrix_element, proc_id = ""):
3306 """Write the auto_dsig.f file for the differential cross section 3307 calculation, includes pdf call information""" 3308 3309 if not matrix_element.get('processes') or \ 3310 not matrix_element.get('diagrams'): 3311 return 0 3312 3313 nexternal, ninitial = matrix_element.get_nexternal_ninitial() 3314 3315 if ninitial < 1 or ninitial > 2: 3316 raise writers.FortranWriter.FortranWriterError, \ 3317 """Need ninitial = 1 or 2 to write auto_dsig file""" 3318 3319 replace_dict = {} 3320 3321 # Extract version number and date from VERSION file 3322 info_lines = self.get_mg5_info_lines() 3323 replace_dict['info_lines'] = info_lines 3324 3325 # Extract process info lines 3326 process_lines = self.get_process_info_lines(matrix_element) 3327 replace_dict['process_lines'] = process_lines 3328 3329 # Set proc_id 3330 replace_dict['proc_id'] = proc_id 3331 replace_dict['numproc'] = 1 3332 3333 # Set dsig_line 3334 if ninitial == 1: 3335 # No conversion, since result of decay should be given in GeV 3336 dsig_line = "pd(0)*dsiguu" 3337 else: 3338 # Convert result (in GeV) to pb 3339 dsig_line = "pd(0)*conv*dsiguu" 3340 3341 replace_dict['dsig_line'] = dsig_line 3342 3343 # Extract pdf lines 3344 pdf_vars, pdf_data, pdf_lines = \ 3345 self.get_pdf_lines(matrix_element, ninitial, proc_id != "") 3346 replace_dict['pdf_vars'] = pdf_vars 3347 replace_dict['pdf_data'] = pdf_data 3348 replace_dict['pdf_lines'] = pdf_lines 3349 3350 # Lines that differ between subprocess group and regular 3351 if proc_id: 3352 replace_dict['numproc'] = int(proc_id) 3353 replace_dict['passcuts_begin'] = "" 3354 replace_dict['passcuts_end'] = "" 3355 # Set lines for subprocess group version 3356 # Set define_iconfigs_lines 3357 replace_dict['define_subdiag_lines'] = \ 3358 """\nINTEGER SUBDIAG(MAXSPROC),IB(2) 3359 COMMON/TO_SUB_DIAG/SUBDIAG,IB""" 3360 replace_dict['cutsdone'] = "" 3361 else: 3362 replace_dict['passcuts_begin'] = "IF (PASSCUTS(PP)) THEN" 3363 replace_dict['passcuts_end'] = "ENDIF" 3364 replace_dict['define_subdiag_lines'] = "" 3365 replace_dict['cutsdone'] = " cutsdone=.false.\n cutspassed=.false." 3366 3367 file = open(pjoin(_file_path, \ 3368 'iolibs/template_files/auto_dsig_v4.inc')).read() 3369 file = file % replace_dict 3370 3371 # Write the file 3372 writer.writelines(file)
3373 3374 #=========================================================================== 3375 # write_coloramps_file 3376 #===========================================================================
3377 - def write_coloramps_file(self, writer, mapconfigs, matrix_element):
3378 """Write the coloramps.inc file for MadEvent""" 3379 3380 lines = self.get_icolamp_lines(mapconfigs, matrix_element, 1) 3381 lines.insert(0, "logical icolamp(%d,%d,1)" % \ 3382 (max(len(matrix_element.get('color_basis').keys()), 1), 3383 len(mapconfigs))) 3384 3385 3386 # Write the file 3387 writer.writelines(lines) 3388 3389 return True
3390 3391 #=========================================================================== 3392 # write_colors_file 3393 #===========================================================================
3394 - def write_colors_file(self, writer, matrix_elements):
3395 """Write the get_color.f file for MadEvent, which returns color 3396 for all particles used in the matrix element.""" 3397 3398 if isinstance(matrix_elements, helas_objects.HelasMatrixElement): 3399 matrix_elements = [matrix_elements] 3400 3401 model = matrix_elements[0].get('processes')[0].get('model') 3402 3403 # We need the both particle and antiparticle wf_ids, since the identity 3404 # depends on the direction of the wf. 3405 wf_ids = set(sum([sum([sum([[wf.get_pdg_code(),wf.get_anti_pdg_code()] \ 3406 for wf in d.get('wavefunctions')],[]) \ 3407 for d in me.get('diagrams')], []) \ 3408 for me in matrix_elements], [])) 3409 3410 leg_ids = set(sum([sum([sum([[l.get('id'), 3411 model.get_particle(l.get('id')).get_anti_pdg_code()] \ 3412 for l in p.get_legs_with_decays()], []) \ 3413 for p in me.get('processes')], []) \ 3414 for me in matrix_elements], [])) 3415 particle_ids = sorted(list(wf_ids.union(leg_ids))) 3416 3417 lines = """function get_color(ipdg) 3418 implicit none 3419 integer get_color, ipdg 3420 3421 if(ipdg.eq.%d)then 3422 get_color=%d 3423 return 3424 """ % (particle_ids[0], model.get_particle(particle_ids[0]).get_color()) 3425 3426 for part_id in particle_ids[1:]: 3427 lines += """else if(ipdg.eq.%d)then 3428 get_color=%d 3429 return 3430 """ % (part_id, model.get_particle(part_id).get_color()) 3431 # Dummy particle for multiparticle vertices with pdg given by 3432 # first code not in the model 3433 lines += """else if(ipdg.eq.%d)then 3434 c This is dummy particle used in multiparticle vertices 3435 get_color=2 3436 return 3437 """ % model.get_first_non_pdg() 3438 lines += """else 3439 write(*,*)'Error: No color given for pdg ',ipdg 3440 get_color=0 3441 return 3442 endif 3443 end 3444 """ 3445 3446 # Write the file 3447 writer.writelines(lines) 3448 3449 return True
3450 3451 #=========================================================================== 3452 # write_config_nqcd_file 3453 #===========================================================================
3454 - def write_config_nqcd_file(self, writer, nqcd_list):
3455 """Write the config_nqcd.inc with the number of QCD couplings 3456 for each config""" 3457 3458 lines = [] 3459 for iconf, n in enumerate(nqcd_list): 3460 lines.append("data nqcd(%d)/%d/" % (iconf+1, n)) 3461 3462 # Write the file 3463 writer.writelines(lines) 3464 3465 return True
3466 3467 #=========================================================================== 3468 # write_maxconfigs_file 3469 #===========================================================================
3470 - def write_maxconfigs_file(self, writer, matrix_elements):
3471 """Write the maxconfigs.inc file for MadEvent""" 3472 3473 if isinstance(matrix_elements, helas_objects.HelasMultiProcess): 3474 maxconfigs = max([me.get_num_configs() for me in \ 3475 matrix_elements.get('matrix_elements')]) 3476 else: 3477 maxconfigs = max([me.get_num_configs() for me in matrix_elements]) 3478 3479 lines = "integer lmaxconfigs\n" 3480 lines += "parameter(lmaxconfigs=%d)" % maxconfigs 3481 3482 # Write the file 3483 writer.writelines(lines) 3484 3485 return True
3486 3487 3488 3489 #=========================================================================== 3490 # write_config_subproc_map_file 3491 #===========================================================================
3492 - def write_config_subproc_map_file(self, writer, s_and_t_channels):
3493 """Write a dummy config_subproc.inc file for MadEvent""" 3494 3495 lines = [] 3496 3497 for iconfig in range(len(s_and_t_channels)): 3498 lines.append("DATA CONFSUB(1,%d)/1/" % \ 3499 (iconfig + 1)) 3500 3501 # Write the file 3502 writer.writelines(lines) 3503 3504 return True
3505 3506 #=========================================================================== 3507 # write_configs_file 3508 #===========================================================================
3509 - def write_configs_file(self, writer, matrix_element):
3510 """Write the configs.inc file for MadEvent""" 3511 3512 # Extract number of external particles 3513 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial() 3514 3515 model = matrix_element.get('processes')[0].get('model') 3516 configs = [(i+1, d) for (i, d) in \ 3517 enumerate(matrix_element.get('diagrams'))] 3518 mapconfigs = [c[0] for c in configs] 3519 return mapconfigs, self.write_configs_file_from_diagrams(writer, 3520 [[c[1]] for c in configs], 3521 mapconfigs, 3522 nexternal, ninitial, 3523 model)
3524 3525 #=========================================================================== 3526 # write_run_configs_file 3527 #===========================================================================
3528 - def write_run_config_file(self, writer):
3529 """Write the run_configs.inc file for MadEvent""" 3530 3531 path = pjoin(_file_path,'iolibs','template_files','madevent_run_config.inc') 3532 text = open(path).read() % {'chanperjob':'5'} 3533 writer.write(text) 3534 return True
3535 3536 3537 #=========================================================================== 3538 # write_configs_file_from_diagrams 3539 #===========================================================================
3540 - def write_configs_file_from_diagrams(self, writer, configs, mapconfigs, 3541 nexternal, ninitial, model):
3542 """Write the actual configs.inc file. 3543 3544 configs is the diagrams corresponding to configs (each 3545 diagrams is a list of corresponding diagrams for all 3546 subprocesses, with None if there is no corresponding diagrams 3547 for a given process). 3548 mapconfigs gives the diagram number for each config. 3549 3550 For s-channels, we need to output one PDG for each subprocess in 3551 the subprocess group, in order to be able to pick the right 3552 one for multiprocesses.""" 3553 3554 lines = [] 3555 3556 s_and_t_channels = [] 3557 3558 nqcd_list = [] 3559 3560 minvert = min([max([d for d in config if d][0].get_vertex_leg_numbers()) \ 3561 for config in configs]) 3562 3563 # Number of subprocesses 3564 nsubprocs = len(configs[0]) 3565 3566 nconfigs = 0 3567 3568 new_pdg = model.get_first_non_pdg() 3569 3570 for iconfig, helas_diags in enumerate(configs): 3571 if any([vert > minvert for vert in 3572 [d for d in helas_diags if d][0].get_vertex_leg_numbers()]): 3573 # Only 3-vertices allowed in configs.inc 3574 continue 3575 nconfigs += 1 3576 3577 # Need s- and t-channels for all subprocesses, including 3578 # those that don't contribute to this config 3579 empty_verts = [] 3580 stchannels = [] 3581 for h in helas_diags: 3582 if h: 3583 # get_s_and_t_channels gives vertices starting from 3584 # final state external particles and working inwards 3585 stchannels.append(h.get('amplitudes')[0].\ 3586 get_s_and_t_channels(ninitial, model, 3587 new_pdg)) 3588 else: 3589 stchannels.append((empty_verts, None)) 3590 3591 # For t-channels, just need the first non-empty one 3592 tchannels = [t for s,t in stchannels if t != None][0] 3593 3594 # For s_and_t_channels (to be used later) use only first config 3595 s_and_t_channels.append([[s for s,t in stchannels if t != None][0], 3596 tchannels]) 3597 3598 # Make sure empty_verts is same length as real vertices 3599 if any([s for s,t in stchannels]): 3600 empty_verts[:] = [None]*max([len(s) for s,t in stchannels]) 3601 3602 # Reorganize s-channel vertices to get a list of all 3603 # subprocesses for each vertex 3604 schannels = zip(*[s for s,t in stchannels]) 3605 else: 3606 schannels = [] 3607 3608 allchannels = schannels 3609 if len(tchannels) > 1: 3610 # Write out tchannels only if there are any non-trivial ones 3611 allchannels = schannels + tchannels 3612 3613 # Write out propagators for s-channel and t-channel vertices 3614 3615 lines.append("# Diagram %d" % (mapconfigs[iconfig])) 3616 # Correspondance between the config and the diagram = amp2 3617 lines.append("data mapconfig(%d)/%d/" % (nconfigs, 3618 mapconfigs[iconfig])) 3619 # Number of QCD couplings in this diagram 3620 nqcd = 0 3621 for h in helas_diags: 3622 if h: 3623 try: 3624 nqcd = h.calculate_orders()['QCD'] 3625 except KeyError: 3626 pass 3627 break 3628 else: 3629 continue 3630 3631 nqcd_list.append(nqcd) 3632 3633 for verts in allchannels: 3634 if verts in schannels: 3635 vert = [v for v in verts if v][0] 3636 else: 3637 vert = verts 3638 daughters = [leg.get('number') for leg in vert.get('legs')[:-1]] 3639 last_leg = vert.get('legs')[-1] 3640 lines.append("data (iforest(i,%d,%d),i=1,%d)/%s/" % \ 3641 (last_leg.get('number'), nconfigs, len(daughters), 3642 ",".join([str(d) for d in daughters]))) 3643 if verts in schannels: 3644 pdgs = [] 3645 for v in verts: 3646 if v: 3647 pdgs.append(v.get('legs')[-1].get('id')) 3648 else: 3649 pdgs.append(0) 3650 lines.append("data (sprop(i,%d,%d),i=1,%d)/%s/" % \ 3651 (last_leg.get('number'), nconfigs, nsubprocs, 3652 ",".join([str(d) for d in pdgs]))) 3653 lines.append("data tprid(%d,%d)/0/" % \ 3654 (last_leg.get('number'), nconfigs)) 3655 elif verts in tchannels[:-1]: 3656 lines.append("data tprid(%d,%d)/%d/" % \ 3657 (last_leg.get('number'), nconfigs, 3658 abs(last_leg.get('id')))) 3659 lines.append("data (sprop(i,%d,%d),i=1,%d)/%s/" % \ 3660 (last_leg.get('number'), nconfigs, nsubprocs, 3661 ",".join(['0'] * nsubprocs))) 3662 3663 # Write out number of configs 3664 lines.append("# Number of configs") 3665 lines.append("data mapconfig(0)/%d/" % nconfigs) 3666 3667 # Write the file 3668 writer.writelines(lines) 3669 3670 return s_and_t_channels, nqcd_list
3671 3672 #=========================================================================== 3673 # write_decayBW_file 3674 #===========================================================================
3675 - def write_decayBW_file(self, writer, s_and_t_channels):
3676 """Write the decayBW.inc file for MadEvent""" 3677 3678 lines = [] 3679 3680 booldict = {None: "0", True: "1", False: "2"} 3681 3682 for iconf, config in enumerate(s_and_t_channels): 3683 schannels = config[0] 3684 for vertex in schannels: 3685 # For the resulting leg, pick out whether it comes from 3686 # decay or not, as given by the onshell flag 3687 leg = vertex.get('legs')[-1] 3688 lines.append("data gForceBW(%d,%d)/%s/" % \ 3689 (leg.get('number'), iconf + 1, 3690 booldict[leg.get('onshell')])) 3691 3692 # Write the file 3693 writer.writelines(lines) 3694 3695 return True
3696 3697 #=========================================================================== 3698 # write_dname_file 3699 #===========================================================================
3700 - def write_dname_file(self, writer, dir_name):
3701 """Write the dname.mg file for MG4""" 3702 3703 line = "DIRNAME=%s" % dir_name 3704 3705 # Write the file 3706 writer.write(line + "\n") 3707 3708 return True
3709 3710 #=========================================================================== 3711 # write_driver 3712 #===========================================================================
3713 - def write_driver(self, writer, v5=True):
3714 """Write the SubProcess/driver.f file for MG4""" 3715 3716 path = pjoin(_file_path,'iolibs','template_files','madevent_driver.f') 3717 3718 if self.model_name == 'mssm' or self.model_name.startswith('mssm-'): 3719 card = 'Source/MODEL/MG5_param.dat' 3720 else: 3721 card = 'param_card.dat' 3722 if v5: 3723 text = open(path).read() % {'param_card_name':card, 'secondparam':''} 3724 else: 3725 text = open(path).read() % {'param_card_name':card, 3726 'secondparam': ',.true.'} 3727 writer.write(text) 3728 3729 return True
3730 3731 #=========================================================================== 3732 # write_addmothers 3733 #===========================================================================
3734 - def write_addmothers(self, writer):
3735 """Write the SubProcess/addmothers.f""" 3736 3737 path = pjoin(_file_path,'iolibs','template_files','addmothers.f') 3738 3739 text = open(path).read() % {'iconfig': 'diag_number'} 3740 writer.write(text) 3741 3742 return True
3743 3744 3745 #=========================================================================== 3746 # write_combine_events 3747 #===========================================================================
3748 - def write_combine_events(self, writer, nb_proc=100):
3749 """Write the SubProcess/driver.f file for MG4""" 3750 3751 path = pjoin(_file_path,'iolibs','template_files','madevent_combine_events.f') 3752 3753 if self.model_name == 'mssm' or self.model_name.startswith('mssm-'): 3754 card = 'Source/MODEL/MG5_param.dat' 3755 else: 3756 card = 'param_card.dat' 3757 3758 #set maxpup (number of @X in the process card) 3759 3760 text = open(path).read() % {'param_card_name':card, 'maxpup':nb_proc+1} 3761 #the +1 is just a security. This is not needed but I feel(OM) safer with it. 3762 writer.write(text) 3763 3764 return True
3765 3766 3767 #=========================================================================== 3768 # write_symmetry 3769 #===========================================================================
3770 - def write_symmetry(self, writer, v5=True):
3771 """Write the SubProcess/driver.f file for ME""" 3772 3773 path = pjoin(_file_path,'iolibs','template_files','madevent_symmetry.f') 3774 3775 if self.model_name == 'mssm' or self.model_name.startswith('mssm-'): 3776 card = 'Source/MODEL/MG5_param.dat' 3777 else: 3778 card = 'param_card.dat' 3779 text = open(path).read() 3780 3781 if v5: 3782 text = text % {'param_card_name':card, 'setparasecondarg':''} 3783 else: 3784 text = text % {'param_card_name':card, 'setparasecondarg':',.true.'} 3785 writer.write(text) 3786 3787 return True
3788 3789 3790 3791 3792 #=========================================================================== 3793 # write_iproc_file 3794 #===========================================================================
3795 - def write_iproc_file(self, writer, me_number):
3796 """Write the iproc.dat file for MG4""" 3797 line = "%d" % (me_number + 1) 3798 3799 # Write the file 3800 for line_to_write in writer.write_line(line): 3801 writer.write(line_to_write) 3802 return True
3803 3804 #=========================================================================== 3805 # write_mg_sym_file 3806 #===========================================================================
3807 - def write_mg_sym_file(self, writer, matrix_element):
3808 """Write the mg.sym file for MadEvent.""" 3809 3810 lines = [] 3811 3812 # Extract process with all decays included 3813 final_legs = filter(lambda leg: leg.get('state') == True, 3814 matrix_element.get('processes')[0].get_legs_with_decays()) 3815 3816 ninitial = len(filter(lambda leg: leg.get('state') == False, 3817 matrix_element.get('processes')[0].get('legs'))) 3818 3819 identical_indices = {} 3820 3821 # Extract identical particle info 3822 for i, leg in enumerate(final_legs): 3823 if leg.get('id') in identical_indices: 3824 identical_indices[leg.get('id')].append(\ 3825 i + ninitial + 1) 3826 else: 3827 identical_indices[leg.get('id')] = [i + ninitial + 1] 3828 3829 # Remove keys which have only one particle 3830 for key in identical_indices.keys(): 3831 if len(identical_indices[key]) < 2: 3832 del identical_indices[key] 3833 3834 # Write mg.sym file 3835 lines.append(str(len(identical_indices.keys()))) 3836 for key in identical_indices.keys(): 3837 lines.append(str(len(identical_indices[key]))) 3838 for number in identical_indices[key]: 3839 lines.append(str(number)) 3840 3841 # Write the file 3842 writer.writelines(lines) 3843 3844 return True
3845 3846 #=========================================================================== 3847 # write_mg_sym_file 3848 #===========================================================================
3849 - def write_default_mg_sym_file(self, writer):
3850 """Write the mg.sym file for MadEvent.""" 3851 3852 lines = "0" 3853 3854 # Write the file 3855 writer.writelines(lines) 3856 3857 return True
3858 3859 #=========================================================================== 3860 # write_ncombs_file 3861 #===========================================================================
3862 - def write_ncombs_file(self, writer, nexternal):
3863 """Write the ncombs.inc file for MadEvent.""" 3864 3865 # ncomb (used for clustering) is 2^nexternal 3866 file = " integer n_max_cl\n" 3867 file = file + "parameter (n_max_cl=%d)" % (2 ** nexternal) 3868 3869 # Write the file 3870 writer.writelines(file) 3871 3872 return True
3873 3874 #=========================================================================== 3875 # write_processes_file 3876 #===========================================================================
3877 - def write_processes_file(self, writer, subproc_group):
3878 """Write the processes.dat file with info about the subprocesses 3879 in this group.""" 3880 3881 lines = [] 3882 3883 for ime, me in \ 3884 enumerate(subproc_group.get('matrix_elements')): 3885 lines.append("%s %s" % (str(ime+1) + " " * (7-len(str(ime+1))), 3886 ",".join(p.base_string() for p in \ 3887 me.get('processes')))) 3888 if me.get('has_mirror_process'): 3889 mirror_procs = [copy.copy(p) for p in me.get('processes')] 3890 for proc in mirror_procs: 3891 legs = copy.copy(proc.get('legs_with_decays')) 3892 legs.insert(0, legs.pop(1)) 3893 proc.set("legs_with_decays", legs) 3894 lines.append("mirror %s" % ",".join(p.base_string() for p in \ 3895 mirror_procs)) 3896 else: 3897 lines.append("mirror none") 3898 3899 # Write the file 3900 writer.write("\n".join(lines)) 3901 3902 return True
3903 3904 #=========================================================================== 3905 # write_symswap_file 3906 #===========================================================================
3907 - def write_symswap_file(self, writer, ident_perms):
3908 """Write the file symswap.inc for MG4 by comparing diagrams using 3909 the internal matrix element value functionality.""" 3910 3911 lines = [] 3912 3913 # Write out lines for symswap.inc file (used to permute the 3914 # external leg momenta 3915 for iperm, perm in enumerate(ident_perms): 3916 lines.append("data (isym(i,%d),i=1,nexternal)/%s/" % \ 3917 (iperm+1, ",".join([str(i+1) for i in perm]))) 3918 lines.append("data nsym/%d/" % len(ident_perms)) 3919 3920 # Write the file 3921 writer.writelines(lines) 3922 3923 return True
3924 3925 #=========================================================================== 3926 # write_symfact_file 3927 #===========================================================================
3928 - def write_symfact_file(self, writer, symmetry):
3929 """Write the files symfact.dat for MG4 by comparing diagrams using 3930 the internal matrix element value functionality.""" 3931 3932 pos = max(2, int(math.ceil(math.log10(len(symmetry))))) 3933 form = "%"+str(pos)+"r %"+str(pos+1)+"r" 3934 # Write out lines for symswap.inc file (used to permute the 3935 # external leg momenta 3936 lines = [ form %(i+1, s) for i,s in enumerate(symmetry) if s != 0] 3937 # Write the file 3938 writer.write('\n'.join(lines)) 3939 writer.write('\n') 3940 3941 return True
3942 3943 #=========================================================================== 3944 # write_symperms_file 3945 #===========================================================================
3946 - def write_symperms_file(self, writer, perms):
3947 """Write the symperms.inc file for subprocess group, used for 3948 symmetric configurations""" 3949 3950 lines = [] 3951 for iperm, perm in enumerate(perms): 3952 lines.append("data (perms(i,%d),i=1,nexternal)/%s/" % \ 3953 (iperm+1, ",".join([str(i+1) for i in perm]))) 3954 3955 # Write the file 3956 writer.writelines(lines) 3957 3958 return True
3959 3960 #=========================================================================== 3961 # write_subproc 3962 #===========================================================================
3963 - def write_subproc(self, writer, subprocdir):
3964 """Append this subprocess to the subproc.mg file for MG4""" 3965 3966 # Write line to file 3967 writer.write(subprocdir + "\n") 3968 3969 return True
3970 3971 #=============================================================================== 3972 # ProcessExporterFortranMEGroup 3973 #===============================================================================
3974 -class ProcessExporterFortranMEGroup(ProcessExporterFortranME):
3975 """Class to take care of exporting a set of matrix elements to 3976 MadEvent subprocess group format.""" 3977 3978 matrix_file = "matrix_madevent_group_v4.inc" 3979 3980 #=========================================================================== 3981 # generate_subprocess_directory_v4 3982 #===========================================================================
3983 - def generate_subprocess_directory_v4(self, subproc_group, 3984 fortran_model, 3985 group_number):
3986 """Generate the Pn directory for a subprocess group in MadEvent, 3987 including the necessary matrix_N.f files, configs.inc and various 3988 other helper files""" 3989 3990 assert isinstance(subproc_group, group_subprocs.SubProcessGroup), \ 3991 "subproc_group object not SubProcessGroup" 3992 3993 if not self.model: 3994 self.model = subproc_group.get('matrix_elements')[0].\ 3995 get('processes')[0].get('model') 3996 3997 cwd = os.getcwd() 3998 path = pjoin(self.dir_path, 'SubProcesses') 3999 4000 os.chdir(path) 4001 pathdir = os.getcwd() 4002 4003 # Create the directory PN in the specified path 4004 subprocdir = "P%d_%s" % (subproc_group.get('number'), 4005 subproc_group.get('name')) 4006 try: 4007 os.mkdir(subprocdir) 4008 except os.error as error: 4009 logger.warning(error.strerror + " " + subprocdir) 4010 4011 try: 4012 os.chdir(subprocdir) 4013 except os.error: 4014 logger.error('Could not cd to directory %s' % subprocdir) 4015 return 0 4016 4017 logger.info('Creating files in directory %s' % subprocdir) 4018 4019 # Create the matrix.f files, auto_dsig.f files and all inc files 4020 # for all subprocesses in the group 4021 4022 maxamps = 0 4023 maxflows = 0 4024 tot_calls = 0 4025 4026 matrix_elements = subproc_group.get('matrix_elements') 4027 4028 for ime, matrix_element in \ 4029 enumerate(matrix_elements): 4030 filename = 'matrix%d.f' % (ime+1) 4031 calls, ncolor = \ 4032 self.write_matrix_element_v4(writers.FortranWriter(filename), 4033 matrix_element, 4034 fortran_model, 4035 str(ime+1), 4036 subproc_group.get('diagram_maps')[\ 4037 ime]) 4038 4039 filename = 'auto_dsig%d.f' % (ime+1) 4040 self.write_auto_dsig_file(writers.FortranWriter(filename), 4041 matrix_element, 4042 str(ime+1)) 4043 4044 # Keep track of needed quantities 4045 tot_calls += int(calls) 4046 maxflows = max(maxflows, ncolor) 4047 maxamps = max(maxamps, len(matrix_element.get('diagrams'))) 4048 4049 # Draw diagrams 4050 filename = "matrix%d.ps" % (ime+1) 4051 plot = draw.MultiEpsDiagramDrawer(matrix_element.get('base_amplitude').\ 4052 get('diagrams'), 4053 filename, 4054 model = \ 4055 matrix_element.get('processes')[0].\ 4056 get('model'), 4057 amplitude=True) 4058 logger.info("Generating Feynman diagrams for " + \ 4059 matrix_element.get('processes')[0].nice_string()) 4060 plot.draw() 4061 4062 # Extract number of external particles 4063 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial() 4064 4065 # Generate a list of diagrams corresponding to each configuration 4066 # [[d1, d2, ...,dn],...] where 1,2,...,n is the subprocess number 4067 # If a subprocess has no diagrams for this config, the number is 0 4068 4069 subproc_diagrams_for_config = subproc_group.get('diagrams_for_configs') 4070 4071 filename = 'auto_dsig.f' 4072 self.write_super_auto_dsig_file(writers.FortranWriter(filename), 4073 subproc_group) 4074 4075 filename = 'coloramps.inc' 4076 self.write_coloramps_file(writers.FortranWriter(filename), 4077 subproc_diagrams_for_config, 4078 maxflows, 4079 matrix_elements) 4080 4081 filename = 'get_color.f' 4082 self.write_colors_file(writers.FortranWriter(filename), 4083 matrix_elements) 4084 4085 filename = 'config_subproc_map.inc' 4086 self.write_config_subproc_map_file(writers.FortranWriter(filename), 4087 subproc_diagrams_for_config) 4088 4089 filename = 'configs.inc' 4090 nconfigs, (s_and_t_channels, nqcd_list) = self.write_configs_file(\ 4091 writers.FortranWriter(filename), 4092 subproc_group, 4093 subproc_diagrams_for_config) 4094 4095 filename = 'config_nqcd.inc' 4096 self.write_config_nqcd_file(writers.FortranWriter(filename), 4097 nqcd_list) 4098 4099 filename = 'decayBW.inc' 4100 self.write_decayBW_file(writers.FortranWriter(filename), 4101 s_and_t_channels) 4102 4103 filename = 'dname.mg' 4104 self.write_dname_file(writers.FortranWriter(filename), 4105 subprocdir) 4106 4107 filename = 'iproc.dat' 4108 self.write_iproc_file(writers.FortranWriter(filename), 4109 group_number) 4110 4111 filename = 'leshouche.inc' 4112 self.write_leshouche_file(writers.FortranWriter(filename), 4113 subproc_group) 4114 4115 filename = 'maxamps.inc' 4116 self.write_maxamps_file(writers.FortranWriter(filename), 4117 maxamps, 4118 maxflows, 4119 max([len(me.get('processes')) for me in \ 4120 matrix_elements]), 4121 len(matrix_elements)) 4122 4123 # Note that mg.sym is not relevant for this case 4124 filename = 'mg.sym' 4125 self.write_default_mg_sym_file(writers.FortranWriter(filename)) 4126 4127 filename = 'mirrorprocs.inc' 4128 self.write_mirrorprocs(writers.FortranWriter(filename), 4129 subproc_group) 4130 4131 filename = 'ncombs.inc' 4132 self.write_ncombs_file(writers.FortranWriter(filename), 4133 nexternal) 4134 4135 filename = 'nexternal.inc' 4136 self.write_nexternal_file(writers.FortranWriter(filename), 4137 nexternal, ninitial) 4138 4139 filename = 'ngraphs.inc' 4140 self.write_ngraphs_file(writers.FortranWriter(filename), 4141 nconfigs) 4142 4143 filename = 'pmass.inc' 4144 self.write_pmass_file(writers.FortranWriter(filename), 4145 matrix_element) 4146 4147 filename = 'props.inc' 4148 self.write_props_file(writers.FortranWriter(filename), 4149 matrix_element, 4150 s_and_t_channels) 4151 4152 filename = 'processes.dat' 4153 files.write_to_file(filename, 4154 self.write_processes_file, 4155 subproc_group) 4156 4157 # Find config symmetries and permutations 4158 symmetry, perms, ident_perms = \ 4159 diagram_symmetry.find_symmetry(subproc_group) 4160 4161 filename = 'symswap.inc' 4162 self.write_symswap_file(writers.FortranWriter(filename), 4163 ident_perms) 4164 4165 filename = 'symfact_orig.dat' 4166 self.write_symfact_file(open(filename, 'w'), symmetry) 4167 4168 filename = 'symperms.inc' 4169 self.write_symperms_file(writers.FortranWriter(filename), 4170 perms) 4171 4172 # Generate jpgs -> pass in make_html 4173 #os.system(pjoin('..', '..', 'bin', 'gen_jpeg-pl')) 4174 4175 #import genps.inc and maxconfigs.inc into 4176 ln(self.dir_path + '/Source/genps.inc', self.dir_path + '/SubProcesses', log=False) 4177 ln(self.dir_path + '/Source/maxconfigs.inc', self.dir_path + '/SubProcesses', log=False) 4178 4179 linkfiles = ['addmothers.f', 4180 'cluster.f', 4181 'cluster.inc', 4182 'coupl.inc', 4183 'cuts.f', 4184 'cuts.inc', 4185 'driver.f', 4186 'genps.f', 4187 'genps.inc', 4188 'idenparts.f', 4189 'initcluster.f', 4190 'makefile', 4191 'message.inc', 4192 'myamp.f', 4193 'reweight.f', 4194 'run.inc', 4195 'maxconfigs.inc', 4196 'maxparticles.inc', 4197 'run_config.inc', 4198 'setcuts.f', 4199 'setscales.f', 4200 'sudakov.inc', 4201 'symmetry.f', 4202 'unwgt.f'] 4203 4204 for file in linkfiles: 4205 ln('../' + file , '.') 4206 4207 #import nexternal/leshouch in Source 4208 ln('nexternal.inc', '../../Source', log=False) 4209 ln('leshouche.inc', '../../Source', log=False) 4210 ln('maxamps.inc', '../../Source', log=False) 4211 4212 # Return to SubProcesses dir) 4213 os.chdir(pathdir) 4214 4215 # Add subprocess to subproc.mg 4216 filename = 'subproc.mg' 4217 files.append_to_file(filename, 4218 self.write_subproc, 4219 subprocdir) 4220 4221 # Generate info page 4222 gen_infohtml.make_info_html(os.path.pardir) 4223 4224 # Return to original dir 4225 os.chdir(cwd) 4226 4227 if not tot_calls: 4228 tot_calls = 0 4229 return tot_calls
4230 4231 #=========================================================================== 4232 # write_super_auto_dsig_file 4233 #===========================================================================
4234 - def write_super_auto_dsig_file(self, writer, subproc_group):
4235 """Write the auto_dsig.f file selecting between the subprocesses 4236 in subprocess group mode""" 4237 4238 replace_dict = {} 4239 4240 # Extract version number and date from VERSION file 4241 info_lines = self.get_mg5_info_lines() 4242 replace_dict['info_lines'] = info_lines 4243 4244 matrix_elements = subproc_group.get('matrix_elements') 4245 4246 # Extract process info lines 4247 process_lines = '\n'.join([self.get_process_info_lines(me) for me in \ 4248 matrix_elements]) 4249 replace_dict['process_lines'] = process_lines 4250 4251 nexternal, ninitial = matrix_elements[0].get_nexternal_ninitial() 4252 replace_dict['nexternal'] = nexternal 4253 4254 replace_dict['nsprocs'] = 2*len(matrix_elements) 4255 4256 # Generate dsig definition line 4257 dsig_def_line = "DOUBLE PRECISION " + \ 4258 ",".join(["DSIG%d" % (iproc + 1) for iproc in \ 4259 range(len(matrix_elements))]) 4260 replace_dict["dsig_def_line"] = dsig_def_line 4261 4262 # Generate dsig process lines 4263 call_dsig_proc_lines = [] 4264 for iproc in range(len(matrix_elements)): 4265 call_dsig_proc_lines.append(\ 4266 "IF(IPROC.EQ.%(num)d) DSIGPROC=DSIG%(num)d(P1,WGT,IMODE) ! %(proc)s" % \ 4267 {"num": iproc + 1, 4268 "proc": matrix_elements[iproc].get('processes')[0].base_string()}) 4269 replace_dict['call_dsig_proc_lines'] = "\n".join(call_dsig_proc_lines) 4270 4271 file = open(pjoin(_file_path, \ 4272 'iolibs/template_files/super_auto_dsig_group_v4.inc')).read() 4273 file = file % replace_dict 4274 4275 # Write the file 4276 writer.writelines(file)
4277 4278 #=========================================================================== 4279 # write_mirrorprocs 4280 #===========================================================================
4281 - def write_mirrorprocs(self, writer, subproc_group):
4282 """Write the mirrorprocs.inc file determining which processes have 4283 IS mirror process in subprocess group mode.""" 4284 4285 lines = [] 4286 bool_dict = {True: '.true.', False: '.false.'} 4287 matrix_elements = subproc_group.get('matrix_elements') 4288 lines.append("DATA (MIRRORPROCS(I),I=1,%d)/%s/" % \ 4289 (len(matrix_elements), 4290 ",".join([bool_dict[me.get('has_mirror_process')] for \ 4291 me in matrix_elements]))) 4292 # Write the file 4293 writer.writelines(lines)
4294 4295 #=========================================================================== 4296 # write_addmothers 4297 #===========================================================================
4298 - def write_addmothers(self, writer):
4299 """Write the SubProcess/addmothers.f""" 4300 4301 path = pjoin(_file_path,'iolibs','template_files','addmothers.f') 4302 4303 text = open(path).read() % {'iconfig': 'lconfig'} 4304 writer.write(text) 4305 4306 return True
4307 4308 4309 #=========================================================================== 4310 # write_coloramps_file 4311 #===========================================================================
4312 - def write_coloramps_file(self, writer, diagrams_for_config, maxflows, 4313 matrix_elements):
4314 """Write the coloramps.inc file for MadEvent in Subprocess group mode""" 4315 4316 # Create a map from subprocess (matrix element) to a list of 4317 # the diagrams corresponding to each config 4318 4319 lines = [] 4320 4321 subproc_to_confdiag = {} 4322 for config in diagrams_for_config: 4323 for subproc, diag in enumerate(config): 4324 try: 4325 subproc_to_confdiag[subproc].append(diag) 4326 except KeyError: 4327 subproc_to_confdiag[subproc] = [diag] 4328 4329 for subproc in sorted(subproc_to_confdiag.keys()): 4330 lines.extend(self.get_icolamp_lines(subproc_to_confdiag[subproc], 4331 matrix_elements[subproc], 4332 subproc + 1)) 4333 4334 lines.insert(0, "logical icolamp(%d,%d,%d)" % \ 4335 (maxflows, 4336 len(diagrams_for_config), 4337 len(matrix_elements))) 4338 4339 # Write the file 4340 writer.writelines(lines) 4341 4342 return True
4343 4344 #=========================================================================== 4345 # write_config_subproc_map_file 4346 #===========================================================================
4347 - def write_config_subproc_map_file(self, writer, config_subproc_map):
4348 """Write the config_subproc_map.inc file for subprocess groups""" 4349 4350 lines = [] 4351 # Output only configs that have some corresponding diagrams 4352 iconfig = 0 4353 for config in config_subproc_map: 4354 if set(config) == set([0]): 4355 continue 4356 lines.append("DATA (CONFSUB(i,%d),i=1,%d)/%s/" % \ 4357 (iconfig + 1, len(config), 4358 ",".join([str(i) for i in config]))) 4359 iconfig += 1 4360 # Write the file 4361 writer.writelines(lines) 4362 4363 return True
4364 4365 #=========================================================================== 4366 # write_configs_file 4367 #===========================================================================
4368 - def write_configs_file(self, writer, subproc_group, diagrams_for_config):
4369 """Write the configs.inc file with topology information for a 4370 subprocess group. Use the first subprocess with a diagram for each 4371 configuration.""" 4372 4373 matrix_elements = subproc_group.get('matrix_elements') 4374 model = matrix_elements[0].get('processes')[0].get('model') 4375 4376 diagrams = [] 4377 config_numbers = [] 4378 for iconfig, config in enumerate(diagrams_for_config): 4379 # Check if any diagrams correspond to this config 4380 if set(config) == set([0]): 4381 continue 4382 subproc_diags = [] 4383 for s,d in enumerate(config): 4384 if d: 4385 subproc_diags.append(matrix_elements[s].\ 4386 get('diagrams')[d-1]) 4387 else: 4388 subproc_diags.append(None) 4389 diagrams.append(subproc_diags) 4390 config_numbers.append(iconfig + 1) 4391 4392 # Extract number of external particles 4393 (nexternal, ninitial) = subproc_group.get_nexternal_ninitial() 4394 4395 return len(diagrams), \ 4396 self.write_configs_file_from_diagrams(writer, diagrams, 4397 config_numbers, 4398 nexternal, ninitial, 4399 model)
4400 4401 #=========================================================================== 4402 # write_run_configs_file 4403 #===========================================================================
4404 - def write_run_config_file(self, writer):
4405 """Write the run_configs.inc file for MadEvent""" 4406 4407 path = pjoin(_file_path,'iolibs','template_files','madevent_run_config.inc') 4408 text = open(path).read() % {'chanperjob':'2'} 4409 writer.write(text) 4410 return True
4411 4412 4413 #=========================================================================== 4414 # write_leshouche_file 4415 #===========================================================================
4416 - def write_leshouche_file(self, writer, subproc_group):
4417 """Write the leshouche.inc file for MG4""" 4418 4419 all_lines = [] 4420 4421 for iproc, matrix_element in \ 4422 enumerate(subproc_group.get('matrix_elements')): 4423 all_lines.extend(self.get_leshouche_lines(matrix_element, 4424 iproc)) 4425 4426 # Write the file 4427 writer.writelines(all_lines) 4428 4429 return True
4430 4431 #=============================================================================== 4432 # UFO_model_to_mg4 4433 #=============================================================================== 4434 python_to_fortran = lambda x: parsers.UFOExpressionParserFortran().parse(x) 4435
4436 -class UFO_model_to_mg4(object):
4437 """ A converter of the UFO-MG5 Model to the MG4 format """ 4438 4439 # The list below shows the only variables the user is allowed to change by 4440 # himself for each PS point. If he changes any other, then calling 4441 # UPDATE_AS_PARAM() (or equivalently MP_UPDATE_AS_PARAM()) will not 4442 # correctly account for the change. 4443 PS_dependent_key = ['aS','MU_R'] 4444 mp_complex_format = 'complex*32' 4445 mp_real_format = 'real*16' 4446 # Warning, it is crucial none of the couplings/parameters of the model 4447 # starts with this prefix. I should add a check for this. 4448 # You can change it as the global variable to check_param_card.ParamCard 4449 mp_prefix = check_param_card.ParamCard.mp_prefix 4450
4451 - def __init__(self, model, output_path, opt=None):
4452 """ initialization of the objects """ 4453 4454 self.model = model 4455 self.model_name = model['name'] 4456 self.dir_path = output_path 4457 if opt: 4458 self.opt = opt 4459 else: 4460 self.opt = {'complex_mass': False, 'export_format': 'madevent', 'mp':True} 4461 4462 self.coups_dep = [] # (name, expression, type) 4463 self.coups_indep = [] # (name, expression, type) 4464 self.params_dep = [] # (name, expression, type) 4465 self.params_indep = [] # (name, expression, type) 4466 self.params_ext = [] # external parameter 4467 self.p_to_f = parsers.UFOExpressionParserFortran() 4468 self.mp_p_to_f = parsers.UFOExpressionParserMPFortran()
4469
4471 """modify the parameter if some of them are identical up to the case""" 4472 4473 lower_dict={} 4474 duplicate = set() 4475 keys = self.model['parameters'].keys() 4476 for key in keys: 4477 for param in self.model['parameters'][key]: 4478 lower_name = param.name.lower() 4479 if not lower_name: 4480 continue 4481 try: 4482 lower_dict[lower_name].append(param) 4483 except KeyError,error: 4484 lower_dict[lower_name] = [param] 4485 else: 4486 duplicate.add(lower_name) 4487 logger.debug('%s is define both as lower case and upper case.' 4488 % lower_name) 4489 if not duplicate: 4490 return 4491 4492 re_expr = r'''\b(%s)\b''' 4493 to_change = [] 4494 change={} 4495 for value in duplicate: 4496 for i, var in enumerate(lower_dict[value][1:]): 4497 to_change.append(var.name) 4498 change[var.name] = '%s__%s' %( var.name.lower(), i+2) 4499 var.name = '%s__%s' %( var.name.lower(), i+2) 4500 4501 replace = lambda match_pattern: change[match_pattern.groups()[0]] 4502 rep_pattern = re.compile(re_expr % '|'.join(to_change)) 4503 4504 # change parameters 4505 for key in keys: 4506 if key == ('external',): 4507 continue 4508 for param in self.model['parameters'][key]: 4509 param.expr = rep_pattern.sub(replace, param.expr) 4510 4511 # change couplings 4512 for key in self.model['couplings'].keys(): 4513 for coup in self.model['couplings'][key]: 4514 coup.expr = rep_pattern.sub(replace, coup.expr) 4515 4516 # change mass/width 4517 for part in self.model['particles']: 4518 if str(part.get('mass')) in to_change: 4519 part.set('mass', rep_pattern.sub(replace, str(part.get('mass')))) 4520 if str(part.get('width')) in to_change: 4521 part.set('width', rep_pattern.sub(replace, str(part.get('width'))))
4522
4523 - def refactorize(self, wanted_couplings = []):
4524 """modify the couplings to fit with MG4 convention """ 4525 4526 # Keep only separation in alphaS 4527 keys = self.model['parameters'].keys() 4528 keys.sort(key=len) 4529 for key in keys: 4530 to_add = [o for o in self.model['parameters'][key] if o.name] 4531 4532 if key == ('external',): 4533 self.params_ext += to_add 4534 elif any([(k in key) for k in self.PS_dependent_key]): 4535 self.params_dep += to_add 4536 else: 4537 self.params_indep += to_add 4538 # same for couplings 4539 keys = self.model['couplings'].keys() 4540 keys.sort(key=len) 4541 for key, coup_list in self.model['couplings'].items(): 4542 if any([(k in key) for k in self.PS_dependent_key]): 4543 self.coups_dep += [c for c in coup_list if 4544 (not wanted_couplings or c.name in \ 4545 wanted_couplings)] 4546 else: 4547 self.coups_indep += [c for c in coup_list if 4548 (not wanted_couplings or c.name in \ 4549 wanted_couplings)] 4550 4551 # MG4 use G and not aS as it basic object for alphas related computation 4552 #Pass G in the independant list 4553 if 'G' in self.params_dep: 4554 index = self.params_dep.index('G') 4555 G = self.params_dep.pop(index) 4556 # G.expr = '2*cmath.sqrt(as*pi)' 4557 # self.params_indep.insert(0, self.params_dep.pop(index)) 4558 # No need to add it if not defined 4559 4560 if 'aS' not in self.params_ext: 4561 logger.critical('aS not define as external parameter adding it!') 4562 #self.model['parameters']['aS'] = base_objects.ParamCardVariable('aS', 0.138,'DUMMY',(1,)) 4563 self.params_indep.append( base_objects. ModelVariable('aS', '0.138','real')) 4564 self.params_indep.append( base_objects. ModelVariable('G', '4.1643','real'))
4565 - def build(self, wanted_couplings = [], full=True):
4566 """modify the couplings to fit with MG4 convention and creates all the 4567 different files""" 4568 4569 self.pass_parameter_to_case_insensitive() 4570 self.refactorize(wanted_couplings) 4571 4572 # write the files 4573 if full: 4574 self.write_all()
4575 4576
4577 - def open(self, name, comment='c', format='default'):
4578 """ Open the file name in the correct directory and with a valid 4579 header.""" 4580 4581 file_path = pjoin(self.dir_path, name) 4582 4583 if format == 'fortran': 4584 fsock = writers.FortranWriter(file_path, 'w') 4585 else: 4586 fsock = open(file_path, 'w') 4587 4588 file.writelines(fsock, comment * 77 + '\n') 4589 file.writelines(fsock,'%(comment)s written by the UFO converter\n' % \ 4590 {'comment': comment + (6 - len(comment)) * ' '}) 4591 file.writelines(fsock, comment * 77 + '\n\n') 4592 return fsock
4593 4594
4595 - def write_all(self):
4596 """ write all the files """ 4597 #write the part related to the external parameter 4598 self.create_ident_card() 4599 self.create_param_read() 4600 4601 #write the definition of the parameter 4602 self.create_input() 4603 self.create_intparam_def(dp=True,mp=False) 4604 if self.opt['mp']: 4605 self.create_intparam_def(dp=False,mp=True) 4606 4607 4608 # definition of the coupling. 4609 self.create_actualize_mp_ext_param_inc() 4610 self.create_coupl_inc() 4611 self.create_write_couplings() 4612 self.create_couplings() 4613 4614 # the makefile 4615 self.create_makeinc() 4616 self.create_param_write() 4617 4618 # The model functions 4619 self.create_model_functions_inc() 4620 self.create_model_functions_def() 4621 4622 # The param_card.dat 4623 self.create_param_card() 4624 4625 4626 # All the standard files 4627 self.copy_standard_file()
4628 4629 ############################################################################ 4630 ## ROUTINE CREATING THE FILES ############################################ 4631 ############################################################################ 4632
4633 - def copy_standard_file(self):
4634 """Copy the standard files for the fortran model.""" 4635 4636 4637 #copy the library files 4638 file_to_link = ['formats.inc','printout.f', \ 4639 'rw_para.f', 'testprog.f'] 4640 4641 for filename in file_to_link: 4642 cp( MG5DIR + '/models/template_files/fortran/' + filename, \ 4643 self.dir_path) 4644 4645 file = open(os.path.join(MG5DIR,\ 4646 'models/template_files/fortran/rw_para.f')).read() 4647 4648 includes=["include \'coupl.inc\'","include \'input.inc\'"] 4649 if self.opt['mp']: 4650 includes.extend(["include \'mp_coupl.inc\'","include \'mp_input.inc\'"]) 4651 # In standalone and madloop we do no use the compiled param card but 4652 # still parse the .dat one so we must load it. 4653 if self.opt['export_format'] in ['madloop','madloop_optimized']: 4654 load_card = 'call LHA_loadcard(param_name,npara,param,value)' 4655 lha_read_filename='lha_read_mp.f' 4656 elif self.opt['export_format'].startswith('standalone') or self.opt['export_format'] in ['madweight']: 4657 load_card = 'call LHA_loadcard(param_name,npara,param,value)' 4658 lha_read_filename='lha_read.f' 4659 else: 4660 load_card = '' 4661 lha_read_filename='lha_read.f' 4662 cp( MG5DIR + '/models/template_files/fortran/' + lha_read_filename, \ 4663 os.path.join(self.dir_path,'lha_read.f')) 4664 4665 file=file%{'includes':'\n '.join(includes), 4666 'load_card':load_card} 4667 writer=open(os.path.join(self.dir_path,'rw_para.f'),'w') 4668 writer.writelines(file) 4669 writer.close() 4670 4671 if self.opt['export_format'] in ['madevent', 'FKS5_default', 'FKS5_optimized']: 4672 cp( MG5DIR + '/models/template_files/fortran/makefile_madevent', 4673 self.dir_path + '/makefile') 4674 if self.opt['export_format'] in ['FKS5_default', 'FKS5_optimized']: 4675 path = pjoin(self.dir_path, 'makefile') 4676 text = open(path).read() 4677 text = text.replace('madevent','aMCatNLO') 4678 open(path, 'w').writelines(text) 4679 elif self.opt['export_format'] in ['standalone', 'standalone_msP','standalone_msF', 4680 'madloop','madloop_optimized', 'standalone_rw', 'madweight']: 4681 cp( MG5DIR + '/models/template_files/fortran/makefile_standalone', 4682 self.dir_path + '/makefile') 4683 else: 4684 raise MadGraph5Error('Unknown format')
4685
4686 - def create_coupl_inc(self):
4687 """ write coupling.inc """ 4688 4689 fsock = self.open('coupl.inc', format='fortran') 4690 if self.opt['mp']: 4691 mp_fsock = self.open('mp_coupl.inc', format='fortran') 4692 mp_fsock_same_name = self.open('mp_coupl_same_name.inc',\ 4693 format='fortran') 4694 4695 # Write header 4696 header = """double precision G 4697 common/strong/ G 4698 4699 double complex gal(2) 4700 common/weak/ gal 4701 4702 """ 4703 if self.model.get('expansion_order'): 4704 header=header+"""double precision MU_R 4705 common/rscale/ MU_R 4706 4707 """ 4708 header = header+"""double precision Nf 4709 parameter(Nf=%d) 4710 """ % self.model.get_nflav() 4711 4712 fsock.writelines(header) 4713 4714 if self.opt['mp']: 4715 header = """%(real_mp_format)s %(mp_prefix)sG 4716 common/MP_strong/ %(mp_prefix)sG 4717 4718 %(complex_mp_format)s %(mp_prefix)sgal(2) 4719 common/MP_weak/ %(mp_prefix)sgal 4720 4721 """ 4722 if self.model.get('expansion_order'): 4723 header=header+"""%(complex_mp_format)s %(mp_prefix)sMU_R 4724 common/MP_rscale/ %(mp_prefix)sMU_R 4725 4726 """ 4727 mp_fsock.writelines(header%{'real_mp_format':self.mp_real_format, 4728 'complex_mp_format':self.mp_complex_format, 4729 'mp_prefix':self.mp_prefix}) 4730 mp_fsock_same_name.writelines(header%{'real_mp_format':self.mp_real_format, 4731 'complex_mp_format':self.mp_complex_format, 4732 'mp_prefix':''}) 4733 4734 # Write the Mass definition/ common block 4735 masses = set() 4736 widths = set() 4737 if self.opt['complex_mass']: 4738 complex_mass = set() 4739 4740 for particle in self.model.get('particles'): 4741 #find masses 4742 one_mass = particle.get('mass') 4743 if one_mass.lower() != 'zero': 4744 masses.add(one_mass) 4745 4746 # find width 4747 one_width = particle.get('width') 4748 if one_width.lower() != 'zero': 4749 widths.add(one_width) 4750 if self.opt['complex_mass'] and one_mass.lower() != 'zero': 4751 complex_mass.add('CMASS_%s' % one_mass) 4752 4753 if masses: 4754 fsock.writelines('double precision '+','.join(masses)+'\n') 4755 fsock.writelines('common/masses/ '+','.join(masses)+'\n\n') 4756 if self.opt['mp']: 4757 mp_fsock_same_name.writelines(self.mp_real_format+' '+\ 4758 ','.join(masses)+'\n') 4759 mp_fsock_same_name.writelines('common/MP_masses/ '+\ 4760 ','.join(masses)+'\n\n') 4761 mp_fsock.writelines(self.mp_real_format+' '+','.join([\ 4762 self.mp_prefix+m for m in masses])+'\n') 4763 mp_fsock.writelines('common/MP_masses/ '+\ 4764 ','.join([self.mp_prefix+m for m in masses])+'\n\n') 4765 4766 if widths: 4767 fsock.writelines('double precision '+','.join(widths)+'\n') 4768 fsock.writelines('common/widths/ '+','.join(widths)+'\n\n') 4769 if self.opt['mp']: 4770 mp_fsock_same_name.writelines(self.mp_real_format+' '+\ 4771 ','.join(widths)+'\n') 4772 mp_fsock_same_name.writelines('common/MP_widths/ '+\ 4773 ','.join(widths)+'\n\n') 4774 mp_fsock.writelines(self.mp_real_format+' '+','.join([\ 4775 self.mp_prefix+w for w in widths])+'\n') 4776 mp_fsock.writelines('common/MP_widths/ '+\ 4777 ','.join([self.mp_prefix+w for w in widths])+'\n\n') 4778 4779 # Write the Couplings 4780 coupling_list = [coupl.name for coupl in self.coups_dep + self.coups_indep] 4781 fsock.writelines('double complex '+', '.join(coupling_list)+'\n') 4782 fsock.writelines('common/couplings/ '+', '.join(coupling_list)+'\n') 4783 if self.opt['mp']: 4784 mp_fsock_same_name.writelines(self.mp_complex_format+' '+\ 4785 ','.join(coupling_list)+'\n') 4786 mp_fsock_same_name.writelines('common/MP_couplings/ '+\ 4787 ','.join(coupling_list)+'\n\n') 4788 mp_fsock.writelines(self.mp_complex_format+' '+','.join([\ 4789 self.mp_prefix+c for c in coupling_list])+'\n') 4790 mp_fsock.writelines('common/MP_couplings/ '+\ 4791 ','.join([self.mp_prefix+c for c in coupling_list])+'\n\n') 4792 4793 # Write complex mass for complex mass scheme (if activated) 4794 if self.opt['complex_mass'] and complex_mass: 4795 fsock.writelines('double complex '+', '.join(complex_mass)+'\n') 4796 fsock.writelines('common/complex_mass/ '+', '.join(complex_mass)+'\n') 4797 if self.opt['mp']: 4798 mp_fsock_same_name.writelines(self.mp_complex_format+' '+\ 4799 ','.join(complex_mass)+'\n') 4800 mp_fsock_same_name.writelines('common/MP_complex_mass/ '+\ 4801 ','.join(complex_mass)+'\n\n') 4802 mp_fsock.writelines(self.mp_complex_format+' '+','.join([\ 4803 self.mp_prefix+cm for cm in complex_mass])+'\n') 4804 mp_fsock.writelines('common/MP_complex_mass/ '+\ 4805 ','.join([self.mp_prefix+cm for cm in complex_mass])+'\n\n')
4806
4807 - def create_write_couplings(self):
4808 """ write the file coupl_write.inc """ 4809 4810 fsock = self.open('coupl_write.inc', format='fortran') 4811 4812 fsock.writelines("""write(*,*) ' Couplings of %s' 4813 write(*,*) ' ---------------------------------' 4814 write(*,*) ' '""" % self.model_name) 4815 def format(coupl): 4816 return 'write(*,2) \'%(name)s = \', %(name)s' % {'name': coupl.name}
4817 4818 # Write the Couplings 4819 lines = [format(coupl) for coupl in self.coups_dep + self.coups_indep] 4820 fsock.writelines('\n'.join(lines)) 4821 4822
4823 - def create_input(self):
4824 """create input.inc containing the definition of the parameters""" 4825 4826 fsock = self.open('input.inc', format='fortran') 4827 if self.opt['mp']: 4828 mp_fsock = self.open('mp_input.inc', format='fortran') 4829 4830 #find mass/ width since they are already define 4831 already_def = set() 4832 for particle in self.model.get('particles'): 4833 already_def.add(particle.get('mass').lower()) 4834 already_def.add(particle.get('width').lower()) 4835 if self.opt['complex_mass']: 4836 already_def.add('cmass_%s' % particle.get('mass').lower()) 4837 4838 is_valid = lambda name: name.lower() not in ['g', 'mu_r', 'zero'] and \ 4839 name.lower() not in already_def 4840 4841 real_parameters = [param.name for param in self.params_dep + 4842 self.params_indep if param.type == 'real' 4843 and is_valid(param.name)] 4844 4845 real_parameters += [param.name for param in self.params_ext 4846 if param.type == 'real'and 4847 is_valid(param.name)] 4848 4849 fsock.writelines('double precision '+','.join(real_parameters)+'\n') 4850 fsock.writelines('common/params_R/ '+','.join(real_parameters)+'\n\n') 4851 if self.opt['mp']: 4852 mp_fsock.writelines(self.mp_real_format+' '+','.join([\ 4853 self.mp_prefix+p for p in real_parameters])+'\n') 4854 mp_fsock.writelines('common/MP_params_R/ '+','.join([\ 4855 self.mp_prefix+p for p in real_parameters])+'\n\n') 4856 4857 complex_parameters = [param.name for param in self.params_dep + 4858 self.params_indep if param.type == 'complex' and 4859 is_valid(param.name)] 4860 4861 if complex_parameters: 4862 fsock.writelines('double complex '+','.join(complex_parameters)+'\n') 4863 fsock.writelines('common/params_C/ '+','.join(complex_parameters)+'\n\n') 4864 if self.opt['mp']: 4865 mp_fsock.writelines(self.mp_complex_format+' '+','.join([\ 4866 self.mp_prefix+p for p in complex_parameters])+'\n') 4867 mp_fsock.writelines('common/MP_params_C/ '+','.join([\ 4868 self.mp_prefix+p for p in complex_parameters])+'\n\n')
4869
4870 - def create_intparam_def(self, dp=True, mp=False):
4871 """ create intparam_definition.inc setting the internal parameters. 4872 Output the double precision and/or the multiple precision parameters 4873 depending on the parameters dp and mp. If mp only, then the file names 4874 get the 'mp_' prefix. 4875 """ 4876 4877 fsock = self.open('%sintparam_definition.inc'% 4878 ('mp_' if mp and not dp else ''), format='fortran') 4879 4880 fsock.write_comments(\ 4881 "Parameters that should not be recomputed event by event.\n") 4882 fsock.writelines("if(readlha) then\n") 4883 if dp: 4884 fsock.writelines("G = 2 * DSQRT(AS*PI) ! for the first init\n") 4885 if mp: 4886 fsock.writelines("MP__G = 2 * SQRT(MP__AS*MP__PI) ! for the first init\n") 4887 for param in self.params_indep: 4888 if param.name == 'ZERO': 4889 continue 4890 if dp: 4891 fsock.writelines("%s = %s\n" % (param.name, 4892 self.p_to_f.parse(param.expr))) 4893 if mp: 4894 fsock.writelines("%s%s = %s\n" % (self.mp_prefix,param.name, 4895 self.mp_p_to_f.parse(param.expr))) 4896 4897 fsock.writelines('endif') 4898 4899 fsock.write_comments('\nParameters that should be recomputed at an event by even basis.\n') 4900 if dp: 4901 fsock.writelines("aS = G**2/4/pi\n") 4902 if mp: 4903 fsock.writelines("MP__aS = MP__G**2/4/MP__PI\n") 4904 for param in self.params_dep: 4905 if dp: 4906 fsock.writelines("%s = %s\n" % (param.name, 4907 self.p_to_f.parse(param.expr))) 4908 elif mp: 4909 fsock.writelines("%s%s = %s\n" % (self.mp_prefix,param.name, 4910 self.mp_p_to_f.parse(param.expr))) 4911 4912 fsock.write_comments("\nDefinition of the EW coupling used in the write out of aqed\n") 4913 if ('aEWM1',) in self.model['parameters']: 4914 if dp: 4915 fsock.writelines(""" gal(1) = 3.5449077018110318 / DSQRT(aEWM1) 4916 gal(2) = 1d0 4917 """) 4918 elif mp: 4919 fsock.writelines(""" %(mp_prefix)sgal(1) = 2 * SQRT(MP__PI/MP__aEWM1) 4920 %(mp_prefix)sgal(2) = 1d0 4921 """ %{'mp_prefix':self.mp_prefix}) 4922 pass 4923 # in Gmu scheme, aEWM1 is not external but Gf is an exteranl variable 4924 elif ('Gf',) in self.model['parameters']: 4925 if dp: 4926 fsock.writelines(""" gal(1) = 2.3784142300054421*MDL_MW*MDL_SW*DSQRT(MDL_Gf) 4927 gal(2) = 1d0 4928 """) 4929 elif mp: 4930 fsock.writelines(""" %(mp_prefix)sgal(1) = 2*MP__MDL_MW*MP__MDL_SW*SQRT(SQRT(2e0_16)*MP__MDL_Gf) 4931 %(mp_prefix)sgal(2) = 1d0 4932 """ %{'mp_prefix':self.mp_prefix}) 4933 pass 4934 else: 4935 if dp: 4936 logger.warning('$RED aEWM1 and Gf not define in MODEL. AQED will not be written correcty in LHE FILE') 4937 fsock.writelines(""" gal(1) = 1d0 4938 gal(2) = 1d0 4939 """) 4940 elif mp: 4941 fsock.writelines(""" %(mp_prefix)sgal(1) = 1e0_16 4942 %(mp_prefix)sgal(2) = 1e0_16 4943 """%{'mp_prefix':self.mp_prefix})
4944 4945
4946 - def create_couplings(self):
4947 """ create couplings.f and all couplingsX.f """ 4948 4949 nb_def_by_file = 25 4950 4951 self.create_couplings_main(nb_def_by_file) 4952 nb_coup_indep = 1 + len(self.coups_indep) // nb_def_by_file 4953 nb_coup_dep = 1 + len(self.coups_dep) // nb_def_by_file 4954 4955 for i in range(nb_coup_indep): 4956 # For the independent couplings, we compute the double and multiple 4957 # precision ones together 4958 data = self.coups_indep[nb_def_by_file * i: 4959 min(len(self.coups_indep), nb_def_by_file * (i+1))] 4960 self.create_couplings_part(i + 1, data, dp=True, mp=self.opt['mp']) 4961 4962 for i in range(nb_coup_dep): 4963 # For the dependent couplings, we compute the double and multiple 4964 # precision ones in separate subroutines. 4965 data = self.coups_dep[nb_def_by_file * i: 4966 min(len(self.coups_dep), nb_def_by_file * (i+1))] 4967 self.create_couplings_part( i + 1 + nb_coup_indep , data, 4968 dp=True,mp=False) 4969 if self.opt['mp']: 4970 self.create_couplings_part( i + 1 + nb_coup_indep , data, 4971 dp=False,mp=True)
4972 4973
4974 - def create_couplings_main(self, nb_def_by_file=25):
4975 """ create couplings.f """ 4976 4977 fsock = self.open('couplings.f', format='fortran') 4978 4979 fsock.writelines("""subroutine coup() 4980 4981 implicit none 4982 double precision PI, ZERO 4983 logical READLHA 4984 parameter (PI=3.141592653589793d0) 4985 parameter (ZERO=0d0)""") 4986 if self.opt['mp']: 4987 fsock.writelines("""%s MP__PI, MP__ZERO 4988 parameter (MP__PI=3.1415926535897932384626433832795e0_16) 4989 parameter (MP__ZERO=0e0_16) 4990 include \'mp_input.inc\' 4991 include \'mp_coupl.inc\' 4992 """%self.mp_real_format) 4993 fsock.writelines("""include \'input.inc\' 4994 include \'coupl.inc\' 4995 READLHA = .true. 4996 include \'intparam_definition.inc\'""") 4997 if self.opt['mp']: 4998 fsock.writelines("""include \'mp_intparam_definition.inc\'\n""") 4999 5000 nb_coup_indep = 1 + len(self.coups_indep) // nb_def_by_file 5001 nb_coup_dep = 1 + len(self.coups_dep) // nb_def_by_file 5002 5003 fsock.writelines('\n'.join(\ 5004 ['call coup%s()' % (i + 1) for i in range(nb_coup_indep)])) 5005 5006 fsock.write_comments('\ncouplings needed to be evaluated points by points\n') 5007 5008 fsock.writelines('\n'.join(\ 5009 ['call coup%s()' % (nb_coup_indep + i + 1) \ 5010 for i in range(nb_coup_dep)])) 5011 if self.opt['mp']: 5012 fsock.writelines('\n'.join(\ 5013 ['call mp_coup%s()' % (nb_coup_indep + i + 1) \ 5014 for i in range(nb_coup_dep)])) 5015 fsock.writelines('''\n return \n end\n''') 5016 5017 fsock.writelines("""subroutine update_as_param() 5018 5019 implicit none 5020 double precision PI, ZERO 5021 logical READLHA 5022 parameter (PI=3.141592653589793d0) 5023 parameter (ZERO=0d0)""") 5024 fsock.writelines("""include \'input.inc\' 5025 include \'coupl.inc\' 5026 READLHA = .false.""") 5027 fsock.writelines(""" 5028 include \'intparam_definition.inc\'\n 5029 """) 5030 5031 nb_coup_indep = 1 + len(self.coups_indep) // nb_def_by_file 5032 nb_coup_dep = 1 + len(self.coups_dep) // nb_def_by_file 5033 5034 fsock.write_comments('\ncouplings needed to be evaluated points by points\n') 5035 5036 fsock.writelines('\n'.join(\ 5037 ['call coup%s()' % (nb_coup_indep + i + 1) \ 5038 for i in range(nb_coup_dep)])) 5039 fsock.writelines('''\n return \n end\n''') 5040 5041 fsock.writelines("""subroutine update_as_param2(mu_r2,as2) 5042 5043 implicit none 5044 double precision PI 5045 parameter (PI=3.141592653589793d0) 5046 double precision mu_r2, as2""") 5047 fsock.writelines("""include \'input.inc\' 5048 include \'coupl.inc\'""") 5049 fsock.writelines(""" 5050 MU_R = mu_r2 5051 G = SQRT(4.0d0*PI*AS2) 5052 AS = as2 5053 5054 CALL UPDATE_AS_PARAM() 5055 """) 5056 fsock.writelines('''\n return \n end\n''') 5057 5058 if self.opt['mp']: 5059 fsock.writelines("""subroutine mp_update_as_param() 5060 5061 implicit none 5062 logical READLHA""") 5063 fsock.writelines("""%s MP__PI, MP__ZERO 5064 parameter (MP__PI=3.1415926535897932384626433832795e0_16) 5065 parameter (MP__ZERO=0e0_16) 5066 include \'mp_input.inc\' 5067 include \'mp_coupl.inc\' 5068 """%self.mp_real_format) 5069 fsock.writelines("""include \'input.inc\' 5070 include \'coupl.inc\' 5071 include \'actualize_mp_ext_params.inc\' 5072 READLHA = .false. 5073 include \'mp_intparam_definition.inc\'\n 5074 """) 5075 5076 nb_coup_indep = 1 + len(self.coups_indep) // nb_def_by_file 5077 nb_coup_dep = 1 + len(self.coups_dep) // nb_def_by_file 5078 5079 fsock.write_comments('\ncouplings needed to be evaluated points by points\n') 5080 5081 fsock.writelines('\n'.join(\ 5082 ['call mp_coup%s()' % (nb_coup_indep + i + 1) \ 5083 for i in range(nb_coup_dep)])) 5084 fsock.writelines('''\n return \n end\n''')
5085
5086 - def create_couplings_part(self, nb_file, data, dp=True, mp=False):
5087 """ create couplings[nb_file].f containing information coming from data. 5088 Outputs the computation of the double precision and/or the multiple 5089 precision couplings depending on the parameters dp and mp. 5090 If mp is True and dp is False, then the prefix 'MP_' is appended to the 5091 filename and subroutine name. 5092 """ 5093 5094 fsock = self.open('%scouplings%s.f' %('mp_' if mp and not dp else '', 5095 nb_file), format='fortran') 5096 fsock.writelines("""subroutine %scoup%s() 5097 5098 implicit none"""%('mp_' if mp and not dp else '',nb_file)) 5099 if dp: 5100 fsock.writelines(""" 5101 double precision PI, ZERO 5102 parameter (PI=3.141592653589793d0) 5103 parameter (ZERO=0d0) 5104 include 'input.inc' 5105 include 'coupl.inc'""") 5106 if mp: 5107 fsock.writelines("""%s MP__PI, MP__ZERO 5108 parameter (MP__PI=3.1415926535897932384626433832795e0_16) 5109 parameter (MP__ZERO=0e0_16) 5110 include \'mp_input.inc\' 5111 include \'mp_coupl.inc\' 5112 """%self.mp_real_format) 5113 fsock.writelines(""" 5114 include 'model_functions.inc'""") 5115 for coupling in data: 5116 if dp: 5117 fsock.writelines('%s = %s' % (coupling.name, 5118 self.p_to_f.parse(coupling.expr))) 5119 if mp: 5120 fsock.writelines('%s%s = %s' % (self.mp_prefix,coupling.name, 5121 self.mp_p_to_f.parse(coupling.expr))) 5122 fsock.writelines('end')
5123
5124 - def create_model_functions_inc(self):
5125 """ Create model_functions.inc which contains the various declarations 5126 of auxiliary functions which might be used in the couplings expressions 5127 """ 5128 5129 fsock = self.open('model_functions.inc', format='fortran') 5130 fsock.writelines("""double complex cond 5131 double complex condif 5132 double complex reglog 5133 double complex arg""") 5134 if self.opt['mp']: 5135 fsock.writelines("""%(complex_mp_format)s mp_cond 5136 %(complex_mp_format)s mp_condif 5137 %(complex_mp_format)s mp_reglog 5138 %(complex_mp_format)s mp_arg"""\ 5139 %{'complex_mp_format':self.mp_complex_format})
5140
5141 - def create_model_functions_def(self):
5142 """ Create model_functions.f which contains the various definitions 5143 of auxiliary functions which might be used in the couplings expressions 5144 Add the functions.f functions for formfactors support 5145 """ 5146 5147 fsock = self.open('model_functions.f', format='fortran') 5148 fsock.writelines("""double complex function cond(condition,truecase,falsecase) 5149 implicit none 5150 double complex condition,truecase,falsecase 5151 if(condition.eq.(0.0d0,0.0d0)) then 5152 cond=truecase 5153 else 5154 cond=falsecase 5155 endif 5156 end 5157 5158 double complex function condif(condition,truecase,falsecase) 5159 implicit none 5160 logical condition 5161 double complex truecase,falsecase 5162 if(condition) then 5163 condif=truecase 5164 else 5165 condif=falsecase 5166 endif 5167 end 5168 5169 double complex function reglog(arg) 5170 implicit none 5171 double complex arg 5172 if(arg.eq.(0.0d0,0.0d0)) then 5173 reglog=(0.0d0,0.0d0) 5174 else 5175 reglog=log(arg) 5176 endif 5177 end 5178 5179 double complex function arg(comnum) 5180 implicit none 5181 double complex comnum 5182 double complex iim 5183 iim = (0.0d0,1.0d0) 5184 if(comnum.eq.(0.0d0,0.0d0)) then 5185 arg=(0.0d0,0.0d0) 5186 else 5187 arg=log(comnum/abs(comnum))/iim 5188 endif 5189 end""") 5190 if self.opt['mp']: 5191 fsock.writelines(""" 5192 5193 %(complex_mp_format)s function mp_cond(condition,truecase,falsecase) 5194 implicit none 5195 %(complex_mp_format)s condition,truecase,falsecase 5196 if(condition.eq.(0.0e0_16,0.0e0_16)) then 5197 mp_cond=truecase 5198 else 5199 mp_cond=falsecase 5200 endif 5201 end 5202 5203 %(complex_mp_format)s function mp_condif(condition,truecase,falsecase) 5204 implicit none 5205 logical condition 5206 %(complex_mp_format)s truecase,falsecase 5207 if(condition) then 5208 mp_condif=truecase 5209 else 5210 mp_condif=falsecase 5211 endif 5212 end 5213 5214 %(complex_mp_format)s function mp_reglog(arg) 5215 implicit none 5216 %(complex_mp_format)s arg 5217 if(arg.eq.(0.0e0_16,0.0e0_16)) then 5218 mp_reglog=(0.0e0_16,0.0e0_16) 5219 else 5220 mp_reglog=log(arg) 5221 endif 5222 end 5223 5224 %(complex_mp_format)s function mp_arg(comnum) 5225 implicit none 5226 %(complex_mp_format)s comnum 5227 %(complex_mp_format)s imm 5228 imm = (0.0e0_16,1.0e0_16) 5229 if(comnum.eq.(0.0e0_16,0.0e0_16)) then 5230 mp_arg=(0.0e0_16,0.0e0_16) 5231 else 5232 mp_arg=log(comnum/abs(comnum))/imm 5233 endif 5234 end"""%{'complex_mp_format':self.mp_complex_format}) 5235 5236 #check for the file functions.f 5237 model_path = self.model.get('modelpath') 5238 if os.path.exists(pjoin(model_path,'Fortran','functions.f')): 5239 fsock.write_comment_line(' USER DEFINE FUNCTIONS ') 5240 input = pjoin(model_path,'Fortran','functions.f') 5241 file.writelines(fsock, open(input).read()) 5242 fsock.write_comment_line(' END USER DEFINE FUNCTIONS ')
5243
5244 - def create_makeinc(self):
5245 """create makeinc.inc containing the file to compile """ 5246 5247 fsock = self.open('makeinc.inc', comment='#') 5248 text = 'MODEL = couplings.o lha_read.o printout.o rw_para.o' 5249 text += ' model_functions.o ' 5250 5251 nb_coup_indep = 1 + len(self.coups_dep) // 25 5252 nb_coup_dep = 1 + len(self.coups_indep) // 25 5253 couplings_files=['couplings%s.o' % (i+1) \ 5254 for i in range(nb_coup_dep + nb_coup_indep) ] 5255 if self.opt['mp']: 5256 couplings_files+=['mp_couplings%s.o' % (i+1) for i in \ 5257 range(nb_coup_dep,nb_coup_dep + nb_coup_indep) ] 5258 text += ' '.join(couplings_files) 5259 fsock.writelines(text)
5260
5261 - def create_param_write(self):
5262 """ create param_write """ 5263 5264 fsock = self.open('param_write.inc', format='fortran') 5265 5266 fsock.writelines("""write(*,*) ' External Params' 5267 write(*,*) ' ---------------------------------' 5268 write(*,*) ' '""") 5269 def format(name): 5270 return 'write(*,*) \'%(name)s = \', %(name)s' % {'name': name}
5271 5272 # Write the external parameter 5273 lines = [format(param.name) for param in self.params_ext] 5274 fsock.writelines('\n'.join(lines)) 5275 5276 fsock.writelines("""write(*,*) ' Internal Params' 5277 write(*,*) ' ---------------------------------' 5278 write(*,*) ' '""") 5279 lines = [format(data.name) for data in self.params_indep 5280 if data.name != 'ZERO'] 5281 fsock.writelines('\n'.join(lines)) 5282 fsock.writelines("""write(*,*) ' Internal Params evaluated point by point' 5283 write(*,*) ' ----------------------------------------' 5284 write(*,*) ' '""") 5285 lines = [format(data.name) for data in self.params_dep] 5286 5287 fsock.writelines('\n'.join(lines)) 5288 5289 5290
5291 - def create_ident_card(self):
5292 """ create the ident_card.dat """ 5293 5294 def format(parameter): 5295 """return the line for the ident_card corresponding to this parameter""" 5296 colum = [parameter.lhablock.lower()] + \ 5297 [str(value) for value in parameter.lhacode] + \ 5298 [parameter.name] 5299 if not parameter.name: 5300 return '' 5301 return ' '.join(colum)+'\n'
5302 5303 fsock = self.open('ident_card.dat') 5304 5305 external_param = [format(param) for param in self.params_ext] 5306 fsock.writelines('\n'.join(external_param)) 5307
5308 - def create_actualize_mp_ext_param_inc(self):
5309 """ create the actualize_mp_ext_params.inc code """ 5310 5311 # In principle one should actualize all external, but for now, it is 5312 # hardcoded that only AS and MU_R can by dynamically changed by the user 5313 # so that we only update those ones. 5314 # Of course, to be on the safe side, one could decide to update all 5315 # external parameters. 5316 update_params_list=[p for p in self.params_ext if p.name in 5317 self.PS_dependent_key] 5318 5319 res_strings = ["%(mp_prefix)s%(name)s=%(name)s"\ 5320 %{'mp_prefix':self.mp_prefix,'name':param.name}\ 5321 for param in update_params_list] 5322 # When read_lha is false, it is G which is taken in input and not AS, so 5323 # this is what should be reset here too. 5324 if 'aS' in [param.name for param in update_params_list]: 5325 res_strings.append("%(mp_prefix)sG=G"%{'mp_prefix':self.mp_prefix}) 5326 5327 fsock = self.open('actualize_mp_ext_params.inc', format='fortran') 5328 fsock.writelines('\n'.join(res_strings))
5329
5330 - def create_param_read(self):
5331 """create param_read""" 5332 5333 if self.opt['export_format'] in ['madevent', 'FKS5_default', 'FKS5_optimized']: 5334 fsock = self.open('param_read.inc', format='fortran') 5335 fsock.writelines(' include \'../param_card.inc\'') 5336 return 5337 5338 def format_line(parameter): 5339 """return the line for the ident_card corresponding to this 5340 parameter""" 5341 template = \ 5342 """ call LHA_get_real(npara,param,value,'%(name)s',%(name)s,%(value)s)""" \ 5343 % {'name': parameter.name, 5344 'value': self.p_to_f.parse(str(parameter.value.real))} 5345 if self.opt['mp']: 5346 template = template+ \ 5347 ("\n call MP_LHA_get_real(npara,param,value,'%(name)s',"+ 5348 "%(mp_prefix)s%(name)s,%(value)s)") \ 5349 % {'name': parameter.name,'mp_prefix': self.mp_prefix, 5350 'value': self.mp_p_to_f.parse(str(parameter.value.real))} 5351 return template 5352 5353 fsock = self.open('param_read.inc', format='fortran') 5354 res_strings = [format_line(param) \ 5355 for param in self.params_ext] 5356 5357 # Correct width sign for Majorana particles (where the width 5358 # and mass need to have the same sign) 5359 for particle in self.model.get('particles'): 5360 if particle.is_fermion() and particle.get('self_antipart') and \ 5361 particle.get('width').lower() != 'zero': 5362 5363 res_strings.append('%(width)s = sign(%(width)s,%(mass)s)' % \ 5364 {'width': particle.get('width'), 'mass': particle.get('mass')}) 5365 if self.opt['mp']: 5366 res_strings.append(\ 5367 ('%(mp_pref)s%(width)s = sign(%(mp_pref)s%(width)s,'+\ 5368 '%(mp_pref)s%(mass)s)')%{'width': particle.get('width'),\ 5369 'mass': particle.get('mass'),'mp_pref':self.mp_prefix}) 5370 5371 fsock.writelines('\n'.join(res_strings)) 5372
5373 - def create_param_card(self):
5374 """ create the param_card.dat """ 5375 5376 #1. Check if a default param_card is present: 5377 done = False 5378 if hasattr(self.model, 'restrict_card') and isinstance(self.model.restrict_card, str): 5379 restrict_name = os.path.basename(self.model.restrict_card)[9:-4] 5380 model_path = self.model.get('modelpath') 5381 if os.path.exists(pjoin(model_path,'paramcard_%s.dat' % restrict_name)): 5382 done = True 5383 files.cp(pjoin(model_path,'paramcard_%s.dat' % restrict_name), 5384 pjoin(self.dir_path, 'param_card.dat')) 5385 if not done: 5386 out_path = pjoin(self.dir_path, 'param_card.dat') 5387 param_writer.ParamCardWriter(self.model, out_path) 5388 5389 out_path2 = None 5390 if hasattr(self.model, 'rule_card'): 5391 out_path2 = pjoin(self.dir_path, 'param_card_rule.dat') 5392 self.model.rule_card.write_file(out_path2) 5393 5394 # IF MSSM convert the card to SLAH1 5395 if self.model_name == 'mssm' or self.model_name.startswith('mssm-'): 5396 import models.check_param_card as translator 5397 5398 # Check the format of the param_card for Pythia and make it correct 5399 if out_path2: 5400 translator.make_valid_param_card(out_path, out_path2) 5401 translator.convert_to_slha1(out_path)
5402
5403 -def ExportV4Factory(cmd, noclean, output_type='default'):
5404 """ Determine which Export_v4 class is required. cmd is the command 5405 interface containing all potential usefull information. 5406 The output_type argument specifies from which context the output 5407 is called. It is 'madloop' for MadLoop5, 'amcatnlo' for FKS5 output 5408 and 'default' for tree-level outputs.""" 5409 5410 group_subprocesses = cmd.options['group_subprocesses'] 5411 5412 # First treat the MadLoop5 standalone case 5413 if output_type=='madloop': 5414 import madgraph.loop.loop_exporters as loop_exporters 5415 if os.path.isdir(os.path.join(cmd._mgme_dir, 'Template/loop_material')): 5416 ExporterClass=None 5417 options = {'clean': not noclean, 5418 'complex_mass':cmd.options['complex_mass_scheme'], 5419 'export_format':'madloop', 5420 'mp':True, 5421 'loop_dir': os.path.join(cmd._mgme_dir, 'Template/loop_material'), 5422 'cuttools_dir': cmd._cuttools_dir, 5423 'iregi_dir':cmd._iregi_dir, 5424 'pjfry_dir':cmd.options["pjfry"], 5425 'golem_dir':cmd.options["golem"], 5426 'fortran_compiler':cmd.options['fortran_compiler'], 5427 'output_dependencies':cmd.options['output_dependencies']} 5428 5429 if not cmd.options['loop_optimized_output']: 5430 ExporterClass=loop_exporters.LoopProcessExporterFortranSA 5431 else: 5432 if all([amp['process']['has_born'] for amp in cmd._curr_amps]): 5433 ExporterClass=loop_exporters.LoopProcessOptimizedExporterFortranSA 5434 options['export_format'] = 'madloop_optimized' 5435 else: 5436 logger.warning('ML5 can only exploit the optimized output for '+\ 5437 ' processes with born diagrams. The optimization '+\ 5438 ' option is therefore turned off for this process.') 5439 ExporterClass=loop_exporters.LoopProcessExporterFortranSA 5440 options['export_format'] = 'madloop_default' 5441 return ExporterClass(cmd._mgme_dir, cmd._export_dir, options) 5442 else: 5443 raise MadGraph5Error('MG5_aMC cannot find the \'loop_material\' directory'+\ 5444 ' in %s'%str(cmd._mgme_dir)) 5445 5446 # Then treat the aMC@NLO output 5447 elif output_type=='amcatnlo': 5448 import madgraph.iolibs.export_fks as export_fks 5449 ExporterClass=None 5450 options = {'clean': not noclean, 5451 'complex_mass':cmd.options['complex_mass_scheme'], 5452 'export_format':'madloop', 5453 #use MP for HELAS only if there are virtual amps 5454 'mp':len(cmd._fks_multi_proc.get_virt_amplitudes()) > 0, 5455 'loop_dir': os.path.join(cmd._mgme_dir,'Template','loop_material'), 5456 'cuttools_dir': cmd._cuttools_dir, 5457 'iregi_dir':cmd._iregi_dir, 5458 'pjfry_dir':cmd.options["pjfry"], 5459 'golem_dir':cmd.options["golem"], 5460 'fortran_compiler':cmd.options['fortran_compiler'], 5461 'output_dependencies':cmd.options['output_dependencies']} 5462 if not cmd.options['loop_optimized_output']: 5463 logger.info("Writing out the aMC@NLO code") 5464 ExporterClass = export_fks.ProcessExporterFortranFKS 5465 options['export_format']='FKS5_default' 5466 else: 5467 logger.info("Writing out the aMC@NLO code, using optimized Loops") 5468 ExporterClass = export_fks.ProcessOptimizedExporterFortranFKS 5469 options['export_format']='FKS5_optimized' 5470 return ExporterClass(cmd._mgme_dir, cmd._export_dir, options) 5471 5472 # Then the default tree-level output 5473 elif output_type=='default': 5474 #check if we need to group processes 5475 if cmd.options['group_subprocesses'] == 'Auto': 5476 if cmd._curr_amps[0].get_ninitial() == 2: 5477 group_subprocesses = True 5478 else: 5479 group_subprocesses = False 5480 5481 assert group_subprocesses in [True, False] 5482 5483 opt = {'clean': not noclean, 5484 'complex_mass': cmd.options['complex_mass_scheme'], 5485 'export_format':cmd._export_format, 5486 'mp': False, 5487 'sa_symmetry':False, 5488 'model': cmd._curr_model.get('name') } 5489 5490 format = cmd._export_format #shortcut 5491 5492 if format in ['standalone_msP', 'standalone_msF', 'standalone_rw']: 5493 opt['sa_symmetry'] = True 5494 5495 if format == 'matrix' or format.startswith('standalone'): 5496 return ProcessExporterFortranSA(cmd._mgme_dir, cmd._export_dir, opt, 5497 format=format) 5498 5499 elif format in ['madevent'] and group_subprocesses: 5500 return ProcessExporterFortranMEGroup(cmd._mgme_dir, cmd._export_dir, 5501 opt) 5502 elif format in ['madevent']: 5503 return ProcessExporterFortranME(cmd._mgme_dir, cmd._export_dir,opt) 5504 elif cmd._export_format in ['madweight'] and group_subprocesses: 5505 5506 return ProcessExporterFortranMWGroup(cmd._mgme_dir, cmd._export_dir, 5507 opt) 5508 elif cmd._export_format in ['madweight']: 5509 return ProcessExporterFortranMW(cmd._mgme_dir, cmd._export_dir, opt) 5510 else: 5511 raise Exception, 'Wrong export_v4 format' 5512 else: 5513 raise MadGraph5Error, 'Output type %s not reckognized in ExportV4Factory.'
5514 5515 5516 5517 5518 #=============================================================================== 5519 # ProcessExporterFortranMWGroup 5520 #===============================================================================
5521 -class ProcessExporterFortranMWGroup(ProcessExporterFortranMW):
5522 """Class to take care of exporting a set of matrix elements to 5523 MadEvent subprocess group format.""" 5524 5525 matrix_file = "matrix_madweight_group_v4.inc" 5526 5527 #=========================================================================== 5528 # generate_subprocess_directory_v4 5529 #===========================================================================
5530 - def generate_subprocess_directory_v4(self, subproc_group, 5531 fortran_model, 5532 group_number):
5533 """Generate the Pn directory for a subprocess group in MadEvent, 5534 including the necessary matrix_N.f files, configs.inc and various 5535 other helper files""" 5536 5537 if not isinstance(subproc_group, group_subprocs.SubProcessGroup): 5538 raise base_objects.PhysicsObject.PhysicsObjectError,\ 5539 "subproc_group object not SubProcessGroup" 5540 5541 if not self.model: 5542 self.model = subproc_group.get('matrix_elements')[0].\ 5543 get('processes')[0].get('model') 5544 5545 pathdir = os.path.join(self.dir_path, 'SubProcesses') 5546 5547 # Create the directory PN in the specified path 5548 subprocdir = "P%d_%s" % (subproc_group.get('number'), 5549 subproc_group.get('name')) 5550 try: 5551 os.mkdir(pjoin(pathdir, subprocdir)) 5552 except os.error as error: 5553 logger.warning(error.strerror + " " + subprocdir) 5554 5555 5556 logger.info('Creating files in directory %s' % subprocdir) 5557 Ppath = pjoin(pathdir, subprocdir) 5558 5559 # Create the matrix.f files, auto_dsig.f files and all inc files 5560 # for all subprocesses in the group 5561 5562 maxamps = 0 5563 maxflows = 0 5564 tot_calls = 0 5565 5566 matrix_elements = subproc_group.get('matrix_elements') 5567 5568 for ime, matrix_element in \ 5569 enumerate(matrix_elements): 5570 filename = pjoin(Ppath, 'matrix%d.f' % (ime+1)) 5571 calls, ncolor = \ 5572 self.write_matrix_element_v4(writers.FortranWriter(filename), 5573 matrix_element, 5574 fortran_model, 5575 str(ime+1), 5576 subproc_group.get('diagram_maps')[\ 5577 ime]) 5578 5579 filename = pjoin(Ppath, 'auto_dsig%d.f' % (ime+1)) 5580 self.write_auto_dsig_file(writers.FortranWriter(filename), 5581 matrix_element, 5582 str(ime+1)) 5583 5584 # Keep track of needed quantities 5585 tot_calls += int(calls) 5586 maxflows = max(maxflows, ncolor) 5587 maxamps = max(maxamps, len(matrix_element.get('diagrams'))) 5588 5589 # Draw diagrams 5590 filename = pjoin(Ppath, "matrix%d.ps" % (ime+1)) 5591 plot = draw.MultiEpsDiagramDrawer(matrix_element.get('base_amplitude').\ 5592 get('diagrams'), 5593 filename, 5594 model = \ 5595 matrix_element.get('processes')[0].\ 5596 get('model'), 5597 amplitude=True) 5598 logger.info("Generating Feynman diagrams for " + \ 5599 matrix_element.get('processes')[0].nice_string()) 5600 plot.draw() 5601 5602 # Extract number of external particles 5603 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial() 5604 5605 # Generate a list of diagrams corresponding to each configuration 5606 # [[d1, d2, ...,dn],...] where 1,2,...,n is the subprocess number 5607 # If a subprocess has no diagrams for this config, the number is 0 5608 5609 subproc_diagrams_for_config = subproc_group.get('diagrams_for_configs') 5610 5611 filename = pjoin(Ppath, 'auto_dsig.f') 5612 self.write_super_auto_dsig_file(writers.FortranWriter(filename), 5613 subproc_group) 5614 5615 filename = pjoin(Ppath,'configs.inc') 5616 nconfigs, s_and_t_channels = self.write_configs_file(\ 5617 writers.FortranWriter(filename), 5618 subproc_group, 5619 subproc_diagrams_for_config) 5620 5621 filename = pjoin(Ppath, 'leshouche.inc') 5622 self.write_leshouche_file(writers.FortranWriter(filename), 5623 subproc_group) 5624 5625 filename = pjoin(Ppath, 'phasespace.inc') 5626 self.write_phasespace_file(writers.FortranWriter(filename), 5627 nconfigs) 5628 5629 5630 filename = pjoin(Ppath, 'maxamps.inc') 5631 self.write_maxamps_file(writers.FortranWriter(filename), 5632 maxamps, 5633 maxflows, 5634 max([len(me.get('processes')) for me in \ 5635 matrix_elements]), 5636 len(matrix_elements)) 5637 5638 filename = pjoin(Ppath, 'mirrorprocs.inc') 5639 self.write_mirrorprocs(writers.FortranWriter(filename), 5640 subproc_group) 5641 5642 filename = pjoin(Ppath, 'nexternal.inc') 5643 self.write_nexternal_file(writers.FortranWriter(filename), 5644 nexternal, ninitial) 5645 5646 filename = pjoin(Ppath, 'pmass.inc') 5647 self.write_pmass_file(writers.FortranWriter(filename), 5648 matrix_element) 5649 5650 filename = pjoin(Ppath, 'props.inc') 5651 self.write_props_file(writers.FortranWriter(filename), 5652 matrix_element, 5653 s_and_t_channels) 5654 5655 # filename = pjoin(Ppath, 'processes.dat') 5656 # files.write_to_file(filename, 5657 # self.write_processes_file, 5658 # subproc_group) 5659 5660 # Generate jpgs -> pass in make_html 5661 #os.system(os.path.join('..', '..', 'bin', 'gen_jpeg-pl')) 5662 5663 linkfiles = ['driver.f', 'cuts.f', 'initialization.f','gen_ps.f', 'makefile', 'coupl.inc','madweight_param.inc', 'run.inc', 'setscales.f'] 5664 5665 for file in linkfiles: 5666 ln('../%s' % file, cwd=Ppath) 5667 5668 ln('nexternal.inc', '../../Source', cwd=Ppath, log=False) 5669 ln('leshouche.inc', '../../Source', cwd=Ppath, log=False) 5670 ln('maxamps.inc', '../../Source', cwd=Ppath, log=False) 5671 ln('../../Source/maxparticles.inc', '.', log=True, cwd=Ppath) 5672 ln('../../Source/maxparticles.inc', '.', name='genps.inc', log=True, cwd=Ppath) 5673 ln('phasespace.inc', '../', log=True, cwd=Ppath) 5674 if not tot_calls: 5675 tot_calls = 0 5676 return tot_calls
5677 5678 #=========================================================================== 5679 # write_super_auto_dsig_file 5680 #===========================================================================
5681 - def write_super_auto_dsig_file(self, writer, subproc_group):
5682 """Write the auto_dsig.f file selecting between the subprocesses 5683 in subprocess group mode""" 5684 5685 replace_dict = {} 5686 5687 # Extract version number and date from VERSION file 5688 info_lines = self.get_mg5_info_lines() 5689 replace_dict['info_lines'] = info_lines 5690 5691 matrix_elements = subproc_group.get('matrix_elements') 5692 5693 # Extract process info lines 5694 process_lines = '\n'.join([self.get_process_info_lines(me) for me in \ 5695 matrix_elements]) 5696 replace_dict['process_lines'] = process_lines 5697 5698 nexternal, ninitial = matrix_elements[0].get_nexternal_ninitial() 5699 replace_dict['nexternal'] = nexternal 5700 5701 replace_dict['nsprocs'] = 2*len(matrix_elements) 5702 5703 # Generate dsig definition line 5704 dsig_def_line = "DOUBLE PRECISION " + \ 5705 ",".join(["DSIG%d" % (iproc + 1) for iproc in \ 5706 range(len(matrix_elements))]) 5707 replace_dict["dsig_def_line"] = dsig_def_line 5708 5709 # Generate dsig process lines 5710 call_dsig_proc_lines = [] 5711 for iproc in range(len(matrix_elements)): 5712 call_dsig_proc_lines.append(\ 5713 "IF(IPROC.EQ.%(num)d) DSIGPROC=DSIG%(num)d(P1,WGT,IMODE) ! %(proc)s" % \ 5714 {"num": iproc + 1, 5715 "proc": matrix_elements[iproc].get('processes')[0].base_string()}) 5716 replace_dict['call_dsig_proc_lines'] = "\n".join(call_dsig_proc_lines) 5717 5718 file = open(os.path.join(_file_path, \ 5719 'iolibs/template_files/super_auto_dsig_mw_group_v4.inc')).read() 5720 file = file % replace_dict 5721 5722 # Write the file 5723 writer.writelines(file)
5724 5725 #=========================================================================== 5726 # write_mirrorprocs 5727 #===========================================================================
5728 - def write_mirrorprocs(self, writer, subproc_group):
5729 """Write the mirrorprocs.inc file determining which processes have 5730 IS mirror process in subprocess group mode.""" 5731 5732 lines = [] 5733 bool_dict = {True: '.true.', False: '.false.'} 5734 matrix_elements = subproc_group.get('matrix_elements') 5735 lines.append("DATA (MIRRORPROCS(I),I=1,%d)/%s/" % \ 5736 (len(matrix_elements), 5737 ",".join([bool_dict[me.get('has_mirror_process')] for \ 5738 me in matrix_elements]))) 5739 # Write the file 5740 writer.writelines(lines)
5741 5742 #=========================================================================== 5743 # write_configs_file 5744 #===========================================================================
5745 - def write_configs_file(self, writer, subproc_group, diagrams_for_config):
5746 """Write the configs.inc file with topology information for a 5747 subprocess group. Use the first subprocess with a diagram for each 5748 configuration.""" 5749 5750 matrix_elements = subproc_group.get('matrix_elements') 5751 model = matrix_elements[0].get('processes')[0].get('model') 5752 5753 diagrams = [] 5754 config_numbers = [] 5755 for iconfig, config in enumerate(diagrams_for_config): 5756 # Check if any diagrams correspond to this config 5757 if set(config) == set([0]): 5758 continue 5759 subproc_diags = [] 5760 for s,d in enumerate(config): 5761 if d: 5762 subproc_diags.append(matrix_elements[s].\ 5763 get('diagrams')[d-1]) 5764 else: 5765 subproc_diags.append(None) 5766 diagrams.append(subproc_diags) 5767 config_numbers.append(iconfig + 1) 5768 5769 # Extract number of external particles 5770 (nexternal, ninitial) = subproc_group.get_nexternal_ninitial() 5771 5772 return len(diagrams), \ 5773 self.write_configs_file_from_diagrams(writer, diagrams, 5774 config_numbers, 5775 nexternal, ninitial, 5776 matrix_elements[0],model)
5777 5778 #=========================================================================== 5779 # write_run_configs_file 5780 #===========================================================================
5781 - def write_run_config_file(self, writer):
5782 """Write the run_configs.inc file for MadEvent""" 5783 5784 path = os.path.join(_file_path,'iolibs','template_files','madweight_run_config.inc') 5785 text = open(path).read() % {'chanperjob':'2'} 5786 writer.write(text) 5787 return True
5788 5789 5790 #=========================================================================== 5791 # write_leshouche_file 5792 #===========================================================================
5793 - def write_leshouche_file(self, writer, subproc_group):
5794 """Write the leshouche.inc file for MG4""" 5795 5796 all_lines = [] 5797 5798 for iproc, matrix_element in \ 5799 enumerate(subproc_group.get('matrix_elements')): 5800 all_lines.extend(self.get_leshouche_lines(matrix_element, 5801 iproc)) 5802 5803 # Write the file 5804 writer.writelines(all_lines) 5805 5806 return True
5807