Package models :: Module model_reader
[hide private]
[frames] | no frames]

Source Code for Module models.model_reader

  1  ################################################################################ 
  2  # 
  3  # Copyright (c) 2010 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  """Module to allow reading a param_card and setting all parameters and 
 16  couplings for a model""" 
 17   
 18  from __future__ import division 
 19   
 20  from __future__ import absolute_import 
 21  import array 
 22  import cmath 
 23  import copy 
 24  import itertools 
 25  import logging 
 26  import math 
 27  import os 
 28  import re 
 29  import aloha 
 30   
 31  import madgraph.core.base_objects as base_objects 
 32  import madgraph.loop.loop_base_objects as loop_base_objects 
 33  import models.check_param_card as card_reader 
 34  from madgraph import MadGraph5Error, MG5DIR 
 35  import madgraph.various.misc as misc 
 36  import six 
 37   
 38  ZERO = 0 
 39   
 40  #=============================================================================== 
 41  # Logger for model_reader 
 42  #=============================================================================== 
 43   
 44  logger = logging.getLogger('madgraph.models') 
 45   
 46  #=============================================================================== 
 47  # ModelReader: Used to read a param_card and calculate parameters and 
 48  #              couplings of the model. 
 49  #=============================================================================== 
50 -class ModelReader(loop_base_objects.LoopModel):
51 """Object to read all parameters and couplings of a model 52 """ 53
54 - def default_setup(self):
55 """The particles is changed to ParticleList""" 56 self['coupling_dict'] = {} 57 self['parameter_dict'] = {} 58 super(ModelReader, self).default_setup()
59
60 - def set_parameters_and_couplings(self, param_card = None, scale=None, 61 complex_mass_scheme=None, 62 auto_width=None):
63 """Read a param_card and calculate all parameters and 64 couplings. Set values directly in the parameters and 65 couplings, plus add new dictionary coupling_dict from 66 parameter name to value.""" 67 68 param_card_text = None 69 # Extract external parameters 70 external_parameters = self['parameters'][('external',)] 71 # Read in param_card 72 if param_card: 73 # Create a dictionary from LHA block name and code to parameter name 74 parameter_dict = {} 75 for param in external_parameters: 76 try: 77 dictionary = parameter_dict[param.lhablock.lower()] 78 except KeyError: 79 dictionary = {} 80 parameter_dict[param.lhablock.lower()] = dictionary 81 dictionary[tuple(param.lhacode)] = param 82 if isinstance(param_card, six.string_types): 83 # Check that param_card exists 84 if not os.path.isfile(param_card): 85 raise MadGraph5Error("No such file %s" % param_card) 86 param_card_text = param_card 87 param_card = card_reader.ParamCard(param_card) 88 for param in param_card.get('decay'): 89 if str(param.value).lower() == 'auto': 90 param.value = auto_width(param_card, param.lhacode) 91 #misc.sprint(type(param_card), card_reader.ParamCard, isinstance(param_card, card_reader.ParamCard)) 92 #assert isinstance(param_card, card_reader.ParamCard),'%s is not a ParamCard: %s' % (type(param_card), isinstance(param_card, card_reader.ParamCard)) 93 94 if complex_mass_scheme is None: 95 if aloha.complex_mass: 96 param_card.convert_to_complex_mass_scheme() 97 else: 98 if complex_mass_scheme: 99 param_card.convert_to_complex_mass_scheme() 100 101 key = [k for k in param_card.keys() if not k.startswith('qnumbers ') 102 and not k.startswith('decay_table') 103 and 'info' not in k] 104 param_key = [k for k in parameter_dict.keys() if 'info' not in k] 105 106 if set(key) != set(parameter_dict.keys()): 107 # the two card are different. check if this critical 108 fail = True 109 missing_set = set(parameter_dict.keys()).difference(set(key)) 110 unknow_set = set(key).difference(set(parameter_dict.keys())) 111 missing_block = ','.join(missing_set) 112 unknow_block = ','.join(unknow_set) 113 114 115 msg = '''Invalid restriction card (not same block) 116 %s != %s. 117 Missing block: %s 118 Unknown block : %s''' % (set(key), set(parameter_dict.keys()), 119 missing_block, unknow_block) 120 apply_conversion = [] 121 122 if 'loop' in missing_set: 123 key.append('loop') 124 fail = False 125 126 if not missing_block: 127 logger.warning("Unknow type of information in the card: %s" % unknow_block) 128 fail = False 129 elif self['name'].startswith('mssm-') or self['name'] == 'mssm': 130 if not missing_set: 131 fail = False 132 else: 133 apply_conversion.append('to_slha2') 134 overwrite = False 135 elif missing_set == set(['fralpha']) and 'alpha' in unknow_set: 136 apply_conversion.append('alpha') 137 elif self.need_slha2(missing_set, unknow_set): 138 apply_conversion.append('to_slha2') 139 overwrite = True 140 141 if apply_conversion: 142 try: 143 if 'to_slha2' in apply_conversion: 144 if overwrite: 145 logger.error('Convention for the param_card seems to be wrong. Trying to automatically convert your file to SLHA2 format. \n'+\ 146 "Please check that the conversion occurs as expected (The converter is not fully general)") 147 import time 148 time.sleep(5) 149 150 param_card = param_card.input_path 151 param_card = card_reader.convert_to_mg5card(param_card, 152 writting=overwrite) 153 key = [k for k in param_card.keys() if not k.startswith('qnumbers ') 154 and not k.startswith('decay_table')] 155 if not set(parameter_dict.keys()).difference(set(key)): 156 fail = False 157 if 'alpha' in apply_conversion: 158 logger.info("Missing block fralpha but found a block alpha, apply automatic conversion") 159 param_card.rename_blocks({'alpha':'fralpha'}) 160 param_card['fralpha'].rename_keys({(): (1,)}) 161 param_card.write(param_card.input_path) 162 key = [k for k in param_card.keys() if not k.startswith('qnumbers ') 163 and not k.startswith('decay_table')] 164 if not set(parameter_dict.keys()).difference(set(key)): 165 fail = False 166 except Exception: 167 raise 168 raise MadGraph5Error(msg) 169 170 171 if fail: 172 raise MadGraph5Error(msg) 173 174 for block in key: 175 if block not in parameter_dict: 176 continue 177 for pid in parameter_dict[block]: 178 try: 179 value = param_card[block].get(pid).value 180 except: 181 if block == 'loop': 182 value = param_card['mass'].get(23).value 183 else: 184 raise MadGraph5Error('%s %s not define' % (block, pid)) 185 186 if isinstance(value, str) and value.lower() == 'auto': 187 value = '0.0' 188 if scale and parameter_dict[block][pid].name == 'aS': 189 runner = Alphas_Runner(value, nloop=2) 190 try: 191 value = runner(scale) 192 except ValueError as err: 193 if str(err) == 'math domain error' and scale < 1: 194 value = 0.0 195 else: 196 raise 197 except OverflowError as err: 198 if scale < 1: 199 value = 0.0 200 else: 201 raise 202 203 exec("locals()[\'%s\'] = %s" % (parameter_dict[block][pid].name, 204 value)) 205 parameter_dict[block][pid].value = float(value) 206 207 else: 208 # No param_card, use default values 209 for param in external_parameters: 210 if scale and parameter_dict[block][id].name == 'aS': 211 runner = Alphas_Runner(value, nloop=3) 212 value = runner(scale) 213 exec("locals()[\'%s\'] = %s" % (param.name, param.value)) 214 215 216 # Define all functions used 217 for func in self['functions']: 218 exec("def %s(%s):\n return %s" % (func.name, 219 ",".join(func.arguments), 220 func.expr)) 221 222 # Extract derived parameters 223 derived_parameters = [] 224 keys = [key for key in self['parameters'].keys() if \ 225 key != ('external',)] 226 keys.sort(key=len) 227 for key in keys: 228 derived_parameters += self['parameters'][key] 229 230 # Now calculate derived parameters 231 for param in derived_parameters: 232 try: 233 exec("locals()[\'%s\'] = %s" % (param.name, param.expr)) 234 except Exception as error: 235 msg = 'Unable to evaluate %s = %s: raise error: %s' % (param.name,param.expr, error) 236 raise MadGraph5Error(msg) 237 param.value = complex(eval(param.name)) 238 if not eval(param.name) and eval(param.name) != 0: 239 logger.warning("%s has no expression: %s" % (param.name, 240 param.expr)) 241 242 # Correct width sign for Majorana particles (where the width 243 # and mass need to have the same sign) 244 for particle in self.get('particles'): 245 if particle.is_fermion() and particle.get('self_antipart') and \ 246 particle.get('width').lower() != 'zero' and \ 247 eval(particle.get('mass')).real < 0: 248 exec("locals()[\'%(width)s\'] = -abs(%(width)s)" % \ 249 {'width': particle.get('width')}) 250 251 # Extract couplings 252 couplings = sum(list(self['couplings'].values()), []) 253 # Now calculate all couplings 254 for coup in couplings: 255 #print "I execute %s = %s"%(coup.name, coup.expr) 256 exec("locals()[\'%s\'] = %s" % (coup.name, coup.expr)) 257 coup.value = complex(eval(coup.name)) 258 if not eval(coup.name) and eval(coup.name) != 0: 259 logger.warning("%s has no expression: %s" % (coup.name, 260 coup.expr)) 261 262 # Set parameter and coupling dictionaries 263 self.set('parameter_dict', dict([(param.name, param.value) \ 264 for param in external_parameters + \ 265 derived_parameters])) 266 267 # Add "zero" 268 self.get('parameter_dict')['ZERO'] = complex(0.) 269 270 self.set('coupling_dict', dict([(coup.name, coup.value) \ 271 for coup in couplings])) 272 273 return locals()
274
275 - def get_mass(self, pdg_code):
276 """easy way to have access to a mass value""" 277 278 if isinstance(pdg_code, (int,str)): 279 return self.get('parameter_dict')[self.get_particle(pdg_code).get('mass')].real 280 else: 281 return self.get('parameter_dict')[pdg_code.get('mass')].real
282
283 - def get_width(self, pdg_code):
284 """easy way to have access to a width value""" 285 if isinstance(pdg_code, (int,str)): 286 return self.get('parameter_dict')[self.get_particle(pdg_code).get('width')].real 287 else: 288 return self.get('parameter_dict')[pdg_code.get('mass')].real
289
290 - def need_slha2(self, missing_set, unknow_set):
291 292 return all([b in missing_set for b in ['te','msl2','dsqmix','tu','selmix','msu2','msq2','usqmix','td', 'mse2','msd2']]) and\ 293 all(b in unknow_set for b in ['ae','ad','sbotmix','au','modsel','staumix','stopmix'])
294
295 -class Alphas_Runner(object):
296 """Evaluation of strong coupling constant alpha_S""" 297 # Author: Olivier Mattelaer translated from a fortran routine 298 # written by R. K. Ellis 299 # 300 # q -- scale at which alpha_s is to be evaluated 301 # 302 # asmz -- value of alpha_s at the mass of the Z-boson 303 # nloop -- the number of loops (1,2, or 3) at which beta 304 # 305 # function is evaluated to determine running. 306 # the values of the cmass and the bmass should be set 307 #--------------------------------------------------------------------------- 308
309 - def __init__(self, asmz, nloop, zmass=91.188, cmass=1.4, bmass=4.7):
310 311 self.asmz = asmz 312 self.nloop = nloop 313 self.zmass = zmass 314 self.cmass = cmass 315 self.bmass = bmass 316 317 assert asmz > 0 318 assert cmass > 0 319 assert bmass > 0 320 assert nloop > -1 321 t = 2 * math.log(bmass/zmass) 322 self.amb = self.newton1(t, asmz, 5) 323 t = 2 * math.log(cmass/bmass) 324 self.amc = self.newton1(t, self.amb, 4)
325
326 - def __call__(self, scale):
327 """Evaluation of strong coupling constant alpha_S at scale 'scale'.""" 328 assert scale > 0 329 330 331 if scale < 0.188775276209: 332 return 0 333 elif scale < self.cmass: 334 t = 2 * math.log(scale/self.cmass) 335 return self.newton1(t, self.amc, 3) 336 elif scale < self.bmass: 337 t = 2 * math.log(scale/self.bmass) 338 return self.newton1(t, self.amb, 4) 339 else: 340 t = 2 * math.log(scale/self.zmass) 341 return self.newton1(t, self.asmz, 5)
342 343 # B0=(11.-2.*NF/3.)/4./PI 344 b0 = [0.716197243913527, 0.66314559621623, 0.61009394851893] 345 # C1=(102.D0-38.D0/3.D0*NF)/4.D0/PI/(11.D0-2.D0/3.D0*NF) 346 c1 = [0.565884242104515, 0.49019722472304, 0.40134724779695] 347 # C2=(2857.D0/2.D0-5033*NF/18.D0+325*NF**2/54)/16.D0/PI**2/(11.D0-2.D0/3.D0*NF) 348 c2 = [0.453013579178645, 0.30879037953664, 0.14942733137107] 349 # DEL=SQRT(4*C2-C1**2) 350 d = [1.22140465909230, 0.99743079911360, 0.66077962451190] 351 352 353
354 - def newton1(self, t, alphas, nf):
355 """calculate a_out using nloop beta-function evolution 356 with nf flavours, given starting value as-in 357 given alphas and logarithmic separation between 358 input scale and output scale t. 359 Evolution is performed using Newton's method, 360 with a precision given by tol.""" 361 nloop = self.nloop 362 tol = 5e-4 363 arg = nf-3 364 b0, c1, c2, d = self.b0[arg], self.c1[arg], self.c2[arg], self.d[arg] 365 366 if nloop == 2: 367 f = lambda AS: 1.0/AS+c1*math.log((c1*AS)/(1+c1*AS)) 368 elif nloop == 3: 369 f = lambda AS: 1.0/AS+0.5*c1*math.log((c2*AS**2)/(1+c1*AS+c2*AS**2)) \ 370 -(c1**2-2*c2)/d*math.atan((2*c2*AS+c1)/d) 371 372 a_out = alphas / (1 + alphas * b0 * t) 373 if nloop == 1: 374 return a_out 375 376 a_out = alphas/(1+b0*alphas*t+c1*alphas*math.log(1+alphas*b0*t)) 377 if a_out < 0: 378 a_out = 0.3 379 380 while 1: 381 AS = a_out 382 F = b0 * t + f(alphas) -f(AS) 383 if nloop == 2: 384 FP=1/(AS**2*(1+c1*AS)) 385 elif nloop == 3: 386 FP=1/(AS**2*(1+c1*AS + c2 * AS**2)) 387 if FP == 0: 388 return AS 389 a_out = AS - F/FP 390 delta = abs(F/FP/AS) 391 if delta < tol: 392 break 393 return a_out
394