Package madgraph :: Package interface :: Module reweight_interface
[hide private]
[frames] | no frames]

Source Code for Module madgraph.interface.reweight_interface

   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  """ Command interface for MadSpin """ 
  16  from __future__ import division 
  17  import difflib 
  18  import logging 
  19  import math 
  20  import os 
  21  import re 
  22  import shutil 
  23  import sys 
  24  import tempfile 
  25  import time 
  26  import subprocess 
  27  from subprocess import Popen, PIPE, STDOUT 
  28   
  29   
  30  pjoin = os.path.join 
  31   
  32  import madgraph.interface.extended_cmd as extended_cmd 
  33  import madgraph.interface.madgraph_interface as mg_interface 
  34  import madgraph.interface.master_interface as master_interface 
  35  import madgraph.interface.common_run_interface as common_run_interface 
  36  import madgraph.iolibs.files as files 
  37  import MadSpin.interface_madspin as madspin_interface 
  38  import madgraph.various.misc as misc 
  39  import madgraph.various.banner as banner 
  40  import madgraph.various.lhe_parser as lhe_parser 
  41  import madgraph.various.combine_plots as combine_plots 
  42  import madgraph.various.cluster as cluster 
  43  import madgraph.fks.fks_common as fks_common 
  44   
  45  import models.import_ufo as import_ufo 
  46  import models.check_param_card as check_param_card  
  47  import MadSpin.decay as madspin 
  48   
  49   
  50  logger = logging.getLogger('decay.stdout') # -> stdout 
  51  logger_stderr = logging.getLogger('decay.stderr') # ->stderr 
  52  cmd_logger = logging.getLogger('cmdprint2') # -> print 
  53   
  54  # global to check which f2py module have been already loaded. (to avoid border effect) 
  55  dir_to_f2py_free_mod = {} 
  56  nb_f2py_module = 0 # each time the process/model is changed this number is modified to  
