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 double precision MU_R 4703 common/rscale/ MU_R 4704 4705 """ 4706 4707 header = header+"""double precision Nf 4708 parameter(Nf=%d) 4709 """ % self.model.get_nflav() 4710 4711 fsock.writelines(header) 4712 4713 if self.opt['mp']: 4714 header = """%(real_mp_format)s %(mp_prefix)sG 4715 common/MP_strong/ %(mp_prefix)sG 4716 4717 %(complex_mp_format)s %(mp_prefix)sgal(2) 4718 common/MP_weak/ %(mp_prefix)sgal 4719 4720 %(complex_mp_format)s %(mp_prefix)sMU_R 4721 common/MP_rscale/ %(mp_prefix)sMU_R 4722 """ 4723 4724 mp_fsock.writelines(header%{'real_mp_format':self.mp_real_format, 4725 'complex_mp_format':self.mp_complex_format, 4726 'mp_prefix':self.mp_prefix}) 4727 mp_fsock_same_name.writelines(header%{'real_mp_format':self.mp_real_format, 4728 'complex_mp_format':self.mp_complex_format, 4729 'mp_prefix':''}) 4730 4731 # Write the Mass definition/ common block 4732 masses = set() 4733 widths = set() 4734 if self.opt['complex_mass']: 4735 complex_mass = set() 4736 4737 for particle in self.model.get('particles'): 4738 #find masses 4739 one_mass = particle.get('mass') 4740 if one_mass.lower() != 'zero': 4741 masses.add(one_mass) 4742 4743 # find width 4744 one_width = particle.get('width') 4745 if one_width.lower() != 'zero': 4746 widths.add(one_width) 4747 if self.opt['complex_mass'] and one_mass.lower() != 'zero': 4748 complex_mass.add('CMASS_%s' % one_mass) 4749 4750 if masses: 4751 fsock.writelines('double precision '+','.join(masses)+'\n') 4752 fsock.writelines('common/masses/ '+','.join(masses)+'\n\n') 4753 if self.opt['mp']: 4754 mp_fsock_same_name.writelines(self.mp_real_format+' '+\ 4755 ','.join(masses)+'\n') 4756 mp_fsock_same_name.writelines('common/MP_masses/ '+\ 4757 ','.join(masses)+'\n\n') 4758 mp_fsock.writelines(self.mp_real_format+' '+','.join([\ 4759 self.mp_prefix+m for m in masses])+'\n') 4760 mp_fsock.writelines('common/MP_masses/ '+\ 4761 ','.join([self.mp_prefix+m for m in masses])+'\n\n') 4762 4763 if widths: 4764 fsock.writelines('double precision '+','.join(widths)+'\n') 4765 fsock.writelines('common/widths/ '+','.join(widths)+'\n\n') 4766 if self.opt['mp']: 4767 mp_fsock_same_name.writelines(self.mp_real_format+' '+\ 4768 ','.join(widths)+'\n') 4769 mp_fsock_same_name.writelines('common/MP_widths/ '+\ 4770 ','.join(widths)+'\n\n') 4771 mp_fsock.writelines(self.mp_real_format+' '+','.join([\ 4772 self.mp_prefix+w for w in widths])+'\n') 4773 mp_fsock.writelines('common/MP_widths/ '+\ 4774 ','.join([self.mp_prefix+w for w in widths])+'\n\n') 4775 4776 # Write the Couplings 4777 coupling_list = [coupl.name for coupl in self.coups_dep + self.coups_indep] 4778 fsock.writelines('double complex '+', '.join(coupling_list)+'\n') 4779 fsock.writelines('common/couplings/ '+', '.join(coupling_list)+'\n') 4780 if self.opt['mp']: 4781 mp_fsock_same_name.writelines(self.mp_complex_format+' '+\ 4782 ','.join(coupling_list)+'\n') 4783 mp_fsock_same_name.writelines('common/MP_couplings/ '+\ 4784 ','.join(coupling_list)+'\n\n') 4785 mp_fsock.writelines(self.mp_complex_format+' '+','.join([\ 4786 self.mp_prefix+c for c in coupling_list])+'\n') 4787 mp_fsock.writelines('common/MP_couplings/ '+\ 4788 ','.join([self.mp_prefix+c for c in coupling_list])+'\n\n') 4789 4790 # Write complex mass for complex mass scheme (if activated) 4791 if self.opt['complex_mass'] and complex_mass: 4792 fsock.writelines('double complex '+', '.join(complex_mass)+'\n') 4793 fsock.writelines('common/complex_mass/ '+', '.join(complex_mass)+'\n') 4794 if self.opt['mp']: 4795 mp_fsock_same_name.writelines(self.mp_complex_format+' '+\ 4796 ','.join(complex_mass)+'\n') 4797 mp_fsock_same_name.writelines('common/MP_complex_mass/ '+\ 4798 ','.join(complex_mass)+'\n\n') 4799 mp_fsock.writelines(self.mp_complex_format+' '+','.join([\ 4800 self.mp_prefix+cm for cm in complex_mass])+'\n') 4801 mp_fsock.writelines('common/MP_complex_mass/ '+\ 4802 ','.join([self.mp_prefix+cm for cm in complex_mass])+'\n\n')
4803
4804 - def create_write_couplings(self):
4805 """ write the file coupl_write.inc """ 4806 4807 fsock = self.open('coupl_write.inc', format='fortran') 4808 4809 fsock.writelines("""write(*,*) ' Couplings of %s' 4810 write(*,*) ' ---------------------------------' 4811 write(*,*) ' '""" % self.model_name) 4812 def format(coupl): 4813 return 'write(*,2) \'%(name)s = \', %(name)s' % {'name': coupl.name}
4814 4815 # Write the Couplings 4816 lines = [format(coupl) for coupl in self.coups_dep + self.coups_indep] 4817 fsock.writelines('\n'.join(lines)) 4818 4819
4820 - def create_input(self):
4821 """create input.inc containing the definition of the parameters""" 4822 4823 fsock = self.open('input.inc', format='fortran') 4824 if self.opt['mp']: 4825 mp_fsock = self.open('mp_input.inc', format='fortran') 4826 4827 #find mass/ width since they are already define 4828 already_def = set() 4829 for particle in self.model.get('particles'): 4830 already_def.add(particle.get('mass').lower()) 4831 already_def.add(particle.get('width').lower()) 4832 if self.opt['complex_mass']: 4833 already_def.add('cmass_%s' % particle.get('mass').lower()) 4834 4835 is_valid = lambda name: name.lower() not in ['g', 'mu_r', 'zero'] and \ 4836 name.lower() not in already_def 4837 4838 real_parameters = [param.name for param in self.params_dep + 4839 self.params_indep if param.type == 'real' 4840 and is_valid(param.name)] 4841 4842 real_parameters += [param.name for param in self.params_ext 4843 if param.type == 'real'and 4844 is_valid(param.name)] 4845 4846 fsock.writelines('double precision '+','.join(real_parameters)+'\n') 4847 fsock.writelines('common/params_R/ '+','.join(real_parameters)+'\n\n') 4848 if self.opt['mp']: 4849 mp_fsock.writelines(self.mp_real_format+' '+','.join([\ 4850 self.mp_prefix+p for p in real_parameters])+'\n') 4851 mp_fsock.writelines('common/MP_params_R/ '+','.join([\ 4852 self.mp_prefix+p for p in real_parameters])+'\n\n') 4853 4854 complex_parameters = [param.name for param in self.params_dep + 4855 self.params_indep if param.type == 'complex' and 4856 is_valid(param.name)] 4857 4858 if complex_parameters: 4859 fsock.writelines('double complex '+','.join(complex_parameters)+'\n') 4860 fsock.writelines('common/params_C/ '+','.join(complex_parameters)+'\n\n') 4861 if self.opt['mp']: 4862 mp_fsock.writelines(self.mp_complex_format+' '+','.join([\ 4863 self.mp_prefix+p for p in complex_parameters])+'\n') 4864 mp_fsock.writelines('common/MP_params_C/ '+','.join([\ 4865 self.mp_prefix+p for p in complex_parameters])+'\n\n')
4866
4867 - def create_intparam_def(self, dp=True, mp=False):
4868 """ create intparam_definition.inc setting the internal parameters. 4869 Output the double precision and/or the multiple precision parameters 4870 depending on the parameters dp and mp. If mp only, then the file names 4871 get the 'mp_' prefix. 4872 """ 4873 4874 fsock = self.open('%sintparam_definition.inc'% 4875 ('mp_' if mp and not dp else ''), format='fortran') 4876 4877 fsock.write_comments(\ 4878 "Parameters that should not be recomputed event by event.\n") 4879 fsock.writelines("if(readlha) then\n") 4880 if dp: 4881 fsock.writelines("G = 2 * DSQRT(AS*PI) ! for the first init\n") 4882 if mp: 4883 fsock.writelines("MP__G = 2 * SQRT(MP__AS*MP__PI) ! for the first init\n") 4884 for param in self.params_indep: 4885 if param.name == 'ZERO': 4886 continue 4887 if dp: 4888 fsock.writelines("%s = %s\n" % (param.name, 4889 self.p_to_f.parse(param.expr))) 4890 if mp: 4891 fsock.writelines("%s%s = %s\n" % (self.mp_prefix,param.name, 4892 self.mp_p_to_f.parse(param.expr))) 4893 4894 fsock.writelines('endif') 4895 4896 fsock.write_comments('\nParameters that should be recomputed at an event by even basis.\n') 4897 if dp: 4898 fsock.writelines("aS = G**2/4/pi\n") 4899 if mp: 4900 fsock.writelines("MP__aS = MP__G**2/4/MP__PI\n") 4901 for param in self.params_dep: 4902 if dp: 4903 fsock.writelines("%s = %s\n" % (param.name, 4904 self.p_to_f.parse(param.expr))) 4905 elif mp: 4906 fsock.writelines("%s%s = %s\n" % (self.mp_prefix,param.name, 4907 self.mp_p_to_f.parse(param.expr))) 4908 4909 fsock.write_comments("\nDefinition of the EW coupling used in the write out of aqed\n") 4910 if ('aEWM1',) in self.model['parameters']: 4911 if dp: 4912 fsock.writelines(""" gal(1) = 3.5449077018110318 / DSQRT(aEWM1) 4913 gal(2) = 1d0 4914 """) 4915 elif mp: 4916 fsock.writelines(""" %(mp_prefix)sgal(1) = 2 * SQRT(MP__PI/MP__aEWM1) 4917 %(mp_prefix)sgal(2) = 1d0 4918 """ %{'mp_prefix':self.mp_prefix}) 4919 pass 4920 # in Gmu scheme, aEWM1 is not external but Gf is an exteranl variable 4921 elif ('Gf',) in self.model['parameters']: 4922 if dp: 4923 fsock.writelines(""" gal(1) = 2.3784142300054421*MDL_MW*MDL_SW*DSQRT(MDL_Gf) 4924 gal(2) = 1d0 4925 """) 4926 elif mp: 4927 fsock.writelines(""" %(mp_prefix)sgal(1) = 2*MP__MDL_MW*MP__MDL_SW*SQRT(SQRT(2e0_16)*MP__MDL_Gf) 4928 %(mp_prefix)sgal(2) = 1d0 4929 """ %{'mp_prefix':self.mp_prefix}) 4930 pass 4931 else: 4932 if dp: 4933 logger.warning('$RED aEWM1 and Gf not define in MODEL. AQED will not be written correcty in LHE FILE') 4934 fsock.writelines(""" gal(1) = 1d0 4935 gal(2) = 1d0 4936 """) 4937 elif mp: 4938 fsock.writelines(""" %(mp_prefix)sgal(1) = 1e0_16 4939 %(mp_prefix)sgal(2) = 1e0_16 4940 """%{'mp_prefix':self.mp_prefix})
4941 4942
4943 - def create_couplings(self):
4944 """ create couplings.f and all couplingsX.f """ 4945 4946 nb_def_by_file = 25 4947 4948 self.create_couplings_main(nb_def_by_file) 4949 nb_coup_indep = 1 + len(self.coups_indep) // nb_def_by_file 4950 nb_coup_dep = 1 + len(self.coups_dep) // nb_def_by_file 4951 4952 for i in range(nb_coup_indep): 4953 # For the independent couplings, we compute the double and multiple 4954 # precision ones together 4955 data = self.coups_indep[nb_def_by_file * i: 4956 min(len(self.coups_indep), nb_def_by_file * (i+1))] 4957 self.create_couplings_part(i + 1, data, dp=True, mp=self.opt['mp']) 4958 4959 for i in range(nb_coup_dep): 4960 # For the dependent couplings, we compute the double and multiple 4961 # precision ones in separate subroutines. 4962 data = self.coups_dep[nb_def_by_file * i: 4963 min(len(self.coups_dep), nb_def_by_file * (i+1))] 4964 self.create_couplings_part( i + 1 + nb_coup_indep , data, 4965 dp=True,mp=False) 4966 if self.opt['mp']: 4967 self.create_couplings_part( i + 1 + nb_coup_indep , data, 4968 dp=False,mp=True)
4969 4970
4971 - def create_couplings_main(self, nb_def_by_file=25):
4972 """ create couplings.f """ 4973 4974 fsock = self.open('couplings.f', format='fortran') 4975 4976 fsock.writelines("""subroutine coup() 4977 4978 implicit none 4979 double precision PI, ZERO 4980 logical READLHA 4981 parameter (PI=3.141592653589793d0) 4982 parameter (ZERO=0d0)""") 4983 if self.opt['mp']: 4984 fsock.writelines("""%s MP__PI, MP__ZERO 4985 parameter (MP__PI=3.1415926535897932384626433832795e0_16) 4986 parameter (MP__ZERO=0e0_16) 4987 include \'mp_input.inc\' 4988 include \'mp_coupl.inc\' 4989 """%self.mp_real_format) 4990 fsock.writelines("""include \'input.inc\' 4991 include \'coupl.inc\' 4992 READLHA = .true. 4993 include \'intparam_definition.inc\'""") 4994 if self.opt['mp']: 4995 fsock.writelines("""include \'mp_intparam_definition.inc\'\n""") 4996 4997 nb_coup_indep = 1 + len(self.coups_indep) // nb_def_by_file 4998 nb_coup_dep = 1 + len(self.coups_dep) // nb_def_by_file 4999 5000 fsock.writelines('\n'.join(\ 5001 ['call coup%s()' % (i + 1) for i in range(nb_coup_indep)])) 5002 5003 fsock.write_comments('\ncouplings needed to be evaluated points by points\n') 5004 5005 fsock.writelines('\n'.join(\ 5006 ['call coup%s()' % (nb_coup_indep + i + 1) \ 5007 for i in range(nb_coup_dep)])) 5008 if self.opt['mp']: 5009 fsock.writelines('\n'.join(\ 5010 ['call mp_coup%s()' % (nb_coup_indep + i + 1) \ 5011 for i in range(nb_coup_dep)])) 5012 fsock.writelines('''\n return \n end\n''') 5013 5014 fsock.writelines("""subroutine update_as_param() 5015 5016 implicit none 5017 double precision PI, ZERO 5018 logical READLHA 5019 parameter (PI=3.141592653589793d0) 5020 parameter (ZERO=0d0)""") 5021 fsock.writelines("""include \'input.inc\' 5022 include \'coupl.inc\' 5023 READLHA = .false.""") 5024 fsock.writelines(""" 5025 include \'intparam_definition.inc\'\n 5026 """) 5027 5028 nb_coup_indep = 1 + len(self.coups_indep) // nb_def_by_file 5029 nb_coup_dep = 1 + len(self.coups_dep) // nb_def_by_file 5030 5031 fsock.write_comments('\ncouplings needed to be evaluated points by points\n') 5032 5033 fsock.writelines('\n'.join(\ 5034 ['call coup%s()' % (nb_coup_indep + i + 1) \ 5035 for i in range(nb_coup_dep)])) 5036 fsock.writelines('''\n return \n end\n''') 5037 5038 fsock.writelines("""subroutine update_as_param2(mu_r2,as2) 5039 5040 implicit none 5041 double precision PI 5042 parameter (PI=3.141592653589793d0) 5043 double precision mu_r2, as2""") 5044 fsock.writelines("""include \'input.inc\' 5045 include \'coupl.inc\'""") 5046 fsock.writelines(""" 5047 MU_R = mu_r2 5048 G = SQRT(4.0d0*PI*AS2) 5049 AS = as2 5050 5051 CALL UPDATE_AS_PARAM() 5052 """) 5053 fsock.writelines('''\n return \n end\n''') 5054 5055 if self.opt['mp']: 5056 fsock.writelines("""subroutine mp_update_as_param() 5057 5058 implicit none 5059 logical READLHA""") 5060 fsock.writelines("""%s MP__PI, MP__ZERO 5061 parameter (MP__PI=3.1415926535897932384626433832795e0_16) 5062 parameter (MP__ZERO=0e0_16) 5063 include \'mp_input.inc\' 5064 include \'mp_coupl.inc\' 5065 """%self.mp_real_format) 5066 fsock.writelines("""include \'input.inc\' 5067 include \'coupl.inc\' 5068 include \'actualize_mp_ext_params.inc\' 5069 READLHA = .false. 5070 include \'mp_intparam_definition.inc\'\n 5071 """) 5072 5073 nb_coup_indep = 1 + len(self.coups_indep) // nb_def_by_file 5074 nb_coup_dep = 1 + len(self.coups_dep) // nb_def_by_file 5075 5076 fsock.write_comments('\ncouplings needed to be evaluated points by points\n') 5077 5078 fsock.writelines('\n'.join(\ 5079 ['call mp_coup%s()' % (nb_coup_indep + i + 1) \ 5080 for i in range(nb_coup_dep)])) 5081 fsock.writelines('''\n return \n end\n''')
5082
5083 - def create_couplings_part(self, nb_file, data, dp=True, mp=False):
5084 """ create couplings[nb_file].f containing information coming from data. 5085 Outputs the computation of the double precision and/or the multiple 5086 precision couplings depending on the parameters dp and mp. 5087 If mp is True and dp is False, then the prefix 'MP_' is appended to the 5088 filename and subroutine name. 5089 """ 5090 5091 fsock = self.open('%scouplings%s.f' %('mp_' if mp and not dp else '', 5092 nb_file), format='fortran') 5093 fsock.writelines("""subroutine %scoup%s() 5094 5095 implicit none"""%('mp_' if mp and not dp else '',nb_file)) 5096 if dp: 5097 fsock.writelines(""" 5098 double precision PI, ZERO 5099 parameter (PI=3.141592653589793d0) 5100 parameter (ZERO=0d0) 5101 include 'input.inc' 5102 include 'coupl.inc'""") 5103 if mp: 5104 fsock.writelines("""%s MP__PI, MP__ZERO 5105 parameter (MP__PI=3.1415926535897932384626433832795e0_16) 5106 parameter (MP__ZERO=0e0_16) 5107 include \'mp_input.inc\' 5108 include \'mp_coupl.inc\' 5109 """%self.mp_real_format) 5110 fsock.writelines(""" 5111 include 'model_functions.inc'""") 5112 for coupling in data: 5113 if dp: 5114 fsock.writelines('%s = %s' % (coupling.name, 5115 self.p_to_f.parse(coupling.expr))) 5116 if mp: 5117 fsock.writelines('%s%s = %s' % (self.mp_prefix,coupling.name, 5118 self.mp_p_to_f.parse(coupling.expr))) 5119 fsock.writelines('end')
5120
5121 - def create_model_functions_inc(self):
5122 """ Create model_functions.inc which contains the various declarations 5123 of auxiliary functions which might be used in the couplings expressions 5124 """ 5125 5126 fsock = self.open('model_functions.inc', format='fortran') 5127 fsock.writelines("""double complex cond 5128 double complex condif 5129 double complex reglog 5130 double complex arg""") 5131 if self.opt['mp']: 5132 fsock.writelines("""%(complex_mp_format)s mp_cond 5133 %(complex_mp_format)s mp_condif 5134 %(complex_mp_format)s mp_reglog 5135 %(complex_mp_format)s mp_arg"""\ 5136 %{'complex_mp_format':self.mp_complex_format})
5137
5138 - def create_model_functions_def(self):
5139 """ Create model_functions.f which contains the various definitions 5140 of auxiliary functions which might be used in the couplings expressions 5141 Add the functions.f functions for formfactors support 5142 """ 5143 5144 fsock = self.open('model_functions.f', format='fortran') 5145 fsock.writelines("""double complex function cond(condition,truecase,falsecase) 5146 implicit none 5147 double complex condition,truecase,falsecase 5148 if(condition.eq.(0.0d0,0.0d0)) then 5149 cond=truecase 5150 else 5151 cond=falsecase 5152 endif 5153 end 5154 5155 double complex function condif(condition,truecase,falsecase) 5156 implicit none 5157 logical condition 5158 double complex truecase,falsecase 5159 if(condition) then 5160 condif=truecase 5161 else 5162 condif=falsecase 5163 endif 5164 end 5165 5166 double complex function reglog(arg) 5167 implicit none 5168 double complex arg 5169 if(arg.eq.(0.0d0,0.0d0)) then 5170 reglog=(0.0d0,0.0d0) 5171 else 5172 reglog=log(arg) 5173 endif 5174 end 5175 5176 double complex function arg(comnum) 5177 implicit none 5178 double complex comnum 5179 double complex iim 5180 iim = (0.0d0,1.0d0) 5181 if(comnum.eq.(0.0d0,0.0d0)) then 5182 arg=(0.0d0,0.0d0) 5183 else 5184 arg=log(comnum/abs(comnum))/iim 5185 endif 5186 end""") 5187 if self.opt['mp']: 5188 fsock.writelines(""" 5189 5190 %(complex_mp_format)s function mp_cond(condition,truecase,falsecase) 5191 implicit none 5192 %(complex_mp_format)s condition,truecase,falsecase 5193 if(condition.eq.(0.0e0_16,0.0e0_16)) then 5194 mp_cond=truecase 5195 else 5196 mp_cond=falsecase 5197 endif 5198 end 5199 5200 %(complex_mp_format)s function mp_condif(condition,truecase,falsecase) 5201 implicit none 5202 logical condition 5203 %(complex_mp_format)s truecase,falsecase 5204 if(condition) then 5205 mp_condif=truecase 5206 else 5207 mp_condif=falsecase 5208 endif 5209 end 5210 5211 %(complex_mp_format)s function mp_reglog(arg) 5212 implicit none 5213 %(complex_mp_format)s arg 5214 if(arg.eq.(0.0e0_16,0.0e0_16)) then 5215 mp_reglog=(0.0e0_16,0.0e0_16) 5216 else 5217 mp_reglog=log(arg) 5218 endif 5219 end 5220 5221 %(complex_mp_format)s function mp_arg(comnum) 5222 implicit none 5223 %(complex_mp_format)s comnum 5224 %(complex_mp_format)s imm 5225 imm = (0.0e0_16,1.0e0_16) 5226 if(comnum.eq.(0.0e0_16,0.0e0_16)) then 5227 mp_arg=(0.0e0_16,0.0e0_16) 5228 else 5229 mp_arg=log(comnum/abs(comnum))/imm 5230 endif 5231 end"""%{'complex_mp_format':self.mp_complex_format}) 5232 5233 #check for the file functions.f 5234 model_path = self.model.get('modelpath') 5235 if os.path.exists(pjoin(model_path,'Fortran','functions.f')): 5236 fsock.write_comment_line(' USER DEFINE FUNCTIONS ') 5237 input = pjoin(model_path,'Fortran','functions.f') 5238 file.writelines(fsock, open(input).read()) 5239 fsock.write_comment_line(' END USER DEFINE FUNCTIONS ') 5240 5241 # check for functions define in the UFO model 5242 ufo_fct = self.model.get('functions') 5243 if ufo_fct: 5244 fsock.write_comment_line(' START UFO DEFINE FUNCTIONS ') 5245 for fct in ufo_fct: 5246 # already handle by default 5247 if fct.name not in ["complexconjugate", "re", "im", "sec", "csc", "asec", "acsc", 5248 "theta_function", "cond", "reglog", "arg"]: 5249 ufo_fct_template = """ 5250 double complex function %(name)s(%(args)s) 5251 implicit none 5252 double complex %(args)s 5253 %(name)s = %(fct)s 5254 5255 return 5256 end 5257 """ 5258 text = ufo_fct_template % { 5259 'name': fct.name, 5260 'args': ", ".join(fct.arguments), 5261 'fct': self.p_to_f.parse(fct.expr) 5262 } 5263 fsock.writelines(text) 5264 if self.opt['mp']: 5265 fsock.write_comment_line(' START UFO DEFINE FUNCTIONS FOR MP') 5266 for fct in ufo_fct: 5267 # already handle by default 5268 if fct.name not in ["complexconjugate", "re", "im", "sec", "csc", "asec", "acsc", 5269 "theta_function", "cond", "reglog", "arg"]: 5270 ufo_fct_template = """ 5271 %(complex_mp_format)s function mp__%(name)s(mp__%(args)s) 5272 implicit none 5273 %(complex_mp_format)s mp__%(args)s 5274 mp__%(name)s = %(fct)s 5275 5276 return 5277 end 5278 """ 5279 text = ufo_fct_template % { 5280 'name': fct.name, 5281 'args': ", mp__".join(fct.arguments), 5282 'fct': self.mp_p_to_f.parse(fct.expr), 5283 'complex_mp_format': self.mp_complex_format 5284 } 5285 fsock.writelines(text) 5286 5287 5288 5289 fsock.write_comment_line(' STOP UFO DEFINE FUNCTIONS ')
5290 5291 5292
5293 - def create_makeinc(self):
5294 """create makeinc.inc containing the file to compile """ 5295 5296 fsock = self.open('makeinc.inc', comment='#') 5297 text = 'MODEL = couplings.o lha_read.o printout.o rw_para.o' 5298 text += ' model_functions.o ' 5299 5300 nb_coup_indep = 1 + len(self.coups_dep) // 25 5301 nb_coup_dep = 1 + len(self.coups_indep) // 25 5302 couplings_files=['couplings%s.o' % (i+1) \ 5303 for i in range(nb_coup_dep + nb_coup_indep) ] 5304 if self.opt['mp']: 5305 couplings_files+=['mp_couplings%s.o' % (i+1) for i in \ 5306 range(nb_coup_dep,nb_coup_dep + nb_coup_indep) ] 5307 text += ' '.join(couplings_files) 5308 fsock.writelines(text)
5309
5310 - def create_param_write(self):
5311 """ create param_write """ 5312 5313 fsock = self.open('param_write.inc', format='fortran') 5314 5315 fsock.writelines("""write(*,*) ' External Params' 5316 write(*,*) ' ---------------------------------' 5317 write(*,*) ' '""") 5318 def format(name): 5319 return 'write(*,*) \'%(name)s = \', %(name)s' % {'name': name}
5320 5321 # Write the external parameter 5322 lines = [format(param.name) for param in self.params_ext] 5323 fsock.writelines('\n'.join(lines)) 5324 5325 fsock.writelines("""write(*,*) ' Internal Params' 5326 write(*,*) ' ---------------------------------' 5327 write(*,*) ' '""") 5328 lines = [format(data.name) for data in self.params_indep 5329 if data.name != 'ZERO'] 5330 fsock.writelines('\n'.join(lines)) 5331 fsock.writelines("""write(*,*) ' Internal Params evaluated point by point' 5332 write(*,*) ' ----------------------------------------' 5333 write(*,*) ' '""") 5334 lines = [format(data.name) for data in self.params_dep] 5335 5336 fsock.writelines('\n'.join(lines)) 5337 5338 5339
5340 - def create_ident_card(self):
5341 """ create the ident_card.dat """ 5342 5343 def format(parameter): 5344 """return the line for the ident_card corresponding to this parameter""" 5345 colum = [parameter.lhablock.lower()] + \ 5346 [str(value) for value in parameter.lhacode] + \ 5347 [parameter.name] 5348 if not parameter.name: 5349 return '' 5350 return ' '.join(colum)+'\n'
5351 5352 fsock = self.open('ident_card.dat') 5353 5354 external_param = [format(param) for param in self.params_ext] 5355 fsock.writelines('\n'.join(external_param)) 5356
5357 - def create_actualize_mp_ext_param_inc(self):
5358 """ create the actualize_mp_ext_params.inc code """ 5359 5360 # In principle one should actualize all external, but for now, it is 5361 # hardcoded that only AS and MU_R can by dynamically changed by the user 5362 # so that we only update those ones. 5363 # Of course, to be on the safe side, one could decide to update all 5364 # external parameters. 5365 update_params_list=[p for p in self.params_ext if p.name in 5366 self.PS_dependent_key] 5367 5368 res_strings = ["%(mp_prefix)s%(name)s=%(name)s"\ 5369 %{'mp_prefix':self.mp_prefix,'name':param.name}\ 5370 for param in update_params_list] 5371 # When read_lha is false, it is G which is taken in input and not AS, so 5372 # this is what should be reset here too. 5373 if 'aS' in [param.name for param in update_params_list]: 5374 res_strings.append("%(mp_prefix)sG=G"%{'mp_prefix':self.mp_prefix}) 5375 5376 fsock = self.open('actualize_mp_ext_params.inc', format='fortran') 5377 fsock.writelines('\n'.join(res_strings))
5378
5379 - def create_param_read(self):
5380 """create param_read""" 5381 5382 if self.opt['export_format'] in ['madevent', 'FKS5_default', 'FKS5_optimized']: 5383 fsock = self.open('param_read.inc', format='fortran') 5384 fsock.writelines(' include \'../param_card.inc\'') 5385 return 5386 5387 def format_line(parameter): 5388 """return the line for the ident_card corresponding to this 5389 parameter""" 5390 template = \ 5391 """ call LHA_get_real(npara,param,value,'%(name)s',%(name)s,%(value)s)""" \ 5392 % {'name': parameter.name, 5393 'value': self.p_to_f.parse(str(parameter.value.real))} 5394 if self.opt['mp']: 5395 template = template+ \ 5396 ("\n call MP_LHA_get_real(npara,param,value,'%(name)s',"+ 5397 "%(mp_prefix)s%(name)s,%(value)s)") \ 5398 % {'name': parameter.name,'mp_prefix': self.mp_prefix, 5399 'value': self.mp_p_to_f.parse(str(parameter.value.real))} 5400 return template 5401 5402 fsock = self.open('param_read.inc', format='fortran') 5403 res_strings = [format_line(param) \ 5404 for param in self.params_ext] 5405 5406 # Correct width sign for Majorana particles (where the width 5407 # and mass need to have the same sign) 5408 for particle in self.model.get('particles'): 5409 if particle.is_fermion() and particle.get('self_antipart') and \ 5410 particle.get('width').lower() != 'zero': 5411 5412 res_strings.append('%(width)s = sign(%(width)s,%(mass)s)' % \ 5413 {'width': particle.get('width'), 'mass': particle.get('mass')}) 5414 if self.opt['mp']: 5415 res_strings.append(\ 5416 ('%(mp_pref)s%(width)s = sign(%(mp_pref)s%(width)s,'+\ 5417 '%(mp_pref)s%(mass)s)')%{'width': particle.get('width'),\ 5418 'mass': particle.get('mass'),'mp_pref':self.mp_prefix}) 5419 5420 fsock.writelines('\n'.join(res_strings)) 5421
5422 - def create_param_card(self):
5423 """ create the param_card.dat """ 5424 5425 #1. Check if a default param_card is present: 5426 done = False 5427 if hasattr(self.model, 'restrict_card') and isinstance(self.model.restrict_card, str): 5428 restrict_name = os.path.basename(self.model.restrict_card)[9:-4] 5429 model_path = self.model.get('modelpath') 5430 if os.path.exists(pjoin(model_path,'paramcard_%s.dat' % restrict_name)): 5431 done = True 5432 files.cp(pjoin(model_path,'paramcard_%s.dat' % restrict_name), 5433 pjoin(self.dir_path, 'param_card.dat')) 5434 if not done: 5435 out_path = pjoin(self.dir_path, 'param_card.dat') 5436 param_writer.ParamCardWriter(self.model, out_path) 5437 5438 out_path2 = None 5439 if hasattr(self.model, 'rule_card'): 5440 out_path2 = pjoin(self.dir_path, 'param_card_rule.dat') 5441 self.model.rule_card.write_file(out_path2) 5442 5443 # IF MSSM convert the card to SLAH1 5444 if self.model_name == 'mssm' or self.model_name.startswith('mssm-'): 5445 import models.check_param_card as translator 5446 5447 # Check the format of the param_card for Pythia and make it correct 5448 if out_path2: 5449 translator.make_valid_param_card(out_path, out_path2) 5450 translator.convert_to_slha1(out_path)
5451
5452 -def ExportV4Factory(cmd, noclean, output_type='default'):
5453 """ Determine which Export_v4 class is required. cmd is the command 5454 interface containing all potential usefull information. 5455 The output_type argument specifies from which context the output 5456 is called. It is 'madloop' for MadLoop5, 'amcatnlo' for FKS5 output 5457 and 'default' for tree-level outputs.""" 5458 5459 group_subprocesses = cmd.options['group_subprocesses'] 5460 5461 # First treat the MadLoop5 standalone case 5462 if output_type=='madloop': 5463 import madgraph.loop.loop_exporters as loop_exporters 5464 if os.path.isdir(os.path.join(cmd._mgme_dir, 'Template/loop_material')): 5465 ExporterClass=None 5466 options = {'clean': not noclean, 5467 'complex_mass':cmd.options['complex_mass_scheme'], 5468 'export_format':'madloop', 5469 'mp':True, 5470 'loop_dir': os.path.join(cmd._mgme_dir, 'Template/loop_material'), 5471 'cuttools_dir': cmd._cuttools_dir, 5472 'iregi_dir':cmd._iregi_dir, 5473 'pjfry_dir':cmd.options["pjfry"], 5474 'golem_dir':cmd.options["golem"], 5475 'fortran_compiler':cmd.options['fortran_compiler'], 5476 'output_dependencies':cmd.options['output_dependencies']} 5477 5478 if not cmd.options['loop_optimized_output']: 5479 ExporterClass=loop_exporters.LoopProcessExporterFortranSA 5480 else: 5481 if all([amp['process']['has_born'] for amp in cmd._curr_amps]): 5482 ExporterClass=loop_exporters.LoopProcessOptimizedExporterFortranSA 5483 options['export_format'] = 'madloop_optimized' 5484 else: 5485 logger.warning('ML5 can only exploit the optimized output for '+\ 5486 ' processes with born diagrams. The optimization '+\ 5487 ' option is therefore turned off for this process.') 5488 ExporterClass=loop_exporters.LoopProcessExporterFortranSA 5489 options['export_format'] = 'madloop_default' 5490 return ExporterClass(cmd._mgme_dir, cmd._export_dir, options) 5491 else: 5492 raise MadGraph5Error('MG5_aMC cannot find the \'loop_material\' directory'+\ 5493 ' in %s'%str(cmd._mgme_dir)) 5494 5495 # Then treat the aMC@NLO output 5496 elif output_type=='amcatnlo': 5497 import madgraph.iolibs.export_fks as export_fks 5498 ExporterClass=None 5499 options = {'clean': not noclean, 5500 'complex_mass':cmd.options['complex_mass_scheme'], 5501 'export_format':'madloop', 5502 #use MP for HELAS only if there are virtual amps 5503 'mp':len(cmd._fks_multi_proc.get_virt_amplitudes()) > 0, 5504 'loop_dir': os.path.join(cmd._mgme_dir,'Template','loop_material'), 5505 'cuttools_dir': cmd._cuttools_dir, 5506 'iregi_dir':cmd._iregi_dir, 5507 'pjfry_dir':cmd.options["pjfry"], 5508 'golem_dir':cmd.options["golem"], 5509 'fortran_compiler':cmd.options['fortran_compiler'], 5510 'output_dependencies':cmd.options['output_dependencies']} 5511 if not cmd.options['loop_optimized_output']: 5512 logger.info("Writing out the aMC@NLO code") 5513 ExporterClass = export_fks.ProcessExporterFortranFKS 5514 options['export_format']='FKS5_default' 5515 else: 5516 logger.info("Writing out the aMC@NLO code, using optimized Loops") 5517 ExporterClass = export_fks.ProcessOptimizedExporterFortranFKS 5518 options['export_format']='FKS5_optimized' 5519 return ExporterClass(cmd._mgme_dir, cmd._export_dir, options) 5520 5521 # Then the default tree-level output 5522 elif output_type=='default': 5523 #check if we need to group processes 5524 if cmd.options['group_subprocesses'] == 'Auto': 5525 if cmd._curr_amps[0].get_ninitial() == 2: 5526 group_subprocesses = True 5527 else: 5528 group_subprocesses = False 5529 5530 assert group_subprocesses in [True, False] 5531 5532 opt = {'clean': not noclean, 5533 'complex_mass': cmd.options['complex_mass_scheme'], 5534 'export_format':cmd._export_format, 5535 'mp': False, 5536 'sa_symmetry':False, 5537 'model': cmd._curr_model.get('name') } 5538 5539 format = cmd._export_format #shortcut 5540 5541 if format in ['standalone_msP', 'standalone_msF', 'standalone_rw']: 5542 opt['sa_symmetry'] = True 5543 5544 if format == 'matrix' or format.startswith('standalone'): 5545 return ProcessExporterFortranSA(cmd._mgme_dir, cmd._export_dir, opt, 5546 format=format) 5547 5548 elif format in ['madevent'] and group_subprocesses: 5549 return ProcessExporterFortranMEGroup(cmd._mgme_dir, cmd._export_dir, 5550 opt) 5551 elif format in ['madevent']: 5552 return ProcessExporterFortranME(cmd._mgme_dir, cmd._export_dir,opt) 5553 elif cmd._export_format in ['madweight'] and group_subprocesses: 5554 5555 return ProcessExporterFortranMWGroup(cmd._mgme_dir, cmd._export_dir, 5556 opt) 5557 elif cmd._export_format in ['madweight']: 5558 return ProcessExporterFortranMW(cmd._mgme_dir, cmd._export_dir, opt) 5559 else: 5560 raise Exception, 'Wrong export_v4 format' 5561 else: 5562 raise MadGraph5Error, 'Output type %s not reckognized in ExportV4Factory.'
5563 5564 5565 5566 5567 #=============================================================================== 5568 # ProcessExporterFortranMWGroup 5569 #===============================================================================
5570 -class ProcessExporterFortranMWGroup(ProcessExporterFortranMW):
5571 """Class to take care of exporting a set of matrix elements to 5572 MadEvent subprocess group format.""" 5573 5574 matrix_file = "matrix_madweight_group_v4.inc" 5575 5576 #=========================================================================== 5577 # generate_subprocess_directory_v4 5578 #===========================================================================
5579 - def generate_subprocess_directory_v4(self, subproc_group, 5580 fortran_model, 5581 group_number):
5582 """Generate the Pn directory for a subprocess group in MadEvent, 5583 including the necessary matrix_N.f files, configs.inc and various 5584 other helper files""" 5585 5586 if not isinstance(subproc_group, group_subprocs.SubProcessGroup): 5587 raise base_objects.PhysicsObject.PhysicsObjectError,\ 5588 "subproc_group object not SubProcessGroup" 5589 5590 if not self.model: 5591 self.model = subproc_group.get('matrix_elements')[0].\ 5592 get('processes')[0].get('model') 5593 5594 pathdir = os.path.join(self.dir_path, 'SubProcesses') 5595 5596 # Create the directory PN in the specified path 5597 subprocdir = "P%d_%s" % (subproc_group.get('number'), 5598 subproc_group.get('name')) 5599 try: 5600 os.mkdir(pjoin(pathdir, subprocdir)) 5601 except os.error as error: 5602 logger.warning(error.strerror + " " + subprocdir) 5603 5604 5605 logger.info('Creating files in directory %s' % subprocdir) 5606 Ppath = pjoin(pathdir, subprocdir) 5607 5608 # Create the matrix.f files, auto_dsig.f files and all inc files 5609 # for all subprocesses in the group 5610 5611 maxamps = 0 5612 maxflows = 0 5613 tot_calls = 0 5614 5615 matrix_elements = subproc_group.get('matrix_elements') 5616 5617 for ime, matrix_element in \ 5618 enumerate(matrix_elements): 5619 filename = pjoin(Ppath, 'matrix%d.f' % (ime+1)) 5620 calls, ncolor = \ 5621 self.write_matrix_element_v4(writers.FortranWriter(filename), 5622 matrix_element, 5623 fortran_model, 5624 str(ime+1), 5625 subproc_group.get('diagram_maps')[\ 5626 ime]) 5627 5628 filename = pjoin(Ppath, 'auto_dsig%d.f' % (ime+1)) 5629 self.write_auto_dsig_file(writers.FortranWriter(filename), 5630 matrix_element, 5631 str(ime+1)) 5632 5633 # Keep track of needed quantities 5634 tot_calls += int(calls) 5635 maxflows = max(maxflows, ncolor) 5636 maxamps = max(maxamps, len(matrix_element.get('diagrams'))) 5637 5638 # Draw diagrams 5639 filename = pjoin(Ppath, "matrix%d.ps" % (ime+1)) 5640 plot = draw.MultiEpsDiagramDrawer(matrix_element.get('base_amplitude').\ 5641 get('diagrams'), 5642 filename, 5643 model = \ 5644 matrix_element.get('processes')[0].\ 5645 get('model'), 5646 amplitude=True) 5647 logger.info("Generating Feynman diagrams for " + \ 5648 matrix_element.get('processes')[0].nice_string()) 5649 plot.draw() 5650 5651 # Extract number of external particles 5652 (nexternal, ninitial) = matrix_element.get_nexternal_ninitial() 5653 5654 # Generate a list of diagrams corresponding to each configuration 5655 # [[d1, d2, ...,dn],...] where 1,2,...,n is the subprocess number 5656 # If a subprocess has no diagrams for this config, the number is 0 5657 5658 subproc_diagrams_for_config = subproc_group.get('diagrams_for_configs') 5659 5660 filename = pjoin(Ppath, 'auto_dsig.f') 5661 self.write_super_auto_dsig_file(writers.FortranWriter(filename), 5662 subproc_group) 5663 5664 filename = pjoin(Ppath,'configs.inc') 5665 nconfigs, s_and_t_channels = self.write_configs_file(\ 5666 writers.FortranWriter(filename), 5667 subproc_group, 5668 subproc_diagrams_for_config) 5669 5670 filename = pjoin(Ppath, 'leshouche.inc') 5671 self.write_leshouche_file(writers.FortranWriter(filename), 5672 subproc_group) 5673 5674 filename = pjoin(Ppath, 'phasespace.inc') 5675 self.write_phasespace_file(writers.FortranWriter(filename), 5676 nconfigs) 5677 5678 5679 filename = pjoin(Ppath, 'maxamps.inc') 5680 self.write_maxamps_file(writers.FortranWriter(filename), 5681 maxamps, 5682 maxflows, 5683 max([len(me.get('processes')) for me in \ 5684 matrix_elements]), 5685 len(matrix_elements)) 5686 5687 filename = pjoin(Ppath, 'mirrorprocs.inc') 5688 self.write_mirrorprocs(writers.FortranWriter(filename), 5689 subproc_group) 5690 5691 filename = pjoin(Ppath, 'nexternal.inc') 5692 self.write_nexternal_file(writers.FortranWriter(filename), 5693 nexternal, ninitial) 5694 5695 filename = pjoin(Ppath, 'pmass.inc') 5696 self.write_pmass_file(writers.FortranWriter(filename), 5697 matrix_element) 5698 5699 filename = pjoin(Ppath, 'props.inc') 5700 self.write_props_file(writers.FortranWriter(filename), 5701 matrix_element, 5702 s_and_t_channels) 5703 5704 # filename = pjoin(Ppath, 'processes.dat') 5705 # files.write_to_file(filename, 5706 # self.write_processes_file, 5707 # subproc_group) 5708 5709 # Generate jpgs -> pass in make_html 5710 #os.system(os.path.join('..', '..', 'bin', 'gen_jpeg-pl')) 5711 5712 linkfiles = ['driver.f', 'cuts.f', 'initialization.f','gen_ps.f', 'makefile', 'coupl.inc','madweight_param.inc', 'run.inc', 'setscales.f'] 5713 5714 for file in linkfiles: 5715 ln('../%s' % file, cwd=Ppath) 5716 5717 ln('nexternal.inc', '../../Source', cwd=Ppath, log=False) 5718 ln('leshouche.inc', '../../Source', cwd=Ppath, log=False) 5719 ln('maxamps.inc', '../../Source', cwd=Ppath, log=False) 5720 ln('../../Source/maxparticles.inc', '.', log=True, cwd=Ppath) 5721 ln('../../Source/maxparticles.inc', '.', name='genps.inc', log=True, cwd=Ppath) 5722 ln('phasespace.inc', '../', log=True, cwd=Ppath) 5723 if not tot_calls: 5724 tot_calls = 0 5725 return tot_calls
5726 5727 #=========================================================================== 5728 # write_super_auto_dsig_file 5729 #===========================================================================
5730 - def write_super_auto_dsig_file(self, writer, subproc_group):
5731 """Write the auto_dsig.f file selecting between the subprocesses 5732 in subprocess group mode""" 5733 5734 replace_dict = {} 5735 5736 # Extract version number and date from VERSION file 5737 info_lines = self.get_mg5_info_lines() 5738 replace_dict['info_lines'] = info_lines 5739 5740 matrix_elements = subproc_group.get('matrix_elements') 5741 5742 # Extract process info lines 5743 process_lines = '\n'.join([self.get_process_info_lines(me) for me in \ 5744 matrix_elements]) 5745 replace_dict['process_lines'] = process_lines 5746 5747 nexternal, ninitial = matrix_elements[0].get_nexternal_ninitial() 5748 replace_dict['nexternal'] = nexternal 5749 5750 replace_dict['nsprocs'] = 2*len(matrix_elements) 5751 5752 # Generate dsig definition line 5753 dsig_def_line = "DOUBLE PRECISION " + \ 5754 ",".join(["DSIG%d" % (iproc + 1) for iproc in \ 5755 range(len(matrix_elements))]) 5756 replace_dict["dsig_def_line"] = dsig_def_line 5757 5758 # Generate dsig process lines 5759 call_dsig_proc_lines = [] 5760 for iproc in range(len(matrix_elements)): 5761 call_dsig_proc_lines.append(\ 5762 "IF(IPROC.EQ.%(num)d) DSIGPROC=DSIG%(num)d(P1,WGT,IMODE) ! %(proc)s" % \ 5763 {"num": iproc + 1, 5764 "proc": matrix_elements[iproc].get('processes')[0].base_string()}) 5765 replace_dict['call_dsig_proc_lines'] = "\n".join(call_dsig_proc_lines) 5766 5767 file = open(os.path.join(_file_path, \ 5768 'iolibs/template_files/super_auto_dsig_mw_group_v4.inc')).read() 5769 file = file % replace_dict 5770 5771 # Write the file 5772 writer.writelines(file)
5773 5774 #=========================================================================== 5775 # write_mirrorprocs 5776 #===========================================================================
5777 - def write_mirrorprocs(self, writer, subproc_group):
5778 """Write the mirrorprocs.inc file determining which processes have 5779 IS mirror process in subprocess group mode.""" 5780 5781 lines = [] 5782 bool_dict = {True: '.true.', False: '.false.'} 5783 matrix_elements = subproc_group.get('matrix_elements') 5784 lines.append("DATA (MIRRORPROCS(I),I=1,%d)/%s/" % \ 5785 (len(matrix_elements), 5786 ",".join([bool_dict[me.get('has_mirror_process')] for \ 5787 me in matrix_elements]))) 5788 # Write the file 5789 writer.writelines(lines)
5790 5791 #=========================================================================== 5792 # write_configs_file 5793 #===========================================================================
5794 - def write_configs_file(self, writer, subproc_group, diagrams_for_config):
5795 """Write the configs.inc file with topology information for a 5796 subprocess group. Use the first subprocess with a diagram for each 5797 configuration.""" 5798 5799 matrix_elements = subproc_group.get('matrix_elements') 5800 model = matrix_elements[0].get('processes')[0].get('model') 5801 5802 diagrams = [] 5803 config_numbers = [] 5804 for iconfig, config in enumerate(diagrams_for_config): 5805 # Check if any diagrams correspond to this config 5806 if set(config) == set([0]): 5807 continue 5808 subproc_diags = [] 5809 for s,d in enumerate(config): 5810 if d: 5811 subproc_diags.append(matrix_elements[s].\ 5812 get('diagrams')[d-1]) 5813 else: 5814 subproc_diags.append(None) 5815 diagrams.append(subproc_diags) 5816 config_numbers.append(iconfig + 1) 5817 5818 # Extract number of external particles 5819 (nexternal, ninitial) = subproc_group.get_nexternal_ninitial() 5820 5821 return len(diagrams), \ 5822 self.write_configs_file_from_diagrams(writer, diagrams, 5823 config_numbers, 5824 nexternal, ninitial, 5825 matrix_elements[0],model)
5826 5827 #=========================================================================== 5828 # write_run_configs_file 5829 #===========================================================================
5830 - def write_run_config_file(self, writer):
5831 """Write the run_configs.inc file for MadEvent""" 5832 5833 path = os.path.join(_file_path,'iolibs','template_files','madweight_run_config.inc') 5834 text = open(path).read() % {'chanperjob':'2'} 5835 writer.write(text) 5836 return True
5837 5838 5839 #=========================================================================== 5840 # write_leshouche_file 5841 #===========================================================================
5842 - def write_leshouche_file(self, writer, subproc_group):
5843 """Write the leshouche.inc file for MG4""" 5844 5845 all_lines = [] 5846 5847 for iproc, matrix_element in \ 5848 enumerate(subproc_group.get('matrix_elements')): 5849 all_lines.extend(self.get_leshouche_lines(matrix_element, 5850 iproc)) 5851 5852 # Write the file 5853 writer.writelines(all_lines) 5854 5855 return True
5856