Package madgraph :: Package various :: Module systematics
[hide private]
[frames] | no frames]

Source Code for Module madgraph.various.systematics

  1  ################################################################################ 
  2  # 
  3  # Copyright (c) 2016 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  from __future__ import division 
 16  from __builtin__ import True, False 
 17  if __name__ == "__main__": 
 18      import sys 
 19      import os 
 20      root = os.path.dirname(__file__) 
 21      if os.path.basename(root) == 'internal': 
 22          sys.path.append(os.path.dirname(root)) 
 23      else: 
 24          sys.path.append(os.path.dirname(os.path.dirname(root))) 
 25           
 26  import lhe_parser 
 27  import banner 
 28  import banner as banner_mod 
 29  import itertools 
 30  import misc 
 31  import math 
 32  import os  
 33  import re 
 34  import sys 
 35  import time 
 36  import StringIO 
 37   
 38  pjoin = os.path.join 
 39  root = os.path.dirname(__file__) 
 40   
41 -class SystematicsError(Exception):
42 pass
43
44 -class Systematics(object):
45
46 - def __init__(self, input_file, output_file, 47 start_event=0, stop_event=sys.maxint, write_banner=False, 48 mur=[0.5,1,2], 49 muf=[0.5,1,2], 50 alps=[1], 51 pdf='errorset', #[(id, subset)] 52 dyn=[-1,1,2,3,4], 53 together=[('mur', 'muf', 'dyn')], 54 remove_wgts=[], 55 keep_wgts=[], 56 start_id=None, 57 lhapdf_config=misc.which('lhapdf-config'), 58 log=lambda x: sys.stdout.write(str(x)+'\n') 59 ):
60 61 # INPUT/OUTPUT FILE 62 if isinstance(input_file, str): 63 self.input = lhe_parser.EventFile(input_file) 64 else: 65 self.input = input_file 66 self.output_path = output_file 67 if output_file != None: 68 if isinstance(output_file, str): 69 if output_file == input_file: 70 directory,name = os.path.split(output_file) 71 new_name = pjoin(directory, '.tmp_'+name) 72 self.output = lhe_parser.EventFile(new_name, 'w') 73 else: 74 self.output = lhe_parser.EventFile(output_file, 'w') 75 else: 76 self.output = output_file 77 self.log = log 78 79 #get some information from the run_card. 80 self.banner = banner_mod.Banner(self.input.banner) 81 self.force_write_banner = bool(write_banner) 82 self.orig_dyn = self.banner.get('run_card', 'dynamical_scale_choice') 83 self.orig_pdf = self.banner.run_card.get_lhapdf_id() 84 matching_mode = self.banner.get('run_card', 'ickkw') 85 86 #check for beam 87 beam1, beam2 = self.banner.get_pdg_beam() 88 if abs(beam1) != 2212 and abs(beam2) != 2212: 89 self.b1 = 0 90 self.b2 = 0 91 pdf = 'central' 92 #raise SystematicsError, 'can only reweight proton beam' 93 elif abs(beam1) != 2212: 94 self.b1 = 0 95 self.b2 = beam2//2212 96 elif abs(beam2) != 2212: 97 self.b1 = beam1//2212 98 self.b2 = 0 99 else: 100 self.b1 = beam1//2212 101 self.b2 = beam2//2212 102 103 if isinstance(self.banner.run_card, banner_mod.RunCardLO): 104 self.is_lo = True 105 if not self.banner.run_card['use_syst']: 106 raise SystematicsError, 'The events have not been generated with use_syst=True. Cannot evaluate systematics error on these events.' 107 else: 108 self.is_lo = False 109 if not self.banner.run_card['store_rwgt_info']: 110 raise SystematicsError, 'The events have not been generated with store_rwgt_info=True. Cannot evaluate systematics error on these events.' 111 112 # MUR/MUF/ALPS PARSING 113 if isinstance(mur, str): 114 mur = mur.split(',') 115 self.mur=[float(i) for i in mur] 116 if isinstance(muf, str): 117 muf = muf.split(',') 118 self.muf=[float(i) for i in muf] 119 120 if isinstance(alps, str): 121 alps = alps.split(',') 122 self.alps=[float(i) for i in alps] 123 124 # DYNAMICAL SCALE PARSING + together 125 if isinstance(dyn, str): 126 dyn = dyn.split(',') 127 self.dyn=[int(i) for i in dyn] 128 # For FxFx only mode -1 makes sense 129 if matching_mode == 3: 130 self.dyn = [-1] 131 # avoid sqrts at NLO if ISR is possible 132 if 4 in self.dyn and self.b1 and self.b2 and not self.is_lo: 133 self.dyn.remove(4) 134 135 if isinstance(together, str): 136 self.together = together.split(',') 137 else: 138 self.together = together 139 140 # START/STOP EVENT 141 self.start_event=int(start_event) 142 self.stop_event=int(stop_event) 143 if start_event != 0: 144 self.log( "#starting from event #%s" % start_event) 145 if stop_event != sys.maxint: 146 self.log( "#stopping at event #%s" % stop_event) 147 148 # LHAPDF set 149 if isinstance(lhapdf_config, list): 150 lhapdf_config = lhapdf_config[0] 151 lhapdf = misc.import_python_lhapdf(lhapdf_config) 152 if not lhapdf: 153 log('fail to load lhapdf: doe not perform systematics') 154 return 155 lhapdf.setVerbosity(0) 156 self.pdfsets = {} 157 if isinstance(pdf, str): 158 pdf = pdf.split(',') 159 160 if isinstance(pdf,list) and isinstance(pdf[0],(str,int)): 161 self.pdf = [] 162 for data in pdf: 163 if data == 'errorset': 164 data = '%s' % self.orig_pdf 165 if data == 'central': 166 data = '%s@0' % self.orig_pdf 167 if '@' in data: 168 #one particular dataset 169 name, arg = data.rsplit('@',1) 170 if int(arg) == 0: 171 if name.isdigit(): 172 self.pdf.append(lhapdf.mkPDF(int(name))) 173 else: 174 self.pdf.append(lhapdf.mkPDF(name)) 175 elif name.isdigit(): 176 try: 177 self.pdf.append(lhapdf.mkPDF(int(name)+int(arg))) 178 except: 179 raise Exception, 'Individual error sets need to be called with LHAPDF NAME not with LHAGLUE NUMBER' 180 else: 181 self.pdf.append(lhapdf.mkPDF(name, int(arg))) 182 else: 183 if data.isdigit(): 184 pdfset = lhapdf.mkPDF(int(data)).set() 185 else: 186 pdfset = lhapdf.mkPDF(data).set() 187 self.pdfsets[pdfset.lhapdfID] = pdfset 188 self.pdf += pdfset.mkPDFs() 189 else: 190 self.pdf = pdf 191 192 for p in self.pdf: 193 if p.lhapdfID == self.orig_pdf: 194 self.orig_pdf = p 195 break 196 else: 197 self.orig_pdf = lhapdf.mkPDF(self.orig_pdf) 198 if not self.b1 == 0 == self.b2: 199 self.log( "# events generated with PDF: %s (%s)" %(self.orig_pdf.set().name,self.orig_pdf.lhapdfID )) 200 # create all the function that need to be called 201 self.get_all_fct() # define self.fcts and self.args 202 203 # For e+/e- type of collision initialise the running of alps 204 if self.b1 == 0 == self.b2: 205 try: 206 from models.model_reader import Alphas_Runner 207 except ImportError: 208 root_path = pjoin(root, os.pardir, os.pardir) 209 try: 210 import internal.madevent_interface as me_int 211 cmd = me_int.MadEventCmd(root_path,force_run=True) 212 except ImportError: 213 import internal.amcnlo_run_interface as me_int 214 cmd = me_int.Cmd(root_path,force_run=True) 215 if 'mg5_path' in cmd.options and cmd.options['mg5_path']: 216 sys.path.append(cmd.options['mg5_path']) 217 from models.model_reader import Alphas_Runner 218 219 if not hasattr(self.banner, 'param_card'): 220 param_card = self.banner.charge_card('param_card') 221 else: 222 param_card = self.banner.param_card 223 224 asmz = param_card.get_value('sminputs', 3, 0.13) 225 nloop =2 226 zmass = param_card.get_value('mass', 23, 91.188) 227 cmass = param_card.get_value('mass', 4, 1.4) 228 if cmass == 0: 229 cmass = 1.4 230 bmass = param_card.get_value('mass', 5, 4.7) 231 if bmass == 0: 232 bmass = 4.7 233 self.alpsrunner = Alphas_Runner(asmz, nloop, zmass, cmass, bmass) 234 235 # Store which weight to keep/removed 236 self.remove_wgts = [] 237 for id in remove_wgts: 238 if id == 'all': 239 self.remove_wgts = ['all'] 240 break 241 elif ',' in id: 242 min_value, max_value = [int(v) for v in id.split(',')] 243 self.remove_wgts += [i for i in range(min_value, max_value+1)] 244 else: 245 self.remove_wgts.append(id) 246 self.keep_wgts = [] 247 for id in keep_wgts: 248 if id == 'all': 249 self.keep_wgts = ['all'] 250 break 251 elif ',' in id: 252 min_value, max_value = [int(v) for v in id.split(',')] 253 self.remove_wgts += [i for i in range(min_value, max_value+1)] 254 else: 255 self.remove_wgts.append(id) 256 257 # input to start the id in the weight 258 self.start_wgt_id = int(start_id[0]) if (start_id is not None) else None 259 self.has_wgts_pattern = False # tag to check if the pattern for removing
260 # the weights was computed already 261
262 - def is_wgt_kept(self, name):
263 """ determine if we have to keep/remove such weight """ 264 265 if 'all' in self.keep_wgts or not self.remove_wgts: 266 return True 267 268 #start by checking what we want to keep 269 if name in self.keep_wgts: 270 return True 271 272 # check for regular expression 273 if not self.has_wgts_pattern: 274 pat = r'|'.join(w for w in self.keep_wgts if any(letter in w for letter in '*?.([+\\')) 275 if pat: 276 self.keep_wgts_pattern = re.compile(pat) 277 else: 278 self.keep_wgts_pattern = None 279 pat = r'|'.join(w for w in self.remove_wgts if any(letter in w for letter in '*?.([+\\')) 280 if pat: 281 self.rm_wgts_pattern = re.compile(pat) 282 else: 283 self.rm_wgts_pattern = None 284 self.has_wgts_pattern=True 285 286 if self.keep_wgts_pattern and re.match(self.keep_wgts_pattern,name): 287 return True 288 289 #check what we want to remove 290 if 'all' in self.remove_wgts: 291 return False 292 elif name in self.remove_wgts: 293 return False 294 elif self.rm_wgts_pattern and re.match(self.rm_wgts_pattern, name): 295 return False 296 else: 297 return True
298
299 - def remove_old_wgts(self, event):
300 """remove the weight as requested by the user""" 301 302 rwgt_data = event.parse_reweight() 303 for name in rwgt_data.keys(): 304 if not self.is_wgt_kept(name): 305 del rwgt_data[name] 306 event.reweight_order.remove(name)
307 308
309 - def run(self, stdout=sys.stdout):
310 """ """ 311 start_time = time.time() 312 if self.start_event == 0 or self.force_write_banner: 313 lowest_id = self.write_banner(self.output) 314 else: 315 lowest_id = self.get_id() 316 317 ids = [lowest_id+i for i in range(len(self.args)-1)] 318 all_cross = [0 for i in range(len(self.args))] 319 320 self.input.parsing = False 321 for nb_event,event in enumerate(self.input): 322 if nb_event < self.start_event: 323 continue 324 elif nb_event == self.start_event: 325 self.input.parsing = True 326 event = lhe_parser.Event(event) 327 elif nb_event >= self.stop_event: 328 if self.force_write_banner: 329 self.output.write('</LesHouchesEvents>\n') 330 break 331 332 if self.is_lo: 333 if (nb_event-self.start_event)>=0 and (nb_event-self.start_event) % 2500 ==0: 334 self.log( '# currently at event %s [elapsed time: %.2g s]' % (nb_event, time.time()-start_time)) 335 else: 336 if (nb_event-self.start_event)>=0 and (nb_event-self.start_event) % 1000 ==0: 337 self.log( '# currently at event %i [elapsed time: %.2g s]' % (nb_event, time.time()-start_time)) 338 339 self.new_event() #re-init the caching of alphas/pdf 340 self.remove_old_wgts(event) 341 if self.is_lo: 342 wgts = [self.get_lo_wgt(event, *arg) for arg in self.args] 343 else: 344 wgts = [self.get_nlo_wgt(event, *arg) for arg in self.args] 345 346 if wgts[0] == 0: 347 print wgts 348 print event 349 raise Exception 350 351 wgt = [event.wgt*wgts[i]/wgts[0] for i in range(1,len(wgts))] 352 all_cross = [(all_cross[j] + event.wgt*wgts[j]/wgts[0]) for j in range(len(wgts))] 353 354 rwgt_data = event.parse_reweight() 355 rwgt_data.update(zip(ids, wgt)) 356 event.reweight_order += ids 357 # order the 358 self.output.write(str(event)) 359 else: 360 self.output.write('</LesHouchesEvents>\n') 361 self.output.close() 362 self.print_cross_sections(all_cross, min(nb_event,self.stop_event)-self.start_event+1, stdout) 363 364 if self.output.name != self.output_path: 365 import shutil 366 shutil.move(self.output.name, self.output_path) 367 368 return all_cross
369
370 - def print_cross_sections(self, all_cross, nb_event, stdout):
371 """print the cross-section.""" 372 373 norm = self.banner.get('run_card', 'event_norm', default='sum') 374 #print "normalisation is ", norm 375 #print "nb_event is ", nb_event 376 377 max_scale, min_scale = 0,sys.maxint 378 max_alps, min_alps = 0, sys.maxint 379 max_dyn, min_dyn = 0,sys.maxint 380 pdfs = {} 381 dyns = {} # dyn : {'max': , 'min':} 382 383 if norm == 'sum': 384 norm = 1 385 elif norm in ['average', 'bias']: 386 norm = 1./nb_event 387 elif norm == 'unity': 388 norm = 1 389 390 all_cross = [c*norm for c in all_cross] 391 stdout.write("# mur\t\tmuf\t\talpsfact\tdynamical_scale\tpdf\t\tcross-section\n") 392 for i,arg in enumerate(self.args): 393 394 to_print = list(arg) 395 to_print[4] = to_print[4].lhapdfID 396 to_print.append(all_cross[i]) 397 to_report = [] 398 stdout.write('%s\t\t%s\t\t%s\t\t%s\t\t%s\t\t%s\n' % tuple(to_print)) 399 400 mur, muf, alps, dyn, pdf = arg[:5] 401 if pdf == self.orig_pdf and (dyn==self.orig_dyn or dyn==-1)\ 402 and (mur!=1 or muf!=1 or alps!=1): 403 max_scale = max(max_scale,all_cross[i]) 404 min_scale = min(min_scale,all_cross[i]) 405 if pdf == self.orig_pdf and mur==1 and muf==1 and \ 406 (dyn==self.orig_dyn or dyn==-1) and alps!=1: 407 max_alps = max(max_alps,all_cross[i]) 408 min_alps = min(min_alps,all_cross[i]) 409 410 if pdf == self.orig_pdf and mur==1 and muf==1 and alps==1: 411 max_dyn = max(max_dyn,all_cross[i]) 412 min_dyn = min(min_dyn,all_cross[i]) 413 414 if pdf == self.orig_pdf and (alps!=1 or mur!=1 or muf!=1) and \ 415 (dyn!=self.orig_dyn or dyn!=-1): 416 if dyn not in dyns: 417 dyns[dyn] = {'max':0, 'min':sys.maxint,'central':0} 418 curr = dyns[dyn] 419 curr['max'] = max(curr['max'],all_cross[i]) 420 curr['min'] = min(curr['min'],all_cross[i]) 421 if pdf == self.orig_pdf and (alps==1 and mur==1 and muf==1) and \ 422 (dyn!=self.orig_dyn or dyn!=-1): 423 if dyn not in dyns: 424 dyns[dyn] = {'max':0, 'min':sys.maxint,'central':all_cross[i]} 425 else: 426 dyns[dyn]['central'] = all_cross[i] 427 428 if alps==1 and mur==1 and muf==1 and (dyn==self.orig_dyn or dyn==-1): 429 pdfset = pdf.set() 430 if pdfset.lhapdfID in self.pdfsets: 431 if pdfset.lhapdfID not in pdfs : 432 pdfs[pdfset.lhapdfID] = [0] * pdfset.size 433 pdfs[pdfset.lhapdfID][pdf.memberID] = all_cross[i] 434 else: 435 to_report.append('# PDF %s : %s\n' % (pdf.lhapdfID, all_cross[i])) 436 437 stdout.write('\n') 438 439 resume = StringIO.StringIO() 440 441 resume.write( '#***************************************************************************\n') 442 resume.write( "#\n") 443 resume.write( '# original cross-section: %s\n' % all_cross[0]) 444 if max_scale: 445 resume.write( '# scale variation: +%2.3g%% -%2.3g%%\n' % ((max_scale-all_cross[0])/all_cross[0]*100,(all_cross[0]-min_scale)/all_cross[0]*100)) 446 if max_alps: 447 resume.write( '# emission scale variation: +%2.3g%% -%2.3g%%\n' % ((max_alps-all_cross[0])/all_cross[0]*100,(max_alps-min_scale)/all_cross[0]*100)) 448 if max_dyn and (max_dyn!= all_cross[0] or min_dyn != all_cross[0]): 449 resume.write( '# central scheme variation: +%2.3g%% -%2.3g%%\n' % ((max_dyn-all_cross[0])/all_cross[0]*100,(all_cross[0]-min_dyn)/all_cross[0]*100)) 450 if self.orig_pdf.lhapdfID in pdfs: 451 lhapdfid = self.orig_pdf.lhapdfID 452 values = pdfs[lhapdfid] 453 pdfset = self.pdfsets[lhapdfid] 454 try: 455 pdferr = pdfset.uncertainty(values) 456 except RuntimeError: 457 resume.write( '# PDF variation: missing combination\n') 458 else: 459 resume.write( '# PDF variation: +%2.3g%% -%2.3g%%\n' % (pdferr.errplus*100/all_cross[0], pdferr.errminus*100/all_cross[0])) 460 # report error/central not directly linked to the central 461 resume.write( "#\n") 462 for lhapdfid,values in pdfs.items(): 463 if lhapdfid == self.orig_pdf.lhapdfID: 464 continue 465 if len(values) == 1 : 466 continue 467 pdfset = self.pdfsets[lhapdfid] 468 469 if pdfset.errorType == 'unknown' : 470 # Don't know how to determine uncertainty for 'unknown' errorType : 471 # File "lhapdf.pyx", line 329, in lhapdf.PDFSet.uncertainty (lhapdf.cpp:6621) 472 # RuntimeError: "ErrorType: unknown" not supported by LHAPDF::PDFSet::uncertainty. 473 continue 474 try: 475 pdferr = pdfset.uncertainty(values) 476 except RuntimeError: 477 # the same error can happend to some other type of error like custom. 478 pass 479 else: 480 resume.write( '#PDF %s: %g +%2.3g%% -%2.3g%%\n' % (pdfset.name, pdferr.central,pdferr.errplus*100/all_cross[0], pdferr.errminus*100/all_cross[0])) 481 482 dyn_name = {1: '\sum ET', 2:'\sum\sqrt{m^2+pt^2}', 3:'0.5 \sum\sqrt{m^2+pt^2}',4:'\sqrt{\hat s}' } 483 for key, curr in dyns.items(): 484 if key ==-1: 485 continue 486 central, maxvalue, minvalue = curr['central'], curr['max'], curr['min'] 487 if central == 0: 488 continue 489 if maxvalue == 0: 490 resume.write("# dynamical scheme # %s : %g # %s\n" %(key, central, dyn_name[key])) 491 else: 492 resume.write("# dynamical scheme # %s : %g +%2.3g%% -%2.3g%% # %s\n" %(key, central, (maxvalue-central)/central*100,(central-minvalue)/central*100, dyn_name[key])) 493 494 resume.write('\n'.join(to_report)) 495 496 resume.write( '#***************************************************************************\n') 497 498 stdout.write(resume.getvalue()) 499 self.log(resume.getvalue())
500 501
502 - def write_banner(self, fsock):
503 """create the new banner with the information of the weight""" 504 505 cid = self.get_id() 506 lowest_id = cid 507 508 in_scale = False 509 in_pdf = False 510 in_alps = False 511 512 text = '' 513 514 default = self.args[0] 515 for arg in self.args[1:]: 516 mur, muf, alps, dyn, pdf = arg[:5] 517 if pdf == self.orig_pdf and alps ==1 and (mur!=1 or muf!=1 or dyn!=-1): 518 if not in_scale: 519 text += "<weightgroup name=\"Central scale variation\" combine=\"envelope\">\n" 520 in_scale=True 521 elif in_scale: 522 if (pdf == self.orig_pdf and alps ==1) and arg != default: 523 pass 524 else: 525 text += "</weightgroup> # scale\n" 526 in_scale = False 527 528 if pdf == self.orig_pdf and mur == muf == 1 and dyn==-1 and alps!=1: 529 if not in_alps: 530 text += "<weightgroup name=\"Emission scale variation\" combine=\"envelope\">\n" 531 in_alps=True 532 elif in_alps: 533 text += "</weightgroup> # ALPS\n" 534 in_alps=False 535 536 if mur == muf == 1 and dyn==-1 and alps ==1: 537 if pdf.lhapdfID < 0: 538 for central,sets in self.pdfsets.items(): 539 if pdf in sets.set(): 540 misc.sprint(central) 541 542 if pdf.lhapdfID in self.pdfsets: 543 if in_pdf: 544 text += "</weightgroup> # PDFSET -> PDFSET\n" 545 pdfset = self.pdfsets[pdf.lhapdfID] 546 descrip = pdfset.description.replace('=>',';').replace('>','.gt.').replace('<','.lt.') 547 text +="<weightgroup name=\"%s\" combine=\"%s\"> # %s: %s\n" %\ 548 (pdfset.name, pdfset.errorType,pdfset.lhapdfID, descrip) 549 in_pdf=pdf.lhapdfID 550 elif pdf.memberID == 0 and (pdf.lhapdfID - pdf.memberID) in self.pdfsets: 551 if in_pdf: 552 text += "</weightgroup> # PDFSET -> PDFSET\n" 553 pdfset = self.pdfsets[pdf.lhapdfID - 1] 554 descrip = pdfset.description.replace('=>',';').replace('>','.gt.').replace('<','.lt.') 555 text +="<weightgroup name=\"%s\" combine=\"%s\"> # %s: %s\n" %\ 556 (pdfset.name, pdfset.errorType,pdfset.lhapdfID, descrip) 557 in_pdf=pdfset.lhapdfID 558 elif in_pdf and pdf.lhapdfID - pdf.memberID != in_pdf: 559 misc.sprint(pdf.lhapdfID) 560 text += "</weightgroup> # PDFSET -> PDF\n" 561 in_pdf = False 562 elif in_pdf: 563 text += "</weightgroup> PDF \n" 564 in_pdf=False 565 566 567 568 tag, info = '','' 569 if mur!=1.: 570 tag += 'MUR="%s" ' % mur 571 info += 'MUR=%s ' % mur 572 else: 573 tag += 'MUR="%s" ' % mur 574 if muf!=1.: 575 tag += 'MUF="%s" ' % muf 576 info += 'MUF=%s ' % muf 577 else: 578 tag += 'MUF="%s" ' % muf 579 580 if alps!=1.: 581 tag += 'ALPSFACT="%s" ' % alps 582 info += 'alpsfact=%s ' % alps 583 if dyn!=-1.: 584 tag += 'DYN_SCALE="%s" ' % dyn 585 info += 'dyn_scale_choice=%s ' % {1:'sum pt', 2:'HT',3:'HT/2',4:'sqrts'}[dyn] 586 587 if pdf != self.orig_pdf: 588 tag += 'PDF="%s" ' % pdf.lhapdfID 589 info += 'PDF=%s MemberID=%s' % (pdf.lhapdfID-pdf.memberID, pdf.memberID) 590 else: 591 tag += 'PDF="%s" ' % pdf.lhapdfID 592 593 text +='<weight id="%s" %s> %s </weight>\n' % (cid, tag, info) 594 cid+=1 595 596 if in_scale or in_alps or in_pdf: 597 text += "</weightgroup>\n" 598 599 if 'initrwgt' in self.banner: 600 if not self.remove_wgts: 601 self.banner['initrwgt'] += text 602 else: 603 # remove the line which correspond to removed weight 604 # removed empty group. 605 wgt_in_group=0 606 tmp_group_txt =[] 607 out =[] 608 keep_last = False 609 for line in self.banner['initrwgt'].split('\n'): 610 sline = line.strip() 611 if sline.startswith('</weightgroup'): 612 if wgt_in_group: 613 out += tmp_group_txt 614 out.append('</weightgroup>') 615 if '<weightgroup' in line: 616 wgt_in_group=0 617 tmp_group_txt = [line[line.index('<weightgroup'):]] 618 elif sline.startswith('<weightgroup'): 619 wgt_in_group=0 620 tmp_group_txt = [line] 621 elif sline.startswith('<weight'): 622 name = re.findall(r'\bid=[\'\"]([^\'\"]*)[\'\"]', sline) 623 if self.is_wgt_kept(name[0]): 624 tmp_group_txt.append(line) 625 keep_last = True 626 wgt_in_group +=1 627 else: 628 keep_last = False 629 elif keep_last: 630 tmp_group_txt.append(line) 631 out.append(text) 632 self.banner['initrwgt'] = '\n'.join(out) 633 else: 634 self.banner['initrwgt'] = text 635 636 637 self.banner.write(self.output, close_tag=False) 638 639 return lowest_id
640 641
642 - def get_id(self):
643 644 if self.start_wgt_id is not None: 645 return int(self.start_wgt_id) 646 647 if 'initrwgt' in self.banner: 648 pattern = re.compile('<weight id=(?:\'|\")([_\w]+)(?:\'|\")', re.S+re.I+re.M) 649 matches = pattern.findall(self.banner['initrwgt']) 650 matches.append('0') #ensure to have a valid entry for the max 651 return max([int(wid) for wid in matches if wid.isdigit()])+1 652 else: 653 return 1
654 655
656 - def get_all_fct(self):
657 658 all_args = [] 659 default = [1.,1.,1.,-1,self.orig_pdf] 660 #all_args.append(default) 661 pos = {'mur':0, 'muf':1, 'alps':2, 'dyn':3, 'pdf':4} 662 done = set() 663 for one_block in self.together: 664 for name in one_block: 665 done.add(name) 666 for together in itertools.product(*[getattr(self,name) for name in one_block]): 667 new_args = list(default) 668 for name,value in zip(one_block, together): 669 new_args[pos[name]] = value 670 all_args.append(new_args) 671 for name in pos: 672 if name in done: 673 continue 674 for value in getattr(self, name): 675 new_args = list(default) 676 new_args[pos[name]] = value 677 all_args.append(new_args) 678 679 self.args = [default] + [arg for arg in all_args if arg!= default] 680 681 # add the default before the pdf scan to have a full grouping 682 pdfplusone = [pdf for pdf in self.pdf if pdf.lhapdfID == self.orig_pdf.lhapdfID+1] 683 if pdfplusone: 684 pdfplusone = default[:-1] + [pdfplusone[0]] 685 index = self.args.index(pdfplusone) 686 self.args.insert(index, default) 687 688 self.log( "#Will Compute %s weights per event." % (len(self.args)-1)) 689 return
690
691 - def new_event(self):
692 self.alphas = {} 693 self.pdfQ2 = {}
694 695
696 - def get_pdfQ(self, pdf, pdg, x, scale):
697 698 if pdg in [-21,-22]: 699 pdg = abs(pdg) 700 elif pdg == 0: 701 return 1 702 703 f = pdf.xfxQ(pdg, x, scale)/x 704 # if f == 0 and pdf.memberID ==0: 705 # pdfset = pdf.set() 706 # allnumber= [p.xfxQ(pdg, x, scale) for p in pdfset.mkPDFs()] 707 # f = pdfset.uncertainty(allnumber).central /x 708 return f
709
710 - def get_pdfQ2(self, pdf, pdg, x, scale):
711 712 if pdg in [-21,-22]: 713 pdg = abs(pdg) 714 elif pdg == 0: 715 return 1 716 717 if (pdf, pdg,x,scale) in self.pdfQ2: 718 return self.pdfQ2[(pdf, pdg,x,scale)] 719 f = pdf.xfxQ2(pdg, x, scale)/x 720 self.pdfQ2[(pdf, pdg,x,scale)] = f 721 return f 722 723 #one method to handle the nnpd2.3 problem -> now just move to central 724 if f == 0 and pdf.memberID ==0: 725 # to avoid problem with nnpdf2.3 in lhapdf6.1.6 726 #print 'central pdf returns 0', pdg, x, scale 727 #print self.pdfsets 728 pdfset = pdf.set() 729 allnumber= [0] + [self.get_pdfQ2(p, pdg, x, scale) for p in pdfset.mkPDFs()[1:]] 730 f = pdfset.uncertainty(allnumber).central 731 self.pdfQ2[(pdf, pdg,x,scale)] = f 732 return f
733
734 - def get_lo_wgt(self,event, Dmur, Dmuf, Dalps, dyn, pdf):
735 """ 736 pdf is a lhapdf object!""" 737 738 loinfo = event.parse_lo_weight() 739 740 if dyn == -1: 741 mur = loinfo['ren_scale'] 742 muf1 = loinfo['pdf_q1'][-1] 743 muf2 = loinfo['pdf_q2'][-1] 744 else: 745 if dyn == 1: 746 mur = event.get_et_scale(1.) 747 elif dyn == 2: 748 mur = event.get_ht_scale(1.) 749 elif dyn == 3: 750 mur = event.get_ht_scale(0.5) 751 elif dyn == 4: 752 mur = event.get_sqrts_scale(1.) 753 muf1 = mur 754 muf2 = mur 755 loinfo = dict(loinfo) 756 loinfo['pdf_q1'] = loinfo['pdf_q1'] [:-1] + [mur] 757 loinfo['pdf_q2'] = loinfo['pdf_q2'] [:-1] + [mur] 758 759 760 761 # MUR part 762 if self.b1 == 0 == self.b2: 763 if loinfo['n_qcd'] != 0: 764 wgt = self.alpsrunner(Dmur*mur)**loinfo['n_qcd'] 765 else: 766 wgt = 1.0 767 else: 768 wgt = pdf.alphasQ(Dmur*mur)**loinfo['n_qcd'] 769 # MUF/PDF part 770 wgt *= self.get_pdfQ(pdf, self.b1*loinfo['pdf_pdg_code1'][-1], loinfo['pdf_x1'][-1], Dmuf*muf1) 771 wgt *= self.get_pdfQ(pdf, self.b2*loinfo['pdf_pdg_code2'][-1], loinfo['pdf_x2'][-1], Dmuf*muf2) 772 773 for scale in loinfo['asrwt']: 774 if self.b1 == 0 == self.b2: 775 wgt = self.alpsrunner(Dalps*scale) 776 else: 777 wgt *= pdf.alphasQ(Dalps*scale) 778 779 # ALS part 780 for i in range(loinfo['n_pdfrw1']-1): 781 scale = min(Dalps*loinfo['pdf_q1'][i], Dmuf*muf1) 782 wgt *= self.get_pdfQ(pdf, self.b1*loinfo['pdf_pdg_code1'][i], loinfo['pdf_x1'][i], scale) 783 wgt /= self.get_pdfQ(pdf, self.b1*loinfo['pdf_pdg_code1'][i], loinfo['pdf_x1'][i+1], scale) 784 785 for i in range(loinfo['n_pdfrw2']-1): 786 scale = min(Dalps*loinfo['pdf_q2'][i], Dmuf*muf2) 787 wgt *= self.get_pdfQ(pdf, self.b2*loinfo['pdf_pdg_code2'][i], loinfo['pdf_x2'][i], scale) 788 wgt /= self.get_pdfQ(pdf, self.b2*loinfo['pdf_pdg_code2'][i], loinfo['pdf_x2'][i+1], scale) 789 790 return wgt
791
792 - def get_nlo_wgt(self,event, Dmur, Dmuf, Dalps, dyn, pdf):
793 """return the new weight for NLO event --with weight information-- """ 794 795 wgt = 0 796 nloinfo = event.parse_nlo_weight(real_type=(1,11,12,13)) 797 for cevent in nloinfo.cevents: 798 if dyn == 1: 799 mur2 = max(1.0, cevent.get_et_scale(1.)**2) 800 elif dyn == 2: 801 mur2 = max(1.0, cevent.get_ht_scale(1.)**2) 802 elif dyn == 3: 803 mur2 = max(1.0, cevent.get_ht_scale(0.5)**2) 804 elif dyn == 4: 805 mur2 = cevent.get_sqrts_scale(event,1)**2 806 else: 807 mur2 = 0 808 muf2 = mur2 809 810 for onewgt in cevent.wgts: 811 if not __debug__ and (dyn== -1 and Dmur==1 and Dmuf==1 and pdf==self.orig_pdf): 812 wgt += onewgt.ref_wgt 813 814 if dyn == -1: 815 mur2 = onewgt.scales2[1] 816 muf2 = onewgt.scales2[2] 817 Q2 = onewgt.scales2[0] # Ellis-Sexton scale 818 819 wgtpdf = self.get_pdfQ2(pdf, self.b1*onewgt.pdgs[0], onewgt.bjks[0], 820 Dmuf**2 * muf2) 821 wgtpdf *= self.get_pdfQ2(pdf, self.b2*onewgt.pdgs[1], onewgt.bjks[1], 822 Dmuf**2 * muf2) 823 824 tmp = onewgt.pwgt[0] 825 tmp += onewgt.pwgt[1] * math.log(Dmur**2 * mur2/ Q2) 826 tmp += onewgt.pwgt[2] * math.log(Dmuf**2 * muf2/ Q2) 827 828 if self.b1 == 0 == self.b2: 829 alps = self.alpsrunner(Dmur*math.sqrt(mur2)) 830 else: 831 alps = pdf.alphasQ2(Dmur**2*mur2) 832 833 tmp *= math.sqrt(4*math.pi*alps)**onewgt.qcdpower 834 835 if wgtpdf == 0: #happens for nn23pdf due to wrong set in lhapdf 836 key = (self.b1*onewgt.pdgs[0], self.b2*onewgt.pdgs[1], onewgt.bjks[0],onewgt.bjks[1], muf2) 837 if dyn== -1 and Dmuf==1 and Dmur==1 and pdf==self.orig_pdf: 838 wgtpdf = onewgt.ref_wgt / tmp 839 self.pdfQ2[key] = wgtpdf 840 elif key in self.pdfQ2: 841 wgtpdf = self.pdfQ2[key] 842 else: 843 # real zero! 844 wgtpdf = 0 845 846 tmp *= wgtpdf 847 wgt += tmp 848 849 850 if __debug__ and dyn== -1 and Dmur==1 and Dmuf==1 and pdf==self.orig_pdf: 851 if not misc.equal(tmp, onewgt.ref_wgt, sig_fig=2): 852 misc.sprint(tmp, onewgt.ref_wgt, (tmp-onewgt.ref_wgt)/tmp) 853 misc.sprint(onewgt) 854 misc.sprint(cevent) 855 misc.sprint(mur2,muf2) 856 raise Exception, 'not enough agreement between stored value and computed one' 857 858 return wgt
859 860
861 -def call_systematics(args, result=sys.stdout, running=True, 862 log=lambda x:sys.stdout.write(str(x)+'\n')):
863 """calling systematics from a list of arguments""" 864 865 input, output = args[0:2] 866 opts = {} 867 for arg in args[2:]: 868 if '=' in arg: 869 key,values= arg.split('=') 870 key = key.replace('-','') 871 values = values.strip() 872 if values[0] in ["'",'"'] and values[-1]==values[0]: 873 values = values[1:-1] 874 values = values.split(',') 875 if key == 'together': 876 if key in opts: 877 opts[key].append(tuple(values)) 878 else: 879 opts[key]=[tuple(values)] 880 elif key == 'result': 881 result = open(values[0],'w') 882 elif key in ['start_event', 'stop_event']: 883 opts[key] = int(values[0]) 884 elif key == 'write_banner': 885 opts[key] = banner_mod.ConfigFile.format_variable(values[0], bool, 'write_banner') 886 else: 887 if key in opts: 888 opts[key] += values 889 else: 890 opts[key] = values 891 else: 892 raise SystematicsError, "unknow argument %s" % arg 893 894 #load run_card and extract parameter if needed. 895 if 'from_card' in opts: 896 if opts['from_card'] != ['internal']: 897 card = banner.RunCard(opts['from_card'][0]) 898 else: 899 for i in range(10): 900 try: 901 lhe = lhe_parser.EventFile(input) 902 break 903 except OSError,error: 904 print error 905 time.sleep(15*(i+1)) 906 else: 907 raise 908 909 card = banner.RunCard(banner.Banner(lhe.banner)['mgruncard']) 910 lhe.close() 911 912 if isinstance(card, banner.RunCardLO): 913 # LO case 914 opts['mur'] = [float(x) for x in card['sys_scalefact'].split()] 915 opts['muf'] = opts['mur'] 916 if card['sys_alpsfact'] != 'None': 917 opts['alps'] = [float(x) for x in card['sys_alpsfact'].split()] 918 else: 919 opts['alps'] = [1.0] 920 opts['together'] = [('mur','muf','alps','dyn')] 921 if '&&' in card['sys_pdf']: 922 pdfs = card['sys_pdf'].split('&&') 923 else: 924 data = card['sys_pdf'].split() 925 pdfs = [] 926 for d in data: 927 if not d.isdigit(): 928 pdfs.append(d) 929 elif int(d) > 500: 930 pdfs.append(d) 931 else: 932 pdfs[-1] = '%s %s' % (pdfs[-1], d) 933 934 opts['dyn'] = [-1,1,2,3,4] 935 opts['pdf'] = [] 936 for pdf in pdfs: 937 split = pdf.split() 938 if len(split)==1: 939 opts['pdf'].append('%s' %pdf) 940 else: 941 pdf,nb = split 942 for i in range(int(nb)): 943 opts['pdf'].append('%s@%s' % (pdf, i)) 944 if not opts['pdf']: 945 opts['pdf'] = 'central' 946 else: 947 #NLO case 948 raise Exception 949 del opts['from_card'] 950 951 952 obj = Systematics(input, output, log=log, **opts) 953 if running and obj: 954 obj.run(result) 955 return obj
956 957 if __name__ == "__main__": 958 sys_args = sys.argv[1:] 959 for i, arg in enumerate(sys_args) : 960 if arg.startswith('--lhapdf_config=') : 961 lhapdf = misc.import_python_lhapdf(arg[len('--lhapdf_config='):]) 962 del sys_args[i] 963 break 964 965 if 'lhapdf' not in globals(): 966 lhapdf = misc.import_python_lhapdf('lhapdf-config') 967 968 if not lhapdf: 969 sys.exit('Can not run systematics since can not link python to lhapdf, specify --lhapdf-config=') 970 call_systematics(sys_args) 971