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