57 # forced the python module to re-create an executable 58 59 60 61 62 -class ReweightInterface(extended_cmd.Cmd):
63 """Basic interface for reweighting operation""" 64 65 prompt = 'Reweight>' 66 debug_output = 'Reweight_debug' 67 68 @misc.mute_logger()
69 - def __init__(self, event_path=None, allow_madspin=False, *completekey, **stdin):
70 """initialize the interface with potentially an event_path""" 71 72 if not event_path: 73 cmd_logger.info('************************************************************') 74 cmd_logger.info('* *') 75 cmd_logger.info('* Welcome to Reweight Module *') 76 cmd_logger.info('* *') 77 cmd_logger.info('************************************************************') 78 extended_cmd.Cmd.__init__(self, *completekey, **stdin) 79 80 self.model = None 81 self.has_standalone_dir = False 82 83 self.options = {'curr_dir': os.path.realpath(os.getcwd())} 84 85 self.events_file = None 86 self.processes = {} 87 self.second_model = None 88 self.second_process = None 89 self.mg5cmd = master_interface.MasterCmd() 90 self.seed = None 91 self.output_type = "default" 92 self.helicity_reweighting = True 93 self.rwgt_dir = None 94 95 if event_path: 96 logger.info("Extracting the banner ...") 97 self.do_import(event_path, allow_madspin=allow_madspin) 98 99 # dictionary to fortan evaluator 100 self.calculator = {} 101 self.calculator_nbcall = {} 102 103 #all the cross-section for convenience 104 self.all_cross_section = {}
105
106 - def do_import(self, inputfile, allow_madspin=False):
107 """import the event file""" 108 109 args = self.split_arg(inputfile) 110 if not args: 111 return self.InvalidCmd, 'import requires arguments' 112 113 # change directory where to write the output 114 self.options['curr_dir'] = os.path.realpath(os.path.dirname(inputfile)) 115 if os.path.basename(os.path.dirname(os.path.dirname(inputfile))) == 'Events': 116 self.options['curr_dir'] = pjoin(self.options['curr_dir'], 117 os.path.pardir, os.pardir) 118 119 120 if not os.path.exists(inputfile): 121 if inputfile.endswith('.gz'): 122 if not os.path.exists(inputfile[:-3]): 123 raise self.InvalidCmd('No such file or directory : %s' % inputfile) 124 else: 125 inputfile = inputfile[:-3] 126 elif os.path.exists(inputfile + '.gz'): 127 inputfile = inputfile + '.gz' 128 else: 129 raise self.InvalidCmd('No such file or directory : %s' % inputfile) 130 131 if inputfile.endswith('.gz'): 132 misc.gunzip(inputfile) 133 inputfile = inputfile[:-3] 134 135 # Read the banner of the inputfile 136 self.lhe_input = lhe_parser.EventFile(os.path.realpath(inputfile)) 137 if not self.lhe_input.banner: 138 value = self.ask("What is the path to banner", 0, [0], "please enter a path", timeout=0) 139 self.lhe_input.banner = open(value).read() 140 self.banner = self.lhe_input.get_banner() 141 142 #get original cross-section/error 143 if 'init' not in self.banner: 144 self.orig_cross = (0,0) 145 #raise self.InvalidCmd('Event file does not contain init information') 146 else: 147 for line in self.banner['init'].split('\n'): 148 split = line.split() 149 if len(split) == 4: 150 cross, error = float(split[0]), float(split[1]) 151 self.orig_cross = (cross, error) 152 153 154 155 # Check the validity of the banner: 156 if 'slha' not in self.banner: 157 misc.sprint(self.banner) 158 self.events_file = None 159 raise self.InvalidCmd('Event file does not contain model information') 160 elif 'mg5proccard' not in self.banner: 161 self.events_file = None 162 raise self.InvalidCmd('Event file does not contain generation information') 163 164 if 'madspin' in self.banner and not allow_madspin: 165 raise self.InvalidCmd('Reweight should be done before running MadSpin') 166 167 168 # load information 169 process = self.banner.get_detail('proc_card', 'generate') 170 if '[' in process: 171 logger.warning("Remember that the reweighting is performed at Leading Order. NLO precision is not guarantee.") 172 173 if not process: 174 msg = 'Invalid proc_card information in the file (no generate line):\n %s' % self.banner['mg5proccard'] 175 raise Exception, msg 176 process, option = mg_interface.MadGraphCmd.split_process_line(process) 177 self.proc_option = option 178 179 logger.info("process: %s" % process) 180 logger.info("options: %s" % option)
181 182
183 - def get_LO_definition_from_NLO(self, proc):
184 """return the LO definitions of the process corresponding to the born/real""" 185 186 # split the line definition with the part before and after the NLO tag 187 process, order, final = re.split('\[\s*(.*)\s*\]', proc) 188 # add the part without any additional jet. 189 commandline="add process %s %s --no_warning=duplicate;" % (process, final) 190 if not order: 191 #NO NLO tag => nothing to do actually return input 192 return proc 193 elif not order.startswith(('virt=','loonly=','noborn=')): 194 # OK this a standard NLO process 195 if '=' in order: 196 # get the type NLO QCD/QED/... 197 order = order.split('=',1)[1] 198 199 # define the list of particles that are needed for the radiation 200 pert = fks_common.find_pert_particles_interactions(self.model, 201 pert_order = order)['soft_particles'] 202 commandline += "define pert_%s = %s;" % (order.replace(' ',''), ' '.join(map(str,pert)) ) 203 204 # check if we have to increase by one the born order 205 if '%s=' % order in process: 206 result=re.split(' ',process) 207 process='' 208 for r in result: 209 if '%s=' % order in r: 210 ior=re.split('=',r) 211 r='QCD=%i' % (int(ior[1])+1) 212 process=process+r+' ' 213 #handle special tag $ | / @ 214 result = re.split('([/$@]|\w+=\w+)', process, 1) 215 if len(result) ==3: 216 process, split, rest = result 217 commandline+="add process %s pert_%s %s%s %s --no_warning=duplicate;" % (process, order.replace(' ','') ,split, rest, final) 218 else: 219 commandline +='add process %s pert_%s %s --no_warning=duplicate;' % (process,order.replace(' ',''), final) 220 elif order.startswith(('noborn=')): 221 # pass in sqrvirt= 222 return "add process %s " % proc.replace('noborn=', 'sqrvirt=') 223 224 else: 225 #just return the input. since this Madloop. 226 return "add process %s " % proc 227 return commandline
228 229
230 - def check_events(self):
231 """Check some basic property of the events file""" 232 233 sum_of_weight = 0 234 sum_of_abs_weight = 0 235 negative_event = 0 236 positive_event = 0 237 238 start = time.time() 239 for event_nb,event in enumerate(self.lhe_input): 240 #control logger 241 if (event_nb % max(int(10**int(math.log10(float(event_nb)+1))),10)==0): 242 running_time = misc.format_timer(time.time()-start) 243 logger.info('Event nb %s %s' % (event_nb, running_time)) 244 if (event_nb==10001): logger.info('reducing number of print status. Next status update in 10000 events') 245 246 try: 247 event.check() #check 4 momenta/... 248 except Exception, error: 249 print event 250 raise error 251 sum_of_weight += event.wgt 252 sum_of_abs_weight += abs(event.wgt) 253 if event.wgt < 0 : 254 negative_event +=1 255 else: 256 positive_event +=1 257 258 logger.info("total cross-section: %s" % sum_of_weight) 259 logger.info("total abs cross-section: %s" % sum_of_abs_weight) 260 logger.info("fraction of negative event %s", negative_event/(negative_event+positive_event)) 261 logger.info("total number of events %s", (negative_event+positive_event)) 262 logger.info("negative event %s", negative_event)
263 264 265 266 267 @extended_cmd.debug()
268 - def complete_import(self, text, line, begidx, endidx):
269 "Complete the import command" 270 271 args=self.split_arg(line[0:begidx]) 272 273 if len(args) == 1: 274 base_dir = '.' 275 else: 276 base_dir = args[1] 277 278 return self.path_completion(text, base_dir) 279 280 # Directory continuation 281 if os.path.sep in args[-1] + text: 282 return self.path_completion(text, 283 pjoin(*[a for a in args if \ 284 a.endswith(os.path.sep)]))
285
286 - def help_change(self):
287 """help for change command""" 288 289 print "change model X :use model X for the reweighting" 290 print "change process p p > e+ e-: use a new process for the reweighting" 291 print "change process p p > mu+ mu- --add : add one new process to existing ones"
292
293 - def do_change(self, line):
294 """allow to define a second model/processes""" 295 296 global nb_f2py_module 297 298 args = self.split_arg(line) 299 if len(args)<2: 300 logger.critical("not enough argument (need at least two). Discard line") 301 if args[0] == "model": 302 nb_f2py_module += 1 # tag to force the f2py to reload 303 self.second_model = " ".join(args[1:]) 304 if self.has_standalone_dir: 305 self.terminate_fortran_executables() 306 self.has_standalone_dir = False 307 elif args[0] == "process": 308 nb_f2py_module += 1 309 if self.has_standalone_dir: 310 self.terminate_fortran_executables() 311 self.has_standalone_dir = False 312 if args[-1] == "--add": 313 self.second_process.append(" ".join(args[1:-1])) 314 else: 315 self.second_process = [" ".join(args[1:])] 316 elif args[0] == "output": 317 if args[1] in ['default', '2.0', 'unweight']: 318 self.output_type = args[1] 319 elif args[0] == "helicity": 320 self.helicity_reweighting = banner.ConfigFile.format_variable(args[1], bool, "helicity") 321 elif args[0] == "rwgt_dir": 322 self.rwgt_dir = args[1] 323 if not os.path.exists(self.rwgt_dir): 324 os.mkdir(self.rwgt_dir) 325 else: 326 logger.critical("unknown option! %s. Discard line." % args[0])
327 328
329 - def check_launch(self, args):
330 """check the validity of the launch command""" 331 332 if not self.lhe_input: 333 if isinstance(self.lhe_input, lhe_parser.EventFile): 334 self.lhe_input = lhe_parser.EventFile(self.lhe_input.name) 335 else: 336 raise self.InvalidCmd("No events files defined.")
337
338 - def help_launch(self):
339 """help for the launch command""" 340 341 logger.info('''Add to the loaded events a weight associated to a 342 new param_card (to be define). The weight returned is the ratio of the 343 square matrix element by the squared matrix element of production. 344 All scale are kept fix for this re-weighting.''')
345 346 347 #@misc.mute_logger()
348 - def do_launch(self, line):
349 """end of the configuration launched the code""" 350 351 args = self.split_arg(line) 352 self.check_launch(args) 353 354 model_line = self.banner.get('proc_card', 'full_model_line') 355 356 if not self.has_standalone_dir: 357 if self.rwgt_dir and os.path.exists(pjoin(self.rwgt_dir,'rw_me','rwgt.pkl')): 358 self.load_from_pickle() 359 self.me_dir = self.rwgt_dir 360 else: 361 self.create_standalone_directory() 362 363 if self.rwgt_dir: 364 path_me =self.rwgt_dir 365 else: 366 path_me = self.me_dir 367 368 if self.second_model or self.second_process: 369 rw_dir = pjoin(path_me, 'rw_me_second') 370 else: 371 rw_dir = pjoin(path_me, 'rw_me') 372 373 if not '--keep_card' in args: 374 ff = open(pjoin(rw_dir,'Cards', 'param_card.dat'), 'w') 375 ff.write(self.banner['slha']) 376 ff.close() 377 ff = open(pjoin(path_me, 'rw_me','Cards', 'param_card_orig.dat'), 'w') 378 ff.write(self.banner['slha']) 379 ff.close() 380 cmd = common_run_interface.CommonRunCmd.ask_edit_card_static(cards=['param_card.dat'], 381 ask=self.ask, pwd=rw_dir, first_cmd=self.stored_line) 382 self.stored_line = None 383 384 # check for potential scan in the new card 385 new_card = open(pjoin(rw_dir, 'Cards', 'param_card.dat')).read() 386 pattern_scan = re.compile(r'''^[\s\d]*scan''', re.I+re.M) 387 param_card_iterator = [] 388 if pattern_scan.search(new_card): 389 if not isinstance(self.mother, cmd.CmdShell): 390 raise Exception, "scan are not allowed on the Web" 391 # at least one scan parameter found. create an iterator to go trough the cards 392 main_card = check_param_card.ParamCardIterator(new_card) 393 394 param_card_iterator = main_card 395 first_card = param_card_iterator.next(autostart=True) 396 new_card = first_card.write() 397 first_card.write(pjoin(rw_dir, 'Cards', 'param_card.dat')) 398 # check if "Auto" is present for a width parameter 399 if "auto" in new_card.lower(): 400 self.mother.check_param_card(pjoin(rw_dir, 'Cards', 'param_card.dat')) 401 new_card = open(pjoin(rw_dir, 'Cards', 'param_card.dat')).read() 402 403 # Find new tag in the banner and add information if needed 404 if 'initrwgt' in self.banner: 405 if 'type=\'mg_reweighting\'' in self.banner['initrwgt']: 406 blockpat = re.compile(r'''<weightgroup type=\'mg_reweighting\'\s*>(?P<text>.*?)</weightgroup>''', re.I+re.M+re.S) 407 before, content, after = blockpat.split(self.banner['initrwgt']) 408 header_rwgt_other = before + after 409 pattern = re.compile('<weight id=\'mg_reweight_(?P<id>\d+)\'>(?P<info>[^<]*)</weight>', re.S+re.I+re.M) 410 mg_rwgt_info = pattern.findall(content) 411 maxid = 0 412 for i, diff in mg_rwgt_info: 413 if int(i) > maxid: 414 maxid = int(i) 415 maxid += 1 416 rewgtid = maxid 417 else: 418 header_rwgt_other = self.banner['initrwgt'] 419 mg_rwgt_info = [] 420 rewgtid = 1 421 else: 422 self.banner['initrwgt'] = '' 423 header_rwgt_other = '' 424 mg_rwgt_info = [] 425 rewgtid = 1 426 427 # add the reweighting in the banner information: 428 #starts by computing the difference in the cards. 429 s_orig = self.banner['slha'] 430 s_new = new_card 431 if not self.second_model: 432 old_param = check_param_card.ParamCard(s_orig.splitlines()) 433 new_param = check_param_card.ParamCard(s_new.splitlines()) 434 card_diff = old_param.create_diff(new_param) 435 if card_diff == '' and not self.second_process: 436 logger.warning(' REWEIGHTING: original card and new card are identical. Bypass this run') 437 return 438 #raise self.InvalidCmd, 'original card and new card are identical' 439 try: 440 if old_param['sminputs'].get(3)- new_param['sminputs'].get(3) > 1e-3 * new_param['sminputs'].get(3): 441 logger.warning("We found different value of alpha_s. Note that the value of alpha_s used is the one associate with the event and not the one from the cards.") 442 except Exception, error: 443 logger.debug("error in check of alphas: %s" % str(error)) 444 pass #this is a security 445 if not self.second_process: 446 mg_rwgt_info.append((str(rewgtid), card_diff)) 447 else: 448 str_proc = "\n change process ".join([""]+self.second_process) 449 mg_rwgt_info.append((str(rewgtid), str_proc + '\n'+ card_diff)) 450 else: 451 str_info = "change model %s" % self.second_model 452 if self.second_process: 453 str_info += "\n change process ".join([""]+self.second_process) 454 card_diff = str_info 455 str_info += '\n' + s_new 456 mg_rwgt_info.append((str(rewgtid), str_info)) 457 458 # re-create the banner. 459 self.banner['initrwgt'] = header_rwgt_other 460 self.banner['initrwgt'] += '\n<weightgroup type=\'mg_reweighting\'>\n' 461 for tag, diff in mg_rwgt_info: 462 self.banner['initrwgt'] += '<weight id=\'mg_reweight_%s\'>%s</weight>\n' % \ 463 (tag, diff) 464 self.banner['initrwgt'] += '\n</weightgroup>\n' 465 self.banner['initrwgt'] = self.banner['initrwgt'].replace('\n\n', '\n') 466 467 output = open( self.lhe_input.name +'rw', 'w') 468 469 470 logger.info('starts to compute weight for events with the following modification to the param_card:') 471 logger.info(card_diff) 472 473 #write the banner to the output file 474 self.banner.write(output, close_tag=False) 475 # prepare the output file for the weight plot 476 if self.mother: 477 out_path = pjoin(self.mother.me_dir, 'Events', 'reweight.lhe') 478 output2 = open(out_path, 'w') 479 lha_strategy = self.banner.get_lha_strategy() 480 self.banner.set_lha_strategy(4*lha_strategy/abs(lha_strategy)) 481 self.banner.write(output2, close_tag=False) 482 self.banner.set_lha_strategy(lha_strategy) 483 new_banner = banner.Banner(self.banner) 484 if not hasattr(self, 'run_card'): 485 self.run_card = new_banner.charge_card('run_card') 486 self.run_card['run_tag'] = 'reweight_%s' % rewgtid 487 new_banner['slha'] = s_new 488 del new_banner['initrwgt'] 489 assert 'initrwgt' in self.banner 490 ff = open(pjoin(self.mother.me_dir,'Events',self.mother.run_name, '%s_%s_banner.txt' % \ 491 (self.mother.run_name, self.run_card['run_tag'])),'w') 492 new_banner.write(ff) 493 ff.close() 494 495 # Loop over all events 496 tag_name = 'mg_reweight_%s' % rewgtid 497 start = time.time() 498 cross = 0 499 ratio, ratio_square = 0, 0 # to compute the variance and associate error 500 501 os.environ['GFORTRAN_UNBUFFERED_ALL'] = 'y' 502 if self.lhe_input.closed: 503 misc.sprint("using", self.lhe_input.name) 504 self.lhe_input = lhe_parser.EventFile(self.lhe_input.name) 505 506 # Multicore option not really stable -> not use it 507 nb_core = 1 508 # if nb_core >1: 509 # multicore = cluster.MultiCore(nb_core) 510 511 self.lhe_input.seek(0) 512 for event_nb,event in enumerate(self.lhe_input): 513 #control logger 514 if (event_nb % max(int(10**int(math.log10(float(event_nb)+1))),10)==0): 515 running_time = misc.format_timer(time.time()-start) 516 logger.info('Event nb %s %s' % (event_nb, running_time)) 517 if (event_nb==10001): logger.info('reducing number of print status. Next status update in 10000 events') 518 519 if nb_core > 1: 520 # Multicore option not really stable -> not use it 521 while 1: 522 if multicore.queue.qsize() < 100 * nb_core: 523 multicore.submit(self.write_reweighted_event, argument=[event, tag_name]) 524 break 525 #else: 526 # time.sleep(0.001) 527 continue 528 else: 529 weight = self.calculate_weight(event) 530 cross += weight 531 ratio += weight/event.wgt 532 ratio_square += (weight/event.wgt)**2 533 if self.output_type == "default": 534 event.reweight_data[tag_name] = weight 535 #write this event with weight 536 output.write(str(event)) 537 if self.mother: 538 event.wgt = weight 539 event.reweight_data = {} 540 output2.write(str(event)) 541 542 else: 543 event.wgt = weight 544 event.reweight_data = {} 545 if self.mother: 546 output2.write(str(event)) 547 else: 548 output.write(str(event)) 549 550 # check normalisation of the events: 551 if 'event_norm' in self.run_card: 552 if self.run_card['event_norm'] == 'average': 553 cross /= event_nb+1 554 555 556 running_time = misc.format_timer(time.time()-start) 557 logger.info('All event done (nb_event: %s) %s' % (event_nb+1, running_time)) 558 559 output.write('</LesHouchesEvents>\n') 560 output.close() 561 os.environ['GFORTRAN_UNBUFFERED_ALL'] = 'n' 562 if self.mother: 563 output2.write('</LesHouchesEvents>\n') 564 output2.close() 565 # add output information 566 if hasattr(self.mother, 'results'): 567 run_name = self.mother.run_name 568 results = self.mother.results 569 results.add_run(run_name, self.run_card, current=True) 570 results.add_detail('nb_event', event_nb+1) 571 results.add_detail('cross', cross) 572 event_nb +=1 573 variance = ratio_square/event_nb - (ratio/event_nb)**2 574 orig_cross, orig_error = self.orig_cross 575 error = variance/math.sqrt(event_nb) * orig_cross + ratio/event_nb * orig_error 576 577 results.add_detail('error', error) 578 self.mother.create_plot(mode='reweight', event_path=output2.name, 579 tag=self.run_card['run_tag']) 580 #modify the html output to add the original run 581 if 'plot' in results.current.reweight: 582 html_dir = pjoin(self.mother.me_dir, 'HTML', run_name) 583 td = pjoin(self.mother.options['td_path'], 'td') 584 MA = pjoin(self.mother.options['madanalysis_path']) 585 path1 = pjoin(html_dir, 'plots_parton') 586 path2 = pjoin(html_dir, 'plots_%s' % self.run_card['run_tag']) 587 outputplot = path2 588 combine_plots.merge_all_plots(path2, path1, outputplot, td, MA) 589 #results.update_status(level='reweight') 590 #results.update(status, level, makehtml=True, error=False) 591 592 #old_name = self.mother.results.current['run_name'] 593 #new_run = '%s_rw_%s' % (old_name, rewgtid) 594 #self.mother.results.add_run( new_run, self.run_card) 595 #self.mother.results.add_detail('nb_event', event_nb+1) 596 #self.mother.results.add_detail('cross', cross) 597 #self.mother.results.add_detail('error', 'nan') 598 #self.mother.do_plot('%s -f' % new_run) 599 #self.mother.update_status('Reweight %s done' % rewgtid, 'madspin') 600 #self.mother.results.def_current(old_name) 601 #self.run_card['run_tag'] = self.run_card['run_tag'][9:] 602 #self.mother.run_name = old_name 603 self.lhe_input.close() 604 if not self.mother or self.output_type != "default" : 605 target = pjoin(self.mother.me_dir, 'Events', run_name, 'events.lhe') 606 else: 607 target = self.lhe_input.name 608 609 if self.output_type == "default": 610 files.mv(output.name, target) 611 elif self.output_type == "unweight": 612 output2.close() 613 lhe = lhe_parser.EventFile(output2.name) 614 nb_event = lhe.unweight(target) 615 if self.mother and hasattr(self.mother, 'results'): 616 results = self.mother.results 617 results.add_detail('nb_event', nb_event) 618 results.current.parton.append('lhe') 619 620 else: 621 files.mv(output2.name, self.lhe_input.name) 622 if self.mother and hasattr(self.mother, 'results'): 623 results = self.mother.results 624 results.current.parton.append('lhe') 625 626 logger.info('Event %s have now the additional weight' % self.lhe_input.name) 627 logger.info('new cross-section is : %g pb (indicative error: %g pb)' % (cross,error)) 628 self.terminate_fortran_executables(new_card_only=True) 629 #store result 630 self.all_cross_section[rewgtid] = (cross, error) 631 632 # perform the scanning 633 if param_card_iterator: 634 for card in param_card_iterator: 635 card.write(pjoin(rw_dir, 'Cards', 'param_card.dat')) 636 self.exec_cmd("launch --keep_card", printcmd=False, precmd=True)
637 638
639 - def do_set(self, line):
640 "Not in help" 641 642 logger.warning("Invalid Syntax. The command 'set' should be placed after the 'launch' one. Continuing by adding automatically 'launch'") 643 self.stored_line = "set %s" % line 644 return self.exec_cmd("launch")
645
646 - def default(self, line, log=True):
647 """Default action if line is not recognized""" 648 649 if os.path.isfile(line): 650 if log: 651 logger.warning("Invalid Syntax. The path to a param_card' should be placed after the 'launch' command. Continuing by adding automatically 'launch'") 652 self.stored_line = line 653 return self.exec_cmd("launch") 654 else: 655 return super(ReweightInterface,self).default(line, log=log)
656
657 - def write_reweighted_event(self, event, tag_name, **opt):
658 """a function for running in multicore""" 659 660 if not hasattr(opt['thread_space'], "calculator"): 661 opt['thread_space'].calculator = {} 662 opt['thread_space'].calculator_nbcall = {} 663 opt['thread_space'].cross = 0 664 opt['thread_space'].output = open( self.lhe_input.name +'rw.%s' % opt['thread_id'], 'w') 665 if self.mother: 666 out_path = pjoin(self.mother.me_dir, 'Events', 'reweight.lhe.%s' % opt['thread_id']) 667 opt['thread_space'].output2 = open(out_path, 'w') 668 669 weight = self.calculate_weight(event, space=opt['thread_space']) 670 opt['thread_space'].cross += weight 671 if self.output_type == "default": 672 event.reweight_data[tag_name] = weight 673 #write this event with weight 674 opt['thread_space'].output.write(str(event)) 675 if self.mother: 676 event.wgt = weight 677 event.reweight_data = {} 678 opt['thread_space'].output2.write(str(event)) 679 else: 680 event.wgt = weight 681 event.reweight_data = {} 682 if self.mother: 683 opt['thread_space'].output2.write(str(event)) 684 else: 685 opt['thread_space'].output.write(str(event)) 686 687 return 0
688
689 - def calculate_weight(self, event, space=None):
690 """space defines where to find the calculator (in multicore)""" 691 692 if not space: 693 space = self 694 695 event.parse_reweight() 696 697 w_orig = self.calculate_matrix_element(event, 0, space) 698 w_new = self.calculate_matrix_element(event, 1, space) 699 if w_orig == 0: 700 tag, order = event.get_tag_and_order() 701 orig_order, Pdir, hel_dict = self.id_to_path[tag] 702 misc.sprint(w_orig, w_new) 703 misc.sprint(event) 704 raise Exception, "Invalid matrix element for original computation (weight=0)" 705 return w_new/w_orig*event.wgt
706 707 @staticmethod
708 - def invert_momenta(p):
709 """ fortran/C-python do not order table in the same order""" 710 new_p = [] 711 for i in range(len(p[0])): new_p.append([0]*len(p)) 712 for i, onep in enumerate(p): 713 for j, x in enumerate(onep): 714 new_p[j][i] = x 715 return new_p
716 717 @staticmethod
718 - def rename_f2py_lib(Pdir, tag):
719 if tag == 2: 720 return 721 if os.path.exists(pjoin(Pdir, 'matrix%spy.so' % tag)): 722 return 723 else: 724 open(pjoin(Pdir, 'matrix%spy.so' % tag),'w').write(open(pjoin(Pdir, 'matrix2py.so') 725 ).read().replace('matrix2py', 'matrix%spy' % tag))
726
727 - def calculate_matrix_element(self, event, hypp_id, space):
728 """routine to return the matrix element""" 729 730 tag, order = event.get_tag_and_order() 731 732 if (not self.second_model and not self.second_process) or hypp_id==0: 733 orig_order, Pdir, hel_dict = self.id_to_path[tag] 734 else: 735 orig_order, Pdir, hel_dict = self.id_to_path_second[tag] 736 737 run_id = (tag, hypp_id) 738 739 740 assert space == self 741 start = False 742 if run_id in space.calculator: 743 external = space.calculator[run_id] 744 elif (not self.second_model and not self.second_process) or hypp_id==0: 745 # create the executable for this param_card 746 subdir = pjoin(self.me_dir,'rw_me ', 'SubProcesses') 747 if self.me_dir not in sys.path: 748 sys.path.insert(0,self.me_dir) 749 if self.rwgt_dir and self.rwgt_dir not in sys.path: 750 sys.path.insert(0,self.rwgt_dir) 751 Pname = os.path.basename(Pdir) 752 if hypp_id == 0: 753 if (Pdir, 0) not in dir_to_f2py_free_mod: 754 metag = 1 755 dir_to_f2py_free_mod[(Pdir,0)] = (metag, nb_f2py_module) 756 else: 757 metag, old_module = dir_to_f2py_free_mod[(Pdir,0)] 758 if old_module != nb_f2py_module: 759 metag += 1 760 dir_to_f2py_free_mod[(Pdir,0)] = (metag, nb_f2py_module) 761 762 os.environ['MENUM'] = '2' 763 if not self.rwgt_dir or not os.path.exists(pjoin(Pdir, 'matrix2py.so')): 764 misc.compile(['matrix2py.so'], cwd=Pdir) 765 self.rename_f2py_lib(Pdir, 2*metag) 766 767 mymod = __import__('rw_me.SubProcesses.%s.matrix%spy' % (Pname, 2*metag), globals(), locals(), [],-1) 768 S = mymod.SubProcesses 769 P = getattr(S, Pname) 770 mymod = getattr(P, 'matrix%spy' % (2*metag)) 771 with misc.chdir(Pdir): 772 mymod.initialise('param_card_orig.dat') 773 774 if hypp_id == 1: 775 #incorrect line 776 metag = dir_to_f2py_free_mod[(Pdir,0)][0] 777 newtag = 2*metag+1 778 self.rename_f2py_lib(Pdir, newtag) 779 try: 780 mymod = __import__('rw_me.SubProcesses.%s.matrix%spy' % (Pname, newtag), globals(), locals(), [],-1) 781 except Exception, error: 782 os.remove(pjoin(Pdir, 'matrix%spy.so' % newtag)) 783 newtag = "L%s" % newtag 784 os.environ['MENUM'] = newtag 785 misc.compile(['matrix%spy.so' % newtag], cwd=Pdir) 786 mymod = __import__('rw_me.SubProcesses.%s.matrix%spy' % (Pname, newtag), globals(), locals(), [],-1) 787 788 S = mymod.SubProcesses 789 P = getattr(S, Pname) 790 mymod = getattr(P, 'matrix%spy' % newtag) 791 with misc.chdir(Pdir): 792 mymod.initialise('param_card.dat') 793 space.calculator[run_id] = mymod.get_me 794 external = space.calculator[run_id] 795 else: 796 subdir = pjoin(self.me_dir,'rw_me_second', 'SubProcesses') 797 if self.me_dir not in sys.path: 798 sys.path.append(self.me_dir) 799 800 assert hypp_id == 1 801 Pname = os.path.basename(Pdir) 802 os.environ['MENUM'] = '2' 803 if not self.rwgt_dir or not os.path.exists(pjoin(Pdir, 'matrix2py.so')): 804 misc.compile(['matrix2py.so'], cwd=pjoin(subdir, Pdir)) 805 if (Pdir, 1) not in dir_to_f2py_free_mod: 806 metag = 1 807 dir_to_f2py_free_mod[(Pdir,1)] = (metag, nb_f2py_module) 808 else: 809 metag, old_module = dir_to_f2py_free_mod[(Pdir,1)] 810 if old_module != nb_f2py_module: 811 metag += 1 812 dir_to_f2py_free_mod[(Pdir,1)] = (metag, nb_f2py_module) 813 self.rename_f2py_lib(Pdir, metag) 814 815 try: 816 mymod = __import__("rw_me_second.SubProcesses.%s.matrix%spy" % (Pname, metag)) 817 except ImportError: 818 os.remove(pjoin(Pdir, 'matrix%spy.so' % metag )) 819 metag = "L%s" % metag 820 os.environ['MENUM'] = str(metag) 821 misc.compile(['matrix%spy.so' % metag], cwd=pjoin(subdir, Pdir)) 822 mymod = __import__("rw_me_second.SubProcesses.%s.matrix%spy" % (Pname, metag)) 823 reload(mymod) 824 S = mymod.SubProcesses 825 P = getattr(S, Pname) 826 mymod = getattr(P, 'matrix%spy' % metag) 827 with misc.chdir(Pdir): 828 mymod.initialise('param_card.dat') 829 space.calculator[run_id] = mymod.get_me 830 external = space.calculator[run_id] 831 832 833 p = self.invert_momenta(event.get_momenta(orig_order)) 834 # add helicity information 835 836 hel_order = event.get_helicity(orig_order) 837 if self.helicity_reweighting and 9 not in hel_order: 838 nhel = hel_dict[tuple(hel_order)] 839 else: 840 nhel = 0 841 842 with misc.chdir(Pdir): 843 with misc.stdchannel_redirected(sys.stdout, os.devnull): 844 me_value = external(p,event.aqcd, nhel) 845 # for NLO we have also the stability status code 846 if isinstance(me_value, tuple): 847 me_value, code = me_value 848 #if code points unstability -> returns 0 849 hundred_value = (code % 1000) //100 850 if hundred_value in [4]: 851 me_value = 0. 852 853 return me_value
854
855 - def terminate_fortran_executables(self, new_card_only=False):
856 """routine to terminate all fortran executables""" 857 858 for (mode, production) in dict(self.calculator): 859 860 if new_card_only and production == 0: 861 continue 862 del self.calculator[(mode, production)]
863
864 - def do_quit(self, line):
865 866 867 if 'init' in self.banner: 868 cross = 0 869 error = 0 870 for line in self.banner['init'].split('\n'): 871 split = line.split() 872 if len(split) == 4: 873 cross, error = float(split[0]), float(split[1]) 874 logger.info('Original cross-section: %s +- %s pb' % (cross, error)) 875 876 logger.info('Computed cross-section:') 877 keys = self.all_cross_section.keys() 878 keys.sort() 879 for key in keys: 880 logger.info('%s : %s +- %s pb' % (key,self.all_cross_section[key][0],self.all_cross_section[key][1] )) 881 self.terminate_fortran_executables() 882 883 if self.rwgt_dir: 884 self.save_to_pickle()
885
886 - def __del__(self):
887 self.do_quit('')
888 889
890 - def adding_me(self, matrix_elements, path):
891 """Adding one element to the list based on the matrix element"""
892 893 894 895 896 897 898 @misc.mute_logger()
899 - def create_standalone_directory(self, second=False):
900 """generate the various directory for the weight evaluation""" 901 902 # 0. clean previous run ------------------------------------------------ 903 if not self.rwgt_dir: 904 path_me = self.me_dir 905 else: 906 path_me = self.rwgt_dir 907 try: 908 shutil.rmtree(pjoin(path_me,'rw_me')) 909 except Exception: 910 pass 911 912 # 1. Load model--------------------------------------------------------- 913 complex_mass = False 914 has_cms = re.compile(r'''set\s+complex_mass_scheme\s*(True|T|1|true|$|;)''') 915 for line in self.banner.proc_card: 916 if line.startswith('set'): 917 self.mg5cmd.exec_cmd(line, printcmd=False, precmd=False, postcmd=False) 918 if has_cms.search(line): 919 complex_mass = True 920 elif line.startswith('define'): 921 try: 922 self.mg5cmd.exec_cmd(line, printcmd=False, precmd=False, postcmd=False) 923 except Exception: 924 pass 925 926 info = self.banner.get('proc_card', 'full_model_line') 927 if '-modelname' in info: 928 mg_names = False 929 else: 930 mg_names = True 931 model_name = self.banner.get('proc_card', 'model') 932 if model_name: 933 self.load_model(model_name, mg_names, complex_mass) 934 else: 935 raise self.InvalidCmd('Only UFO model can be loaded in this module.') 936 937 mgcmd = self.mg5cmd 938 modelpath = self.model.get('modelpath') 939 if os.path.basename(modelpath) != mgcmd._curr_model['name']: 940 name, restrict = mgcmd._curr_model['name'].rsplit('-',1) 941 if os.path.exists(pjoin(os.path.dirname(modelpath),name, 'restrict_%s.dat' % restrict)): 942 modelpath = pjoin(os.path.dirname(modelpath), mgcmd._curr_model['name']) 943 944 commandline="import model %s " % modelpath 945 mgcmd.exec_cmd(commandline) 946 947 #multiparticles 948 for name, content in self.banner.get('proc_card', 'multiparticles'): 949 mgcmd.exec_cmd("define %s = %s" % (name, content)) 950 951 # 2. compute the production matrix element ----------------------------- 952 processes = [line[9:].strip() for line in self.banner.proc_card 953 if line.startswith('generate')] 954 processes += [' '.join(line.split()[2:]) for line in self.banner.proc_card 955 if re.search('^\s*add\s+process', line)] 956 mgcmd.exec_cmd("set group_subprocesses False") 957 958 logger.info('generating the square matrix element for reweighting') 959 start = time.time() 960 commandline='' 961 for proc in processes: 962 if '[' not in proc: 963 commandline += "add process %s ;" % proc 964 else: 965 commandline += self.get_LO_definition_from_NLO(proc) 966 967 commandline = commandline.replace('add process', 'generate',1) 968 logger.info(commandline) 969 mgcmd.exec_cmd(commandline, precmd=True) 970 commandline = 'output standalone_rw %s' % pjoin(path_me,'rw_me') 971 mgcmd.exec_cmd(commandline, precmd=True) 972 logger.info('Done %.4g' % (time.time()-start)) 973 self.has_standalone_dir = True 974 975 976 # 3. Store id to directory information --------------------------------- 977 matrix_elements = mgcmd._curr_matrix_elements.get_matrix_elements() 978 979 self.id_to_path = {} 980 for me in matrix_elements: 981 for proc in me.get('processes'): 982 initial = [] #filled in the next line 983 final = [l.get('id') for l in proc.get('legs')\ 984 if l.get('state') or initial.append(l.get('id'))] 985 order = (initial, final) 986 tag = proc.get_initial_final_ids() 987 decay_finals = proc.get_final_ids_after_decay() 988 989 if tag[1] != decay_finals: 990 order = (initial, list(decay_finals)) 991 decay_finals.sort() 992 tag = (tag[0], tuple(decay_finals)) 993 Pdir = pjoin(path_me, 'rw_me', 'SubProcesses', 994 'P%s' % me.get('processes')[0].shell_string()) 995 assert os.path.exists(Pdir), "Pdir %s do not exists" % Pdir 996 if tag in self.id_to_path: 997 if not Pdir == self.id_to_path[tag][1]: 998 misc.sprint(tag, Pdir, self.id_to_path[tag][1]) 999 raise self.InvalidCmd, '2 different process have the same final states. This module can not handle such situation' 1000 else: 1001 continue 1002 # build the helicity dictionary 1003 hel_nb = 0 1004 hel_dict = {9:0} # unknown helicity -> use full ME 1005 for helicities in me.get_helicity_matrix(): 1006 hel_nb +=1 #fortran starts at 1 1007 hel_dict[tuple(helicities)] = hel_nb 1008 1009 self.id_to_path[tag] = [order, Pdir, hel_dict] 1010 1011 # 3. If we need a new model/process------------------------------------- 1012 if self.second_model or self.second_process: 1013 self.create_second_standalone_directory()
1014 1015 @misc.mute_logger()
1016 - def create_second_standalone_directory(self, second=False):
1017 """generate the various directory for the weight evaluation""" 1018 1019 # 0. clean previous run ------------------------------------------------ 1020 path_me = self.me_dir 1021 try: 1022 shutil.rmtree(pjoin(path_me,'rw_me_second')) 1023 except Exception: 1024 pass 1025 1026 mgcmd = self.mg5cmd 1027 # 1. Load model--------------------------------------------------------- 1028 if self.second_model: 1029 use_mgdefault= True 1030 complex_mass = False 1031 if ' ' in self.second_model: 1032 args = self.second_model.split() 1033 if '--modelname' in args: 1034 use_mgdefault = False 1035 model_name = args[0] 1036 else: 1037 model_name = self.second_model 1038 self.load_model(model_name, use_mgdefault, complex_mass) 1039 1040 modelpath = self.model.get('modelpath') 1041 if os.path.basename(modelpath) != mgcmd._curr_model['name']: 1042 name, restrict = mgcmd._curr_model['name'].rsplit('-',1) 1043 if os.path.exists(pjoin(os.path.dirname(modelpath),name, 'restrict_%s.dat' % restrict)): 1044 modelpath = pjoin(os.path.dirname(modelpath), mgcmd._curr_model['name']) 1045 1046 commandline="import model %s " % modelpath 1047 if not use_mgdefault: 1048 commandline += ' -modelname ' 1049 mgcmd.exec_cmd(commandline) 1050 1051 # 2. compute the production matrix element ----------------------------- 1052 if self.second_process: 1053 processes = self.second_process 1054 else: 1055 processes = [line[9:].strip() for line in self.banner.proc_card 1056 if line.startswith('generate')] 1057 processes += [' '.join(line.split()[2:]) for line in self.banner.proc_card 1058 if re.search('^\s*add\s+process', line)] 1059 mgcmd.exec_cmd("set group_subprocesses False") 1060 1061 logger.info('generating the square matrix element for reweighting') 1062 start = time.time() 1063 commandline='' 1064 for proc in processes: 1065 if '[' not in proc: 1066 commandline+="add process %s ;" % proc 1067 elif 'sqrvirt' in proc: 1068 commandline+="add process %s ;" % proc 1069 else: 1070 raise self.InvalidCmd('NLO processes can\'t be reweight (for Loop induced reweighting use [sqrvirt =])') 1071 1072 commandline = commandline.replace('add process', 'generate',1) 1073 logger.info(commandline) 1074 mgcmd.exec_cmd(commandline, precmd=True) 1075 1076 matrix_elements = mgcmd._curr_matrix_elements.get_matrix_elements() 1077 1078 commandline = 'output standalone_rw %s' % pjoin(path_me,'rw_me_second') 1079 mgcmd.exec_cmd(commandline, precmd=True) 1080 logger.info('Done %.4g' % (time.time()-start)) 1081 1082 # 3. Store id to directory information --------------------------------- 1083 matrix_elements = mgcmd._curr_matrix_elements.get_matrix_elements() 1084 1085 self.id_to_path_second = {} 1086 to_check = [] # list of tag that do not have a Pdir at creation time. 1087 for me in matrix_elements: 1088 for proc in me.get('processes'): 1089 initial = [] #filled in the next line 1090 final = [l.get('id') for l in proc.get('legs')\ 1091 if l.get('state') or initial.append(l.get('id'))] 1092 order = (initial, final) 1093 tag = proc.get_initial_final_ids() 1094 decay_finals = proc.get_final_ids_after_decay() 1095 1096 if tag[1] != decay_finals: 1097 order = (initial, list(decay_finals)) 1098 decay_finals.sort() 1099 tag = (tag[0], tuple(decay_finals)) 1100 Pdir = pjoin(path_me, 'rw_me_second', 'SubProcesses', 1101 'P%s' % me.get('processes')[0].shell_string()) 1102 if not os.path.exists(Pdir): 1103 to_check.append(tag) 1104 continue 1105 if tag in self.id_to_path_second: 1106 if not Pdir == self.id_to_path_second[tag][1]: 1107 misc.sprint(tag, Pdir, self.id_to_path_second[tag][1]) 1108 raise self.InvalidCmd, '2 different process have the same final states. This module can not handle such situation' 1109 else: 1110 continue 1111 1112 # build the helicity dictionary 1113 hel_nb = 0 1114 hel_dict = {9:0} # unknown helicity -> use full ME 1115 for helicities in me.get_helicity_matrix(): 1116 hel_nb +=1 #fortran starts at 1 1117 hel_dict[tuple(helicities)] = hel_nb 1118 self.id_to_path_second[tag] = [order, Pdir, hel_dict] 1119 1120 for tag in to_check: 1121 if tag not in self.id_to_path: 1122 logger.warning("no valid path for %s" % (tag,)) 1123 #raise self.InvalidCmd, "no valid path for %s" % (tag,) 1124 1125 # 4. Check MadLoopParam 1126 if os.path.exists(pjoin(path_me, 'rw_me_second', 'Cards', 'MadLoopParams.dat')): 1127 MLCard = banner.MadLoopParam(pjoin(path_me, 'rw_me_second', 'Cards', 'MadLoopParams.dat')) 1128 MLCard.set('WriteOutFilters', False) 1129 MLCard.set('UseLoopFilter', False) 1130 MLCard.set("DoubleCheckHelicityFilter", False) 1131 MLCard.set("HelicityFilterLevel", 0) 1132 MLCard.write(pjoin(path_me, 'rw_me_second', 'SubProcesses', 'MadLoopParams.dat'), 1133 pjoin(path_me, 'rw_me_second', 'Cards', 'MadLoopParams.dat'), 1134 commentdefault=False)
1135 1136 1137 1138 1139 1140
1141 - def load_model(self, name, use_mg_default, complex_mass=False):
1142 """load the model""" 1143 1144 loop = False 1145 1146 logger.info('detected model: %s. Loading...' % name) 1147 model_path = name 1148 1149 # Import model 1150 base_model = import_ufo.import_model(name, decay=False, 1151 complex_mass_scheme=complex_mass) 1152 1153 if use_mg_default: 1154 base_model.pass_particles_name_in_mg_default() 1155 1156 self.model = base_model 1157 self.mg5cmd._curr_model = self.model 1158 self.mg5cmd.process_model()
1159 1160
1161 - def save_to_pickle(self):
1162 import madgraph.iolibs.save_load_object as save_load_object 1163 1164 to_save = {} 1165 to_save['id_to_path'] = self.id_to_path 1166 if hasattr(self, 'id_to_path_second'): 1167 to_save['id_to_path_second'] = self.id_to_path_second 1168 else: 1169 to_save['id_to_path_second'] = {} 1170 to_save['all_cross_section'] = self.all_cross_section 1171 to_save['processes'] = self.processes 1172 to_save['second_process'] = self.second_process 1173 if self.second_model: 1174 to_save['second_model'] =True 1175 else: 1176 to_save['second_model'] = None 1177 to_save['rwgt_dir'] = self.rwgt_dir 1178 1179 name = pjoin(self.rwgt_dir, 'rw_me', 'rwgt.pkl') 1180 save_load_object.save_to_file(name, to_save)
1181
1182 - def load_from_pickle(self):
1183 import madgraph.iolibs.save_load_object as save_load_object 1184 1185 obj = save_load_object.load_from_file( pjoin(self.rwgt_dir, 'rw_me', 'rwgt.pkl')) 1186 1187 self.has_standalone_dir = True 1188 self.options = {'curr_dir': os.path.realpath(os.getcwd())} 1189 1190 old_rwgt = obj['rwgt_dir'] 1191 1192 # path to fortran executable 1193 self.id_to_path = {} 1194 for key , (order, Pdir, hel_dict) in obj['id_to_path'].items(): 1195 new_P = Pdir.replace(old_rwgt, self.rwgt_dir) 1196 self.id_to_path[key] = [order, new_P, hel_dict] 1197 1198 # path to fortran executable (for second directory) 1199 self.id_to_path_second = {} 1200 for key , (order, Pdir, hel_dict) in obj['id_to_path_second'].items(): 1201 new_P = Pdir.replace(old_rwgt, self.rwgt_dir) 1202 self.id_to_path_second[key] = [order, new_P, hel_dict] 1203 1204 self.all_cross_section = obj['all_cross_section'] 1205 self.processes = obj['processes'] 1206 self.second_process = obj['second_process'] 1207 self.second_model = obj['second_model']
1208