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