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