1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """ How to import a UFO model to the MG5 format """
16
17 import collections
18 import fractions
19 import logging
20 import os
21 import re
22 import sys
23 import time
24 import collections
25
26
27 from madgraph import MadGraph5Error, MG5DIR, ReadWrite
28 import madgraph.core.base_objects as base_objects
29 import madgraph.loop.loop_base_objects as loop_base_objects
30 import madgraph.core.color_algebra as color
31 import madgraph.iolibs.files as files
32 import madgraph.iolibs.save_load_object as save_load_object
33 from madgraph.core.color_algebra import *
34 import madgraph.various.misc as misc
35 import madgraph.iolibs.ufo_expression_parsers as parsers
36
37 import aloha
38 import aloha.create_aloha as create_aloha
39 import aloha.aloha_fct as aloha_fct
40
41 import models as ufomodels
42 import models.model_reader as model_reader
43 logger = logging.getLogger('madgraph.model')
44 logger_mod = logging.getLogger('madgraph.model')
45
46 root_path = os.path.dirname(os.path.realpath( __file__ ))
47 sys.path.append(root_path)
48
49 sys.path.append(os.path.join(root_path, os.path.pardir, 'Template', 'bin', 'internal'))
50 import check_param_card
51
52 pjoin = os.path.join
53
54
55 pole_dict = {-2:'2EPS',-1:'1EPS',0:'FIN'}
58 """ a error class for wrong import of UFO model"""
59
61 """ a class for invalid Model """
62
63 last_model_path =''
65 """ find the path to a model """
66
67 global last_model_path
68
69
70 if model_name.startswith(('./','../')) and os.path.isdir(model_name):
71 return model_name
72 elif os.path.isdir(os.path.join(MG5DIR, 'models', model_name)):
73 return os.path.join(MG5DIR, 'models', model_name)
74 elif 'PYTHONPATH' in os.environ:
75 for p in os.environ['PYTHONPATH'].split(':'):
76 if os.path.isdir(os.path.join(MG5DIR, p, model_name)):
77 if last_model_path != os.path.join(MG5DIR, p, model_name):
78 logger.info("model loaded from PYTHONPATH: %s", os.path.join(MG5DIR, p, model_name))
79 last_model_path = os.path.join(MG5DIR, p, model_name)
80 return os.path.join(MG5DIR, p, model_name)
81 if os.path.isdir(model_name):
82 logger.warning('No model %s found in default path. Did you mean \'import model ./%s\'',
83 model_name, model_name)
84 if os.path.sep in model_name:
85 raise UFOImportError("Path %s is not a valid pathname" % model_name)
86 elif web_search and '-' not in model_name:
87 found = import_model_from_db(model_name)
88 if found:
89 return find_ufo_path(model_name, web_search=False)
90 else:
91 raise UFOImportError("Path %s is not a valid pathname" % model_name)
92 else:
93 raise UFOImportError("Path %s is not a valid pathname" % model_name)
94
95 raise UFOImportError("Path %s is not a valid pathname" % model_name)
96 return
97
100 """return the file with the online model database"""
101
102 data_path = ['http://madgraph.phys.ucl.ac.be/models_db.dat',
103 'http://madgraph.physics.illinois.edu/models_db.dat']
104 import random
105 import urllib
106 r = random.randint(0,1)
107 r = [r, (1-r)]
108
109 if 'MG5aMC_WWW' in os.environ and os.environ['MG5aMC_WWW']:
110 data_path.append(os.environ['MG5aMC_WWW']+'/models_db.dat')
111 r.insert(0, 2)
112
113
114 for index in r:
115 cluster_path = data_path[index]
116 try:
117 data = urllib.urlopen(cluster_path)
118 except Exception:
119 continue
120 if data.getcode() != 200:
121 continue
122 break
123 else:
124 raise MadGraph5Error, '''Model not found locally and Impossible to connect any of us servers.
125 Please check your internet connection or retry later'''
126 return data
127
129 """ import the model with a given name """
130
131 if os.path.sep in model_name and os.path.exists(os.path.dirname(model_name)):
132 target = os.path.dirname(model_name)
133 model_name = os.path.basename(model_name)
134 else:
135 target = None
136 data =get_model_db()
137 link = None
138 for line in data:
139 split = line.split()
140 if model_name == split[0]:
141 link = split[1]
142 break
143 else:
144 logger.debug('no model with that name (%s) found online', model_name)
145 return False
146
147
148
149
150
151 username = ''
152 if not target:
153 try:
154 import pwd
155 username =pwd.getpwuid( os.getuid() )[ 0 ]
156 except Exception, error:
157 misc.sprint(str(error))
158 username = ''
159 if username in ['omatt', 'mattelaer', 'olivier'] and target is None and \
160 'PYTHONPATH' in os.environ and not local_dir:
161 for directory in os.environ['PYTHONPATH'].split(':'):
162
163 if 'UFOMODEL' == os.path.basename(directory) and os.path.exists(directory) and\
164 misc.glob('*/couplings.py', path=directory) and 'matt' in directory:
165 target= directory
166
167 if target is None:
168 target = pjoin(MG5DIR, 'models')
169 try:
170 os.remove(pjoin(target, 'tmp.tgz'))
171 except Exception:
172 pass
173 logger.info("download model from %s to the following directory: %s", link, target, '$MG:color:BLACK')
174 misc.wget(link, 'tmp.tgz', cwd=target)
175
176
177
178 if link.endswith(('.tgz','.tar.gz','.tar')):
179 try:
180 proc = misc.call('tar -xzpvf tmp.tgz', shell=True, cwd=target)
181 if proc: raise Exception
182 except:
183 proc = misc.call('tar -xpvf tmp.tgz', shell=True, cwd=target)
184
185 if link.endswith(('.zip')):
186 try:
187 proc = misc.call('unzip tmp.tgz', shell=True, cwd=target)
188 if proc: raise Exception
189 except:
190 proc = misc.call('tar -xzpvf tmp.tgz', shell=True, cwd=target)
191 if proc:
192 raise Exception, "Impossible to unpack the model. Please install it manually"
193 return True
194
195 -def import_model(model_name, decay=False, restrict=True, prefix='mdl_',
196 complex_mass_scheme = None):
197 """ a practical and efficient way to import a model"""
198
199
200 try:
201 model_path = find_ufo_path(model_name)
202 except UFOImportError:
203 if '-' not in model_name:
204 if model_name == "mssm":
205 logger.error("mssm model has been replaced by MSSM_SLHA2 model.\n The new model require SLHA2 format. You can use the \"update to_slha2\" command to convert your slha1 param_card.\n That option is available at the time of the edition of the cards.")
206 raise
207 split = model_name.split('-')
208 model_name = '-'.join([text for text in split[:-1]])
209 try:
210 model_path = find_ufo_path(model_name)
211 except UFOImportError:
212 if model_name == "mssm":
213 logger.error("mssm model has been replaced by MSSM_SLHA2 model.\n The new model require SLHA2 format. You can use the \"update to_slha2\" command to convert your slha1 param_card.\n That option is available at the time of the edition of the cards.")
214 raise
215 restrict_name = split[-1]
216
217 restrict_file = os.path.join(model_path, 'restrict_%s.dat'% restrict_name)
218
219
220 if split[-1] == 'full':
221 restrict_file = None
222 else:
223
224 restrict_name = ""
225 if restrict and os.path.exists(os.path.join(model_path,'restrict_default.dat')):
226 restrict_file = os.path.join(model_path,'restrict_default.dat')
227 else:
228 restrict_file = None
229
230 if isinstance(restrict, str):
231 if os.path.exists(os.path.join(model_path, restrict)):
232 restrict_file = os.path.join(model_path, restrict)
233 elif os.path.exists(restrict):
234 restrict_file = restrict
235 else:
236 raise Exception, "%s is not a valid path for restrict file" % restrict
237
238
239 model = import_full_model(model_path, decay, prefix)
240
241 if os.path.exists(pjoin(model_path, "README")):
242 logger.info("Please read carefully the README of the model file for instructions/restrictions of the model.",'$MG:color:BLACK')
243
244 if restrict_name:
245 model["name"] += '-' + restrict_name
246
247
248 useCMS = (complex_mass_scheme is None and aloha.complex_mass) or \
249 complex_mass_scheme==True
250
251 if restrict_file:
252 try:
253 logger.info('Restrict model %s with file %s .' % (model_name, os.path.relpath(restrict_file)))
254 except OSError:
255
256 logger.info('Restrict model %s with file %s .' % (model_name, restrict_file))
257
258 if logger_mod.getEffectiveLevel() > 10:
259 logger.info('Run \"set stdout_level DEBUG\" before import for more information.')
260
261 model = RestrictModel(model)
262
263
264
265 if useCMS:
266
267
268
269
270
271 model.set_parameters_and_couplings(param_card = restrict_file,
272 complex_mass_scheme=False)
273 model.change_mass_to_complex_scheme(toCMS=True)
274 else:
275
276
277
278 model.change_mass_to_complex_scheme(toCMS=False)
279
280 blocks = model.get_param_block()
281 if model_name == 'mssm' or os.path.basename(model_name) == 'mssm':
282 keep_external=True
283 elif all( b in blocks for b in ['USQMIX', 'SL2', 'MSOFT', 'YE', 'NMIX', 'TU','MSE2','UPMNS']):
284 keep_external=True
285 elif model_name == 'MSSM_SLHA2' or os.path.basename(model_name) == 'MSSM_SLHA2':
286 keep_external=True
287 else:
288 keep_external=False
289 if keep_external:
290 logger.info('Detect SLHA2 format. keeping restricted parameter in the param_card')
291
292 model.restrict_model(restrict_file, rm_parameter=not decay,
293 keep_external=keep_external, complex_mass_scheme=complex_mass_scheme)
294 model.path = model_path
295 else:
296
297 if useCMS:
298 model.change_mass_to_complex_scheme(toCMS=True)
299 else:
300
301 model.change_mass_to_complex_scheme(toCMS=False)
302
303 return model
304
305
306 _import_once = []
308 """ a practical and efficient way to import one of those models
309 (no restriction file use)"""
310
311 assert model_path == find_ufo_path(model_path)
312
313 if prefix is True:
314 prefix='mdl_'
315
316
317 files_list_prov = ['couplings.py','lorentz.py','parameters.py',
318 'particles.py', 'vertices.py', 'function_library.py',
319 'propagators.py', 'coupling_orders.py']
320
321 if decay:
322 files_list_prov.append('decays.py')
323
324 files_list = []
325 for filename in files_list_prov:
326 filepath = os.path.join(model_path, filename)
327 if not os.path.isfile(filepath):
328 if filename not in ['propagators.py', 'decays.py', 'coupling_orders.py']:
329 raise UFOImportError, "%s directory is not a valid UFO model: \n %s is missing" % \
330 (model_path, filename)
331 files_list.append(filepath)
332
333 if aloha.unitary_gauge:
334 pickle_name = 'model.pkl'
335 else:
336 pickle_name = 'model_Feynman.pkl'
337 if decay:
338 pickle_name = 'dec_%s' % pickle_name
339
340 allow_reload = False
341 if files.is_uptodate(os.path.join(model_path, pickle_name), files_list):
342 allow_reload = True
343 try:
344 model = save_load_object.load_from_file( \
345 os.path.join(model_path, pickle_name))
346 except Exception, error:
347 logger.info('failed to load model from pickle file. Try importing UFO from File')
348 else:
349
350 if model.has_key('version_tag') and not model.get('version_tag') is None and \
351 model.get('version_tag').startswith(os.path.realpath(model_path)) and \
352 model.get('version_tag').endswith('##' + str(misc.get_pkg_info())):
353
354 for key in model.get('parameters'):
355 for param in model['parameters'][key]:
356 value = param.name.lower()
357 if value in ['as','mu_r', 'zero','aewm1']:
358 continue
359 if prefix:
360 if value.startswith(prefix):
361 _import_once.append((model_path, aloha.unitary_gauge, prefix, decay))
362 return model
363 else:
364 logger.info('reload from .py file')
365 break
366 else:
367 if value.startswith('mdl_'):
368 logger.info('reload from .py file')
369 break
370 else:
371 _import_once.append((model_path, aloha.unitary_gauge, prefix, decay))
372 return model
373 else:
374 continue
375 break
376 else:
377 logger.info('reload from .py file')
378
379 if (model_path, aloha.unitary_gauge, prefix, decay) in _import_once and not allow_reload:
380 raise MadGraph5Error, 'This model %s is modified on disk. To reload it you need to quit/relaunch MG5_aMC ' % model_path
381
382
383 ufo_model = ufomodels.load_model(model_path, decay)
384 ufo2mg5_converter = UFOMG5Converter(ufo_model)
385 model = ufo2mg5_converter.load_model()
386 if model_path[-1] == '/': model_path = model_path[:-1]
387 model.set('name', os.path.split(model_path)[-1])
388
389
390 parameters, couplings = OrganizeModelExpression(ufo_model).main(\
391 additional_couplings =(ufo2mg5_converter.wavefunction_CT_couplings
392 if ufo2mg5_converter.perturbation_couplings else []))
393
394 model.set('parameters', parameters)
395 model.set('couplings', couplings)
396 model.set('functions', ufo_model.all_functions)
397
398
399
400
401 if decay and hasattr(ufo_model, 'all_decays') and ufo_model.all_decays:
402 start = time.time()
403 for ufo_part in ufo_model.all_particles:
404 name = ufo_part.name
405 if not model['case_sensitive']:
406 name = name.lower()
407 p = model['particles'].find_name(name)
408 if hasattr(ufo_part, 'partial_widths'):
409 p.partial_widths = ufo_part.partial_widths
410 elif p and not hasattr(p, 'partial_widths'):
411 p.partial_widths = {}
412
413 logger.debug("load width takes %s", time.time()-start)
414
415 if prefix:
416 start = time.time()
417 model.change_parameter_name_with_prefix()
418 logger.debug("model prefixing takes %s", time.time()-start)
419
420 path = os.path.dirname(os.path.realpath(model_path))
421 path = os.path.join(path, model.get('name'))
422 model.set('version_tag', os.path.realpath(path) +'##'+ str(misc.get_pkg_info()))
423
424
425 if ReadWrite and model['allow_pickle']:
426 save_load_object.save_to_file(os.path.join(model_path, pickle_name),
427 model, log=False)
428
429
430
431
432
433
434 return model
435
437 """Convert a UFO model to the MG5 format"""
438
440 """ initialize empty list for particles/interactions """
441
442 if hasattr(model, '__arxiv__'):
443 logger.info('Please cite %s when using this model', model.__arxiv__, '$MG:color:BLACK')
444
445 self.particles = base_objects.ParticleList()
446 self.interactions = base_objects.InteractionList()
447 self.non_qcd_gluon_emission = 0
448
449 self.wavefunction_CT_couplings = []
450
451
452
453
454 self.perturbation_couplings = {}
455 try:
456 for order in model.all_orders:
457 if(order.perturbative_expansion>0):
458 self.perturbation_couplings[order.name]=order.perturbative_expansion
459 except AttributeError,error:
460 pass
461
462 if self.perturbation_couplings!={}:
463 self.model = loop_base_objects.LoopModel({'perturbation_couplings':\
464 self.perturbation_couplings.keys()})
465 else:
466 self.model = base_objects.Model()
467 self.model.set('particles', self.particles)
468 self.model.set('interactions', self.interactions)
469 self.conservecharge = set(['charge'])
470
471 self.ufomodel = model
472 self.checked_lor = set()
473
474 if auto:
475 self.load_model()
476
478 """load the different of the model first particles then interactions"""
479
480
481
482 def_name = []
483 for param in self.ufomodel.all_parameters:
484 if param.nature == "external":
485 if len(param.lhablock.split())>1:
486 raise InvalidModel, '''LHABlock should be single word which is not the case for
487 \'%s\' parameter with lhablock \'%s\' ''' % (param.name, param.lhablock)
488 if param.name in def_name:
489 raise InvalidModel, "name %s define multiple time. Please correct the UFO model!" \
490 % (param.name)
491 else:
492 def_name.append(param.name)
493
494
495
496 if hasattr(self.ufomodel,'all_CTparameters'):
497 for CTparam in self.ufomodel.all_CTparameters:
498 for pole in pole_dict:
499 if CTparam.pole(pole)!='ZERO':
500 new_param_name = '%s_%s_'%(CTparam.name,pole_dict[pole])
501 if new_param_name in def_name:
502 raise InvalidModel, "CT name %s"% (new_param_name)+\
503 " the model. Please change its name."
504
505 if hasattr(self.ufomodel, 'gauge'):
506 self.model.set('gauge', self.ufomodel.gauge)
507 logger.info('load particles')
508
509
510 if len(set([p.name for p in self.ufomodel.all_particles] + \
511 [p.antiname for p in self.ufomodel.all_particles])) == \
512 len(set([p.name.lower() for p in self.ufomodel.all_particles] + \
513 [p.antiname.lower() for p in self.ufomodel.all_particles])):
514 self.model['case_sensitive'] = False
515
516
517
518 self.detect_incoming_fermion()
519
520 for particle_info in self.ufomodel.all_particles:
521 self.add_particle(particle_info)
522
523
524 color_info = self.find_color_anti_color_rep()
525
526
527 self.model.set('lorentz', list(self.ufomodel.all_lorentz))
528
529
530
531
532
533
534
535
536
537 if hasattr(self.ufomodel,'all_CTparameters'):
538 logger.debug('Handling couplings defined with CTparameters...')
539 start_treat_coupling = time.time()
540 self.treat_couplings(self.ufomodel.all_couplings,
541 self.ufomodel.all_CTparameters)
542 tot_time = time.time()-start_treat_coupling
543 if tot_time>5.0:
544 logger.debug('... done in %s'%misc.format_time(tot_time))
545
546 logger.info('load vertices')
547 for interaction_info in self.ufomodel.all_vertices:
548 self.add_interaction(interaction_info, color_info)
549
550 if self.non_qcd_gluon_emission:
551 logger.critical("Model with non QCD emission of gluon (found %i of those).\n This type of model is not fully supported within MG5aMC.\n"+\
552 " Restriction on LO dynamical scale and MLM matching/merging can occur for some processes.\n"+\
553 " Use such features with care.", self.non_qcd_gluon_emission)
554
555 self.model['allow_pickle'] = False
556 self.model['limitations'].append('MLM')
557
558 if self.perturbation_couplings:
559 try:
560 self.ufomodel.add_NLO()
561 except Exception, error:
562 pass
563
564 for interaction_info in self.ufomodel.all_CTvertices:
565 self.add_CTinteraction(interaction_info, color_info)
566
567
568 for interaction in list(self.interactions):
569 self.optimise_interaction(interaction)
570 if not interaction['couplings']:
571 self.interactions.remove(interaction)
572
573
574 self.model.set('conserved_charge', self.conservecharge)
575
576
577
578
579 all_orders = []
580 try:
581 all_orders = self.ufomodel.all_orders
582 except AttributeError:
583 if self.perturbation_couplings:
584 raise MadGraph5Error, "The loop model MG5 attemps to import does not specify the attribute 'all_order'."
585 else:
586 pass
587
588 hierarchy={}
589 try:
590 for order in all_orders:
591 hierarchy[order.name]=order.hierarchy
592 except AttributeError:
593 if self.perturbation_couplings:
594 raise MadGraph5Error, 'The loop model MG5 attemps to import does not specify an order hierarchy.'
595 else:
596 pass
597 else:
598 self.model.set('order_hierarchy', hierarchy)
599
600
601 expansion_order={}
602
603 coupling_order_counterterms={}
604 try:
605 for order in all_orders:
606 expansion_order[order.name]=order.expansion_order
607 coupling_order_counterterms[order.name]=order.expansion_order
608 except AttributeError:
609 if self.perturbation_couplings:
610 raise MadGraph5Error, 'The loop model MG5 attemps to import does not specify an expansion_order for all coupling orders.'
611 else:
612 pass
613 else:
614 self.model.set('expansion_order', expansion_order)
615 self.model.set('expansion_order', expansion_order)
616
617
618 del self.checked_lor
619
620 return self.model
621
623
624
625
626
627 if not hasattr(self, 'iden_couplings'):
628 coups = collections.defaultdict(list)
629 coups['0'].append('ZERO')
630 for coupling in self.ufomodel.all_couplings:
631
632 coups[str(coupling.value)].append( coupling.name)
633
634 self.iden_couplings = {}
635 for idens in [c for c in coups.values() if len(c)>1]:
636 for i in range(1, len(idens)):
637 self.iden_couplings[idens[i]] = idens[0]
638
639
640 for key, coup in list(interaction['couplings'].items()):
641 if coup in self.iden_couplings:
642 interaction['couplings'][key] = self.iden_couplings[coup]
643 if interaction['couplings'][key] == 'ZERO':
644 del interaction['couplings'][key]
645
646
647
648
649
650
651
652 to_lor = {}
653 for (color, lor), coup in interaction['couplings'].items():
654 key = (color, coup)
655 if key in to_lor:
656 to_lor[key].append(lor)
657 else:
658 to_lor[key] = [lor]
659
660 nb_reduce = []
661 optimize = False
662 for key in to_lor:
663 if len(to_lor[key]) >1:
664 nb_reduce.append(len(to_lor[key])-1)
665 optimize = True
666
667 if not optimize:
668 return
669
670 if not hasattr(self, 'defined_lorentz_expr'):
671 self.defined_lorentz_expr = {}
672 self.lorentz_info = {}
673 self.lorentz_combine = {}
674 for lor in self.model['lorentz']:
675 self.defined_lorentz_expr[lor.get('structure')] = lor.get('name')
676 self.lorentz_info[lor.get('name')] = lor
677
678 for key in to_lor:
679 if len(to_lor[key]) == 1:
680 continue
681 names = [interaction['lorentz'][i] for i in to_lor[key]]
682 names.sort()
683 if self.lorentz_info[names[0]].get('structure') == 'external':
684 continue
685
686 if tuple(names) in self.lorentz_combine:
687
688 new_name = self.lorentz_combine[tuple(names)]
689 else:
690 new_name = self.add_merge_lorentz(names)
691
692
693 color, coup = key
694 to_remove = [(color, lor) for lor in to_lor[key]]
695 for rm in to_remove:
696 del interaction['couplings'][rm]
697
698
699 if new_name not in [l for l in interaction.get('lorentz')]:
700 interaction.get('lorentz').append(new_name)
701
702
703 new_l = interaction.get('lorentz').index(new_name)
704
705 interaction['couplings'][(color, new_l)] = coup
706
707
709 """add a lorentz structure which is the sume of the list given above"""
710
711
712
713 ii = len(names[0])
714 while ii>0:
715 if not all(n.startswith(names[0][:ii]) for n in names[1:]):
716 ii -=1
717 else:
718 base_name = names[0][:ii]
719 break
720 else:
721 base_name = 'LMER'
722
723 i = 1
724 while '%s%s' %(base_name, i) in self.lorentz_info:
725 i +=1
726 new_name = '%s%s' %(base_name, i)
727 self.lorentz_combine[tuple(names)] = new_name
728 assert new_name not in self.lorentz_info
729 assert new_name not in [l.name for l in self.model['lorentz']]
730
731
732 new_struct = ' + '.join([self.lorentz_info[n].get('structure') for n in names])
733 spins = self.lorentz_info[names[0]].get('spins')
734 formfactors = sum([ self.lorentz_info[n].get('formfactors') for n in names \
735 if hasattr(self.lorentz_info[n], 'formfactors') \
736 and self.lorentz_info[n].get('formfactors') \
737 ],[])
738
739 new_lor = self.add_lorentz(new_name, spins, new_struct, formfactors)
740 self.lorentz_info[new_name] = new_lor
741
742 return new_name
743
744
745
746
747
748
749
750 - def add_particle(self, particle_info):
751 """ convert and add a particle in the particle list """
752
753 loop_particles = [[[]]]
754 counterterms = {}
755
756
757
758 pdg = particle_info.pdg_code
759 if pdg in self.incoming or (pdg not in self.outcoming and pdg <0):
760 return
761
762
763 if not self.perturbation_couplings and particle_info.spin < 0:
764 return
765
766 if (aloha.unitary_gauge and 0 in self.model['gauge']) \
767 or (1 not in self.model['gauge']):
768
769
770 if hasattr(particle_info, 'GoldstoneBoson') and particle_info.GoldstoneBoson:
771 return
772 elif hasattr(particle_info, 'goldstone') and particle_info.goldstone:
773 return
774
775 particle = base_objects.Particle()
776
777
778 if (hasattr(particle_info, 'GoldstoneBoson') and particle_info.GoldstoneBoson) \
779 or (hasattr(particle_info, 'goldstoneboson') and particle_info.goldstoneboson):
780 particle.set('type', 'goldstone')
781 elif hasattr(particle_info, 'goldstone') and particle_info.goldstone:
782 particle.set('type', 'goldstone')
783
784 nb_property = 0
785
786 for key,value in particle_info.__dict__.items():
787
788 if key in base_objects.Particle.sorted_keys and not key=='counterterm':
789 nb_property +=1
790 if key in ['name', 'antiname']:
791 if not self.model['case_sensitive']:
792 particle.set(key, value.lower())
793 else:
794 particle.set(key, value)
795 elif key == 'charge':
796 particle.set(key, float(value))
797 elif key in ['mass','width']:
798 particle.set(key, str(value))
799 elif key == 'spin':
800
801
802 particle.set(key,abs(value))
803 if value<0:
804 particle.set('type','ghost')
805 elif key == 'propagating':
806 if not value:
807 particle.set('line', None)
808 elif key == 'line':
809 if particle.get('line') is None:
810 pass
811 else:
812 particle.set('line', value)
813 elif key == 'propagator':
814 if value:
815 if aloha.unitary_gauge:
816 particle.set(key, str(value[0]))
817 else:
818 particle.set(key, str(value[1]))
819 else:
820 particle.set(key, '')
821 else:
822 particle.set(key, value)
823 elif key == 'loop_particles':
824 loop_particles = value
825 elif key == 'counterterm':
826 counterterms = value
827 elif key.lower() not in ('ghostnumber','selfconjugate','goldstone',
828 'goldstoneboson','partial_widths',
829 'texname', 'antitexname', 'propagating', 'ghost'
830 ):
831
832 self.conservecharge.add(key)
833 particle.set(key,value, force=True)
834
835 if not hasattr(particle_info, 'propagator'):
836 nb_property += 1
837 if particle.get('spin') >= 3:
838 if particle.get('mass').lower() == 'zero':
839 particle.set('propagator', 0)
840 elif particle.get('spin') == 3 and not aloha.unitary_gauge:
841 particle.set('propagator', 0)
842
843 assert(10 == nb_property)
844
845
846 if particle_info.name == particle_info.antiname:
847 particle.set('self_antipart', True)
848
849
850
851 if not self.perturbation_couplings or counterterms=={}:
852 self.particles.append(particle)
853 return
854
855
856
857
858
859
860 particle_counterterms = {}
861 for key, counterterm in counterterms.items():
862
863 if len([1 for k in key[:-1] if k==1])==1 and \
864 not any(k>1 for k in key[:-1]):
865 newParticleCountertermKey=[None,\
866
867
868
869
870
871 tuple([tuple(loop_parts) for\
872 loop_parts in loop_particles[key[-1]]])]
873 for i, order in enumerate(self.ufomodel.all_orders[:-1]):
874 if key[i]==1:
875 newParticleCountertermKey[0]=order.name
876 newCouplingName='UVWfct_'+particle_info.name+'_'+str(key[-1])
877 particle_counterterms[tuple(newParticleCountertermKey)]=\
878 dict([(key,newCouplingName+('' if key==0 else '_'+str(-key)+'eps'))\
879 for key in counterterm])
880
881
882 self.ufomodel.object_library.Coupling(\
883 name = newCouplingName,
884 value = counterterm,
885 order = {newParticleCountertermKey[0]:2})
886 self.wavefunction_CT_couplings.append(self.ufomodel.all_couplings.pop())
887
888 particle.set('counterterm',particle_counterterms)
889 self.particles.append(particle)
890 return
891
893 """ This function scan each coupling to see if it contains a CT parameter.
894 when it does, it changes its value to a dictionary with the CT parameter
895 changed to a new parameter for each pole and finite part. For instance,
896 the following coupling:
897 coupling.value = '2*(myCTParam1 + myParam*(myCTParam2 + myCTParam3)'
898 with CTparameters
899 myCTParam1 = {0: Something, -1: SomethingElse}
900 myCTParam2 = {0: OtherSomething }
901 myCTParam3 = {-1: YetOtherSomething }
902 would be turned into
903 coupling.value = {0: '2*(myCTParam1_FIN_ + myParam*(myCTParam2_FIN_ + ZERO)'
904 -1: '2*(myCTParam1_EPS_ + myParam*(ZERO + myCTParam2_EPS_)'}
905
906 all_CTParameter is the list of all CTParameters in the model"""
907
908
909
910
911
912
913 CTparameter_patterns = {}
914 zero_substitution = lambda matchedObj: matchedObj.group('first')+\
915 'ZERO'+matchedObj.group('second')
916 def function_factory(arg):
917 return lambda matchedObj: \
918 matchedObj.group('first')+arg+matchedObj.group('second')
919 for CTparam in all_CTparameters:
920 pattern_finder = re.compile(r"(?P<first>\A|\*|\+|\-|\(|\s)(?P<name>"+
921 CTparam.name+r")(?P<second>\Z|\*|\+|\-|\)|/|\\|\s)")
922
923 sub_functions = [None if CTparam.pole(pole)=='ZERO' else
924 function_factory('%s_%s_'%(CTparam.name,pole_dict[-pole]))
925 for pole in range(3)]
926 CTparameter_patterns[CTparam.name] = (pattern_finder,sub_functions)
927
928 times_zero = re.compile('\*\s*-?ZERO')
929 zero_times = re.compile('ZERO\s*(\*|\/)')
930 def is_expr_zero(expresson):
931 """ Checks whether a single term (involving only the operations
932 * or / is zero. """
933 for term in expresson.split('-'):
934 for t in term.split('+'):
935 t = t.strip()
936 if t in ['ZERO','']:
937 continue
938 if not (times_zero.search(t) or zero_times.search(t)):
939 return False
940 return True
941
942 def find_parenthesis(expr):
943 end = expr.find(')')
944 if end == -1:
945 return None
946 start = expr.rfind('(',0,end+1)
947 if start ==-1:
948 raise InvalidModel,\
949 'Parenthesis of expression %s are malformed'%expr
950 return [expr[:start],expr[start+1:end],expr[end+1:]]
951
952 start_parenthesis = re.compile(r".*\s*[\+\-\*\/\)\(]\s*$")
953
954 def is_value_zero(value):
955 """Check whether an expression like ((A+B)*ZERO+C)*ZERO is zero.
956 Only +,-,/,* operations are allowed and 'ZERO' is a tag for an
957 analytically zero quantity."""
958
959 curr_value = value
960 parenthesis = find_parenthesis(curr_value)
961 while parenthesis:
962
963 if parenthesis[0].endswith('complexconjugate'):
964
965 parenthesis[0] = parenthesis[0][:-16]
966 if parenthesis[0]=='' or re.match(start_parenthesis,
967 parenthesis[0]):
968 if is_value_zero(parenthesis[1]):
969 new_parenthesis = 'ZERO'
970 else:
971 new_parenthesis = 'PARENTHESIS'
972 else:
973 new_parenthesis = '_FUNCTIONARGS'
974 curr_value = parenthesis[0]+new_parenthesis+parenthesis[2]
975 parenthesis = find_parenthesis(curr_value)
976 return is_expr_zero(curr_value)
977
978 def CTCoupling_pole(CTCoupling, pole):
979 """Compute the pole of the CTCoupling in two cases:
980 a) Its value is a dictionary, then just return the corresponding
981 entry in the dictionary.
982 b) It is expressed in terms of CTParameters which are themselves
983 dictionary so we want to substitute their expression to get
984 the value of the pole. In the current implementation, this is
985 just to see if the pole is zero or not.
986 """
987
988 if isinstance(CTCoupling.value,dict):
989 if -pole in CTCoupling.value.keys():
990 return CTCoupling.value[-pole], [], 0
991 else:
992 return 'ZERO', [], 0
993
994 new_expression = CTCoupling.value
995 CTparamNames = []
996 n_CTparams = 0
997 for paramname, value in CTparameter_patterns.items():
998 pattern = value[0]
999
1000
1001 if not re.search(pattern,new_expression):
1002 continue
1003 n_CTparams += 1
1004
1005
1006 if not value[1][pole] is None:
1007 CTparamNames.append('%s_%s_'%(paramname,pole_dict[-pole]))
1008
1009 substitute_function = zero_substitution if \
1010 value[1][pole] is None else value[1][pole]
1011 new_expression = pattern.sub(substitute_function,new_expression)
1012
1013
1014
1015 if pole!=0 and n_CTparams==0:
1016 return 'ZERO', [], n_CTparams
1017
1018
1019
1020
1021
1022
1023 if n_CTparams > 0 and is_value_zero(new_expression):
1024 return 'ZERO', [], n_CTparams
1025 else:
1026 return new_expression, CTparamNames, n_CTparams
1027
1028
1029 for coupl in couplings:
1030 new_value = {}
1031 for pole in range(0,3):
1032 expression, CTparamNames, n_CTparams = CTCoupling_pole(coupl, pole)
1033
1034 if n_CTparams == 0:
1035 break
1036 elif expression!='ZERO':
1037 new_value[-pole] = expression
1038 couplname = coupl.name
1039 if pole!=0:
1040 couplname += "_%deps"%pole
1041
1042
1043
1044
1045 if hasattr(self.model, 'map_CTcoup_CTparam'):
1046 self.model.map_CTcoup_CTparam[couplname] = CTparamNames
1047
1048
1049
1050
1051
1052
1053
1054
1055 if new_value:
1056 coupl.old_value = coupl.value
1057 coupl.value = new_value
1058
1060 """ Split this interaction in order to call add_interaction for
1061 interactions for each element of the loop_particles list. Also it
1062 is necessary to unfold here the contributions to the different laurent
1063 expansion orders of the couplings."""
1064
1065
1066 interaction_info=copy.copy(interaction)
1067
1068 intType=''
1069 if interaction_info.type not in ['UV','UVloop','UVtree','UVmass','R2']:
1070 raise MadGraph5Error, 'MG5 only supports the following types of'+\
1071 ' vertices, R2, UV and UVmass. %s is not in this list.'%interaction_info.type
1072 else:
1073 intType=interaction_info.type
1074
1075 if interaction_info.type=='UV':
1076 if len(interaction_info.particles)==2 and interaction_info.\
1077 particles[0].name==interaction_info.particles[1].name:
1078 intType='UVmass'
1079 else:
1080 intType='UVloop'
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093 order_to_interactions= {}
1094
1095
1096
1097
1098
1099 for key, couplings in interaction_info.couplings.items():
1100 if not isinstance(couplings, list):
1101 couplings = [couplings]
1102 for coupling in couplings:
1103 order = tuple(coupling.order.items())
1104 if order not in order_to_interactions:
1105 order_to_interactions[order] = [
1106 [{} for j in range(0,3)] for i in \
1107 range(0,max(1,len(interaction_info.loop_particles)))]
1108 new_couplings = order_to_interactions[order]
1109 else:
1110 new_couplings = order_to_interactions[order]
1111
1112 for poleOrder in range(0,3):
1113 expression = coupling.pole(poleOrder)
1114 if expression!='ZERO':
1115 if poleOrder==2:
1116 raise InvalidModel, """
1117 The CT coupling %s was found with a contribution to the double pole.
1118 This is either an error in the model or a parsing error in the function 'is_value_zero'.
1119 The expression of the non-zero double pole coupling is:
1120 %s
1121 """%(coupling.name,str(coupling.value))
1122
1123
1124
1125 newCoupling = copy.copy(coupling)
1126 if poleOrder!=0:
1127 newCoupling.name=newCoupling.name+"_"+str(poleOrder)+"eps"
1128 newCoupling.value = expression
1129
1130
1131
1132
1133
1134
1135
1136 new_couplings[key[2]][poleOrder][(key[0],key[1])] = newCoupling
1137
1138 for new_couplings in order_to_interactions.values():
1139
1140 for i, all_couplings in enumerate(new_couplings):
1141 loop_particles=[[]]
1142 if len(interaction_info.loop_particles)>0:
1143 loop_particles=[[part.pdg_code for part in loop_parts] \
1144 for loop_parts in interaction_info.loop_particles[i]]
1145 for poleOrder in range(0,3):
1146 if all_couplings[poleOrder]!={}:
1147 interaction_info.couplings=all_couplings[poleOrder]
1148 self.add_interaction(interaction_info, color_info,\
1149 (intType if poleOrder==0 else (intType+str(poleOrder)+\
1150 'eps')),loop_particles)
1151
1153 """find which color are in the 3/3bar states"""
1154
1155
1156
1157
1158 if not output:
1159 output = {}
1160
1161 for interaction_info in self.ufomodel.all_vertices:
1162 if len(interaction_info.particles) != 3:
1163 continue
1164 colors = [abs(p.color) for p in interaction_info.particles]
1165 if colors[:2] == [3,3]:
1166 if 'T(3,2,1)' in interaction_info.color:
1167 color, anticolor, other = interaction_info.particles
1168 elif 'T(3,1,2)' in interaction_info.color:
1169 anticolor, color, _ = interaction_info.particles
1170 elif 'Identity(1,2)' in interaction_info.color or \
1171 'Identity(2,1)' in interaction_info.color:
1172 first, second, _ = interaction_info.particles
1173 if first.pdg_code in output:
1174 if output[first.pdg_code] == 3:
1175 color, anticolor = first, second
1176 else:
1177 color, anticolor = second, first
1178 elif second.pdg_code in output:
1179 if output[second.pdg_code] == 3:
1180 color, anticolor = second, first
1181 else:
1182 color, anticolor = first, second
1183 else:
1184 continue
1185 else:
1186 continue
1187 elif colors[1:] == [3,3]:
1188 if 'T(1,2,3)' in interaction_info.color:
1189 other, anticolor, color = interaction_info.particles
1190 elif 'T(1,3,2)' in interaction_info.color:
1191 other, color, anticolor = interaction_info.particles
1192 elif 'Identity(2,3)' in interaction_info.color or \
1193 'Identity(3,2)' in interaction_info.color:
1194 _, first, second = interaction_info.particles
1195 if first.pdg_code in output:
1196 if output[first.pdg_code] == 3:
1197 color, anticolor = first, second
1198 else:
1199 color, anticolor = second, first
1200 elif second.pdg_code in output:
1201 if output[second.pdg_code] == 3:
1202 color, anticolor = second, first
1203 else:
1204 color, anticolor = first, second
1205 else:
1206 continue
1207 else:
1208 continue
1209
1210 elif colors.count(3) == 2:
1211 if 'T(2,3,1)' in interaction_info.color:
1212 color, other, anticolor = interaction_info.particles
1213 elif 'T(2,1,3)' in interaction_info.color:
1214 anticolor, other, color = interaction_info.particles
1215 elif 'Identity(1,3)' in interaction_info.color or \
1216 'Identity(3,1)' in interaction_info.color:
1217 first, _, second = interaction_info.particles
1218 if first.pdg_code in output:
1219 if output[first.pdg_code] == 3:
1220 color, anticolor = first, second
1221 else:
1222 color, anticolor = second, first
1223 elif second.pdg_code in output:
1224 if output[second.pdg_code] == 3:
1225 color, anticolor = second, first
1226 else:
1227 color, anticolor = first, second
1228 else:
1229 continue
1230 else:
1231 continue
1232 else:
1233 continue
1234
1235
1236 if color.pdg_code in output:
1237 if output[color.pdg_code] == -3:
1238 raise InvalidModel, 'Particles %s is sometimes in the 3 and sometimes in the 3bar representations' \
1239 % color.name
1240 else:
1241 output[color.pdg_code] = 3
1242
1243
1244 if anticolor.pdg_code in output:
1245 if output[anticolor.pdg_code] == 3:
1246 raise InvalidModel, 'Particles %s is sometimes set as in the 3 and sometimes in the 3bar representations' \
1247 % anticolor.name
1248 else:
1249 output[anticolor.pdg_code] = -3
1250
1251 return output
1252
1254 """define which fermion should be incoming
1255 for that we look at F F~ X interactions
1256 """
1257 self.incoming = []
1258 self.outcoming = []
1259 for interaction_info in self.ufomodel.all_vertices:
1260
1261 pdg = [p.pdg_code for p in interaction_info.particles if p.spin in [2,4]]
1262 if len(pdg) % 2:
1263 raise InvalidModel, 'Odd number of fermion in vertex: %s' % [p.pdg_code for p in interaction_info.particles]
1264 for i in range(0, len(pdg),2):
1265 if pdg[i] == - pdg[i+1]:
1266 if pdg[i] in self.outcoming:
1267 raise InvalidModel, '%s has not coherent incoming/outcoming status between interactions' %\
1268 [p for p in interaction_info.particles if p.spin in [2,4]][i].name
1269
1270 elif not pdg[i] in self.incoming:
1271 self.incoming.append(pdg[i])
1272 self.outcoming.append(pdg[i+1])
1273
1274 - def add_interaction(self, interaction_info, color_info, type='base', loop_particles=None):
1275 """add an interaction in the MG5 model. interaction_info is the
1276 UFO vertices information."""
1277
1278 particles = [self.model.get_particle(particle.pdg_code) \
1279 for particle in interaction_info.particles]
1280 if None in particles:
1281
1282 return
1283 particles = base_objects.ParticleList(particles)
1284
1285
1286 lorentz = [helas for helas in interaction_info.lorentz]
1287
1288
1289 nb_fermion = sum([ 1 if p.is_fermion() else 0 for p in particles])
1290 try:
1291 if nb_fermion == 2:
1292
1293 [aloha_fct.check_flow_validity(helas.structure, nb_fermion) \
1294 for helas in interaction_info.lorentz
1295 if helas.name not in self.checked_lor]
1296 self.checked_lor.update(set([helas.name for helas in interaction_info.lorentz]))
1297 elif nb_fermion:
1298 if any(p.selfconjugate for p in interaction_info.particles if p.spin % 2 == 0):
1299 text = "Majorana can not be dealt in 4/6/... fermion interactions"
1300 raise InvalidModel, text
1301 except aloha_fct.WrongFermionFlow, error:
1302 text = 'Fermion Flow error for interactions %s: %s: %s\n %s' % \
1303 (', '.join([p.name for p in interaction_info.particles]),
1304 helas.name, helas.structure, error)
1305 raise InvalidModel, text
1306
1307
1308
1309
1310
1311 lorentz = [helas.name for helas in lorentz]
1312
1313 colors = [self.treat_color(color_obj, interaction_info, color_info)
1314 for color_obj in interaction_info.color]
1315
1316
1317 order_to_int={}
1318
1319 for key, couplings in interaction_info.couplings.items():
1320 if not isinstance(couplings, list):
1321 couplings = [couplings]
1322 if interaction_info.lorentz[key[1]].name not in lorentz:
1323 continue
1324
1325 if nb_fermion > 2:
1326 flow = aloha_fct.get_fermion_flow(interaction_info.lorentz[key[1]].structure,
1327 nb_fermion)
1328 coupling_sign = self.get_sign_flow(flow, nb_fermion)
1329 else:
1330 coupling_sign = ''
1331 for coupling in couplings:
1332 order = tuple(coupling.order.items())
1333
1334 if '1' in coupling.order:
1335 raise InvalidModel, '''Some couplings have \'1\' order.
1336 This is not allowed in MG.
1337 Please defines an additional coupling to your model'''
1338
1339 if 21 in [particle.pdg_code for particle in interaction_info.particles] and\
1340 'QCD' not in coupling.order:
1341 col = [par.get('color') for par in particles]
1342 if 1 not in col:
1343 self.non_qcd_gluon_emission +=1
1344
1345 if order in order_to_int:
1346 order_to_int[order].get('couplings')[key] = '%s%s' % \
1347 (coupling_sign,coupling.name)
1348 else:
1349
1350 interaction = base_objects.Interaction({'id':len(self.interactions)+1})
1351 interaction.set('particles', particles)
1352 interaction.set('lorentz', lorentz)
1353 interaction.set('couplings', {key:
1354 '%s%s' %(coupling_sign,coupling.name)})
1355 interaction.set('orders', coupling.order)
1356 interaction.set('color', colors)
1357 interaction.set('type', type)
1358 interaction.set('loop_particles', loop_particles)
1359 order_to_int[order] = interaction
1360
1361 self.interactions.append(interaction)
1362
1363
1364
1365
1366 for charge in list(self.conservecharge):
1367 total = 0
1368 for part in interaction_info.particles:
1369 try:
1370 total += getattr(part, charge)
1371 except AttributeError:
1372 pass
1373 if abs(total) > 1e-12:
1374 logger.info('The model has interaction violating the charge: %s' % charge)
1375 self.conservecharge.discard(charge)
1376
1377
1378
1380 """ensure that the flow of particles/lorentz are coherent with flow
1381 and return a correct version if needed"""
1382
1383 if not flow or nb_fermion < 4:
1384 return ''
1385
1386 expected = {}
1387 for i in range(nb_fermion//2):
1388 expected[i+1] = i+2
1389
1390 if flow == expected:
1391 return ''
1392
1393 switch = {}
1394 for i in range(1, nb_fermion+1):
1395 if not i in flow:
1396 continue
1397 switch[i] = len(switch)
1398 switch[flow[i]] = len(switch)
1399
1400
1401 sign = 1
1402 done = []
1403
1404
1405
1406 new_order = []
1407 for id in range(nb_fermion):
1408 nid = switch[id+1]-1
1409
1410 new_order.append(nid)
1411
1412
1413 sign =1
1414 for k in range(len(new_order)-1):
1415 for l in range(k+1,len(new_order)):
1416 if new_order[l] < new_order[k]:
1417 sign *= -1
1418
1419 return '' if sign ==1 else '-'
1420
1421 - def add_lorentz(self, name, spins , expr, formfact=None):
1422 """ Add a Lorentz expression which is not present in the UFO """
1423
1424 logger.debug('MG5 converter defines %s to %s', name, expr)
1425 assert name not in [l.name for l in self.model['lorentz']]
1426 with misc.TMP_variable(self.ufomodel.object_library, 'all_lorentz',
1427 self.model['lorentz']):
1428 new = self.model['lorentz'][0].__class__(name = name,
1429 spins = spins,
1430 structure = expr)
1431 if formfact:
1432 new.formfactors = formfact
1433
1434 assert name in [l.name for l in self.model['lorentz']]
1435 assert name not in [l.name for l in self.ufomodel.all_lorentz]
1436
1437 self.model.create_lorentz_dict()
1438 return new
1439
1440 _pat_T = re.compile(r'T\((?P<first>\d*),(?P<second>\d*)\)')
1441 _pat_id = re.compile(r'Identity\((?P<first>\d*),(?P<second>\d*)\)')
1442
1443 - def treat_color(self, data_string, interaction_info, color_info):
1444 """ convert the string to ColorString"""
1445
1446
1447
1448
1449
1450 output = []
1451 factor = 1
1452 for term in data_string.split('*'):
1453 pattern = self._pat_id.search(term)
1454 if pattern:
1455 particle = interaction_info.particles[int(pattern.group('first'))-1]
1456 particle2 = interaction_info.particles[int(pattern.group('second'))-1]
1457 if particle.color == particle2.color and particle.color in [-6, 6]:
1458 error_msg = 'UFO model have inconsistency in the format:\n'
1459 error_msg += 'interactions for particles %s has color information %s\n'
1460 error_msg += ' but both fermion are in the same representation %s'
1461 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
1462 if particle.color == particle2.color and particle.color in [-3, 3]:
1463 if particle.pdg_code in color_info and particle2.pdg_code in color_info:
1464 if color_info[particle.pdg_code] == color_info[particle2.pdg_code]:
1465 error_msg = 'UFO model have inconsistency in the format:\n'
1466 error_msg += 'interactions for particles %s has color information %s\n'
1467 error_msg += ' but both fermion are in the same representation %s'
1468 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
1469 elif particle.pdg_code in color_info:
1470 color_info[particle2.pdg_code] = -particle.pdg_code
1471 elif particle2.pdg_code in color_info:
1472 color_info[particle.pdg_code] = -particle2.pdg_code
1473 else:
1474 error_msg = 'UFO model have inconsistency in the format:\n'
1475 error_msg += 'interactions for particles %s has color information %s\n'
1476 error_msg += ' but both fermion are in the same representation %s'
1477 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
1478
1479
1480 if particle.color == 6:
1481 output.append(self._pat_id.sub('color.T6(\g<first>,\g<second>)', term))
1482 elif particle.color == -6 :
1483 output.append(self._pat_id.sub('color.T6(\g<second>,\g<first>)', term))
1484 elif particle.color == 8:
1485 output.append(self._pat_id.sub('color.Tr(\g<first>,\g<second>)', term))
1486 factor *= 2
1487 elif particle.color in [-3,3]:
1488 if particle.pdg_code not in color_info:
1489
1490 logger.debug('fail to find 3/3bar representation: Retry to find it')
1491 color_info = self.find_color_anti_color_rep(color_info)
1492 if particle.pdg_code not in color_info:
1493 logger.debug('Not able to find the 3/3bar rep from the interactions for particle %s' % particle.name)
1494 color_info[particle.pdg_code] = particle.color
1495 else:
1496 logger.debug('succeed')
1497 if particle2.pdg_code not in color_info:
1498
1499 logger.debug('fail to find 3/3bar representation: Retry to find it')
1500 color_info = self.find_color_anti_color_rep(color_info)
1501 if particle2.pdg_code not in color_info:
1502 logger.debug('Not able to find the 3/3bar rep from the interactions for particle %s' % particle2.name)
1503 color_info[particle2.pdg_code] = particle2.color
1504 else:
1505 logger.debug('succeed')
1506
1507 if color_info[particle.pdg_code] == 3 :
1508 output.append(self._pat_id.sub('color.T(\g<second>,\g<first>)', term))
1509 elif color_info[particle.pdg_code] == -3:
1510 output.append(self._pat_id.sub('color.T(\g<first>,\g<second>)', term))
1511 else:
1512 raise MadGraph5Error, \
1513 "Unknown use of Identity for particle with color %d" \
1514 % particle.color
1515 else:
1516 output.append(term)
1517 data_string = '*'.join(output)
1518
1519
1520 p = re.compile(r'\'\w(?P<number>\d+)\'')
1521 data_string = p.sub('-\g<number>', data_string)
1522
1523
1524 new_indices = {}
1525 new_indices = dict([(j,i) for (i,j) in \
1526 enumerate(range(1,
1527 len(interaction_info.particles)+1))])
1528
1529
1530 output = data_string.split('*')
1531 output = color.ColorString([eval(data) \
1532 for data in output if data !='1'])
1533 output.coeff = fractions.Fraction(factor)
1534 for col_obj in output:
1535 col_obj.replace_indices(new_indices)
1536
1537 return output
1538
1540 """Organize the couplings/parameters of a model"""
1541
1542 track_dependant = ['aS','aEWM1','MU_R']
1543
1544
1545
1546
1547 complex_number = re.compile(r'''complex\((?P<real>[^,\(\)]+),(?P<imag>[^,\(\)]+)\)''')
1548 expo_expr = re.compile(r'''(?P<expr>[\w.]+)\s*\*\*\s*(?P<expo>[+-]?[\d.]+)''')
1549 cmath_expr = re.compile(r'''cmath.(?P<operation>\w+)\((?P<expr>\w+)\)''')
1550
1551 conj_expr = re.compile(r'''complexconjugate\((?P<expr>\w+)\)''')
1552
1553
1554 separator = re.compile(r'''[+,\-*/()\s]*''')
1555
1556
1558
1559 self.model = model
1560 self.perturbation_couplings = {}
1561 try:
1562 for order in model.all_orders:
1563 if(order.perturbative_expansion>0):
1564 self.perturbation_couplings[order.name]=order.perturbative_expansion
1565 except AttributeError:
1566 pass
1567 self.params = {}
1568 self.couplings = {}
1569 self.all_expr = {}
1570
1571 - def main(self, additional_couplings = []):
1572 """Launch the actual computation and return the associate
1573 params/couplings. Possibly consider additional_couplings in addition
1574 to those defined in the UFO model attribute all_couplings """
1575
1576 additional_params = []
1577 if hasattr(self.model,'all_CTparameters'):
1578 additional_params = self.get_additional_CTparameters()
1579
1580 self.analyze_parameters(additional_params = additional_params)
1581 self.analyze_couplings(additional_couplings = additional_couplings)
1582
1583
1584 if hasattr(self.model,'all_CTparameters'):
1585 self.revert_CTCoupling_modifications()
1586
1587 return self.params, self.couplings
1588
1590 """ Finally revert the possible modifications done by treat_couplings()
1591 in UFOMG5Converter which were useful for the add_CTinteraction() in
1592 particular. This modification consisted in expanding the value of a
1593 CTCoupling which consisted in an expression in terms of a CTParam to
1594 its corresponding dictionary (e.g
1595 CTCoupling.value = 2*CTParam ->
1596 CTCoupling.value = {-1: 2*CTParam_1EPS_, 0: 2*CTParam_FIN_}
1597 for example if CTParam had a non-zero finite and single pole."""
1598
1599 for coupl in self.model.all_couplings:
1600 if hasattr(coupl,'old_value'):
1601 coupl.value = coupl.old_value
1602 del(coupl.old_value)
1603
1605 """ For each CTparameter split it into spimple parameter for each pole
1606 and the finite part if not zero."""
1607
1608 additional_params = []
1609 for CTparam in self.model.all_CTparameters:
1610 for pole in range(3):
1611 if CTparam.pole(pole) != 'ZERO':
1612 CTparam_piece = copy.copy(CTparam)
1613 CTparam_piece.name = '%s_%s_'%(CTparam.name,pole_dict[-pole])
1614 CTparam_piece.nature = 'internal'
1615 CTparam_piece.type = CTparam.type
1616 CTparam_piece.value = CTparam.pole(pole)
1617 CTparam_piece.texname = '%s_{%s}'%\
1618 (CTparam.texname,pole_dict[-pole])
1619 additional_params.append(CTparam_piece)
1620 return additional_params
1621
1623 """ separate the parameters needed to be recomputed events by events and
1624 the others"""
1625
1626
1627
1628 present_aEWM1 = any(param.name == 'aEWM1' for param in
1629 self.model.all_parameters if param.nature == 'external')
1630
1631 if not present_aEWM1:
1632 self.track_dependant = ['aS','Gf','MU_R']
1633
1634 for param in self.model.all_parameters+additional_params:
1635 if param.nature == 'external':
1636 parameter = base_objects.ParamCardVariable(param.name, param.value, \
1637 param.lhablock, param.lhacode)
1638
1639 else:
1640 expr = self.shorten_expr(param.value)
1641 depend_on = self.find_dependencies(expr)
1642 parameter = base_objects.ModelVariable(param.name, expr, param.type, depend_on)
1643
1644 self.add_parameter(parameter)
1645
1647 """ add consistently the parameter in params and all_expr.
1648 avoid duplication """
1649
1650 assert isinstance(parameter, base_objects.ModelVariable)
1651
1652 if parameter.name in self.all_expr:
1653 return
1654
1655 self.all_expr[parameter.name] = parameter
1656 try:
1657 self.params[parameter.depend].append(parameter)
1658 except:
1659 self.params[parameter.depend] = [parameter]
1660
1662 """ add consistently the coupling in couplings and all_expr.
1663 avoid duplication """
1664
1665 assert isinstance(coupling, base_objects.ModelVariable)
1666
1667 if coupling.name in self.all_expr:
1668 return
1669 self.all_expr[coupling.value] = coupling
1670 try:
1671 self.coupling[coupling.depend].append(coupling)
1672 except:
1673 self.coupling[coupling.depend] = [coupling]
1674
1676 """creates the shortcut for all special function/parameter
1677 separate the couplings dependent of track variables of the others"""
1678
1679
1680
1681 if self.perturbation_couplings:
1682 couplings_list=[]
1683 for coupling in self.model.all_couplings + additional_couplings:
1684 if not isinstance(coupling.value,dict):
1685 couplings_list.append(coupling)
1686 else:
1687 for poleOrder in range(0,3):
1688 if coupling.pole(poleOrder)!='ZERO':
1689 newCoupling=copy.copy(coupling)
1690 if poleOrder!=0:
1691 newCoupling.name += "_%deps"%poleOrder
1692 newCoupling.value=coupling.pole(poleOrder)
1693
1694
1695
1696
1697
1698
1699
1700 couplings_list.append(newCoupling)
1701 else:
1702 couplings_list = self.model.all_couplings + additional_couplings
1703 couplings_list = [c for c in couplings_list if not isinstance(c.value, dict)]
1704
1705 for coupling in couplings_list:
1706
1707 expr = self.shorten_expr(coupling.value)
1708 depend_on = self.find_dependencies(expr)
1709 parameter = base_objects.ModelVariable(coupling.name, expr, 'complex', depend_on)
1710
1711 try:
1712 self.couplings[depend_on].append(parameter)
1713 except KeyError:
1714 self.couplings[depend_on] = [parameter]
1715 self.all_expr[coupling.value] = parameter
1716
1718 """check if an expression should be evaluated points by points or not
1719 """
1720 depend_on = set()
1721
1722
1723
1724
1725
1726
1727
1728 expr = self.separator.split(expr)
1729
1730
1731 for subexpr in expr:
1732 if subexpr in self.track_dependant:
1733 depend_on.add(subexpr)
1734
1735 elif subexpr in self.all_expr and self.all_expr[subexpr].depend:
1736 [depend_on.add(value) for value in self.all_expr[subexpr].depend
1737 if self.all_expr[subexpr].depend != ('external',)]
1738 if depend_on:
1739 return tuple(depend_on)
1740 else:
1741 return tuple()
1742
1743
1756
1757
1759 """add the short expression, and return the nice string associate"""
1760
1761 float_real = float(eval(matchobj.group('real')))
1762 float_imag = float(eval(matchobj.group('imag')))
1763 if float_real == 0 and float_imag ==1:
1764 new_param = base_objects.ModelVariable('complexi', 'complex(0,1)', 'complex')
1765 self.add_parameter(new_param)
1766 return 'complexi'
1767 else:
1768 return 'complex(%s, %s)' % (matchobj.group('real'), matchobj.group('imag'))
1769
1770
1772 """add the short expression, and return the nice string associate"""
1773
1774 expr = matchobj.group('expr')
1775 exponent = matchobj.group('expo')
1776 new_exponent = exponent.replace('.','_').replace('+','').replace('-','_m_')
1777 output = '%s__exp__%s' % (expr, new_exponent)
1778 old_expr = '%s**%s' % (expr,exponent)
1779
1780 if expr.startswith('cmath'):
1781 return old_expr
1782
1783 if expr.isdigit():
1784 output = 'nb__' + output
1785 new_param = base_objects.ModelVariable(output, old_expr,'real')
1786 else:
1787 depend_on = self.find_dependencies(expr)
1788 type = self.search_type(expr)
1789 new_param = base_objects.ModelVariable(output, old_expr, type, depend_on)
1790 self.add_parameter(new_param)
1791 return output
1792
1809
1822
1823
1824
1826 """return the type associate to the expression if define"""
1827
1828 try:
1829 return self.all_expr[expr].type
1830 except:
1831 return 'complex'
1832
1834 """ A class for restricting a model for a given param_card.
1835 rules applied:
1836 - Vertex with zero couplings are throw away
1837 - external parameter with zero/one input are changed into internal parameter.
1838 - identical coupling/mass/width are replace in the model by a unique one
1839 """
1840
1848
1849 - def restrict_model(self, param_card, rm_parameter=True, keep_external=False,
1850 complex_mass_scheme=None):
1920
1921
1923 """ create a dict couplings_name -> vertex or (particle, counterterm_key) """
1924
1925 self.coupling_pos = {}
1926 for vertex in self['interactions']:
1927 for key, coupling in vertex['couplings'].items():
1928 if coupling.startswith('-'):
1929 coupling = coupling[1:]
1930 if coupling in self.coupling_pos:
1931 if vertex not in self.coupling_pos[coupling]:
1932 self.coupling_pos[coupling].append(vertex)
1933 else:
1934 self.coupling_pos[coupling] = [vertex]
1935
1936 for particle in self['particles']:
1937 for key, coupling_dict in particle['counterterm'].items():
1938 for LaurentOrder, coupling in coupling_dict.items():
1939 if coupling in self.coupling_pos:
1940 if (particle,key) not in self.coupling_pos[coupling]:
1941 self.coupling_pos[coupling].append((particle,key))
1942 else:
1943 self.coupling_pos[coupling] = [(particle,key)]
1944
1945 return self.coupling_pos
1946
1948 """return a list with the name of all vanishing couplings"""
1949
1950 dict_value_coupling = {}
1951 iden_key = set()
1952 zero_coupling = []
1953 iden_coupling = []
1954
1955 for name, value in self['coupling_dict'].items():
1956 if value == 0:
1957 zero_coupling.append(name)
1958 continue
1959 elif not strict_zero and abs(value) < 1e-13:
1960 logger.debug('coupling with small value %s: %s treated as zero' %
1961 (name, value))
1962 zero_coupling.append(name)
1963 continue
1964 elif not strict_zero and abs(value) < 1e-10:
1965 return self.detect_identical_couplings(strict_zero=True)
1966
1967
1968 if value in dict_value_coupling or -1*value in dict_value_coupling:
1969 if value in dict_value_coupling:
1970 iden_key.add(value)
1971 dict_value_coupling[value].append((name,1))
1972 else:
1973 iden_key.add(-1*value)
1974 dict_value_coupling[-1*value].append((name,-1))
1975 else:
1976 dict_value_coupling[value] = [(name,1)]
1977 for key in iden_key:
1978 tmp = []
1979 if key in dict_value_coupling:
1980 tmp += dict_value_coupling[key]
1981 elif -1*key in dict_value_coupling:
1982 tmp += dict_value_coupling[-1*key]
1983 assert tmp
1984
1985
1986 ords = [self.get_coupling_order(k) for k,c in tmp]
1987 coup_by_ord = collections.defaultdict(list)
1988 for o,t in zip(ords, tmp):
1989 coup_by_ord[str(o)].append(t)
1990
1991 for tmp3 in coup_by_ord.values():
1992 if len(tmp3) > 1:
1993 if tmp3[0][1] == -1:
1994 tmp3 = [(t0,-t1) for t0, t1 in tmp3]
1995 iden_coupling.append(tmp3)
1996
1997
1998
1999
2000 return zero_coupling, iden_coupling
2001
2003 """return the coupling order associated to a coupling """
2004
2005 if cname in self.coupling_order_dict:
2006 return self.coupling_order_dict[cname]
2007
2008 for v in self['interactions']:
2009 for c in v['couplings'].values():
2010 self.coupling_order_dict[c] = v['orders']
2011
2012 if cname not in self.coupling_order_dict:
2013 self.coupling_order_dict[cname] = None
2014
2015
2016
2017 return self.coupling_order_dict[cname]
2018
2019
2020
2022 """ return the list of (name of) parameter which are zero """
2023
2024 null_parameters = []
2025 one_parameters = []
2026 for name, value in self['parameter_dict'].items():
2027 if value == 0 and name != 'ZERO':
2028 null_parameters.append(name)
2029 elif value == 1:
2030 one_parameters.append(name)
2031
2032 return null_parameters, one_parameters
2033
2036 """ Apply the conditional statement simplifications for parameters and
2037 couplings detected by 'simplify_conditional_statements'.
2038 modified_params (modified_couplings) are list of tuples (a,b) with a
2039 parameter (resp. coupling) instance and b is the simplified expression."""
2040
2041 if modified_params:
2042 logger.debug("Conditional expressions are simplified for parameters:")
2043 logger.debug(",".join("%s"%param[0].name for param in modified_params))
2044 for param, new_expr in modified_params:
2045 param.expr = new_expr
2046
2047 if modified_couplings:
2048 logger.debug("Conditional expressions are simplified for couplings:")
2049 logger.debug(",".join("%s"%coupl[0].name for coupl in modified_couplings))
2050 for coupl, new_expr in modified_couplings:
2051 coupl.expr = new_expr
2052
2055 """ Simplifies the 'if' statements in the pythonic UFO expressions
2056 of parameters using the default variables specified in the restrict card.
2057 It returns a list of objects (parameters or couplings) and the new
2058 expression that they should take. Model definitions include all definitons
2059 of the model functions and parameters."""
2060
2061 param_modifications = []
2062 coupl_modifications = []
2063 ifparser = parsers.UFOExpressionParserPythonIF(model_definitions)
2064
2065 start_param = time.time()
2066 if 'parameters' in objects:
2067 for dependences, param_list in self['parameters'].items():
2068 if 'external' in dependences:
2069 continue
2070 for param in param_list:
2071 new_expr, n_changes = ifparser.parse(param.expr)
2072 if n_changes > 0:
2073 param_modifications.append((param, new_expr))
2074
2075 end_param = time.time()
2076
2077 if 'couplings' in objects:
2078 for dependences, coupl_list in self['couplings'].items():
2079 for coupl in coupl_list:
2080 new_expr, n_changes = ifparser.parse(coupl.expr)
2081 if n_changes > 0:
2082 coupl_modifications.append((coupl, new_expr))
2083
2084 end_coupl = time.time()
2085
2086 tot_param_time = end_param-start_param
2087 tot_coupl_time = end_coupl-end_param
2088 if tot_param_time>5.0:
2089 logger.debug("Simplification of conditional statements"+\
2090 " in parameter expressions done in %s."%misc.format_time(tot_param_time))
2091 if tot_coupl_time>5.0:
2092 logger.debug("Simplification of conditional statements"+\
2093 " in couplings expressions done in %s."%misc.format_time(tot_coupl_time))
2094
2095 return param_modifications, coupl_modifications
2096
2098 """ return the list of tuple of name of parameter with the same
2099 input value """
2100
2101
2102 external_parameters = self['parameters'][('external',)]
2103
2104
2105 block_value_to_var={}
2106 mult_param = set([])
2107
2108
2109
2110 for param in external_parameters[:]:
2111 value = self['parameter_dict'][param.name]
2112 if value in [0,1,0.000001e-99,9.999999e-1]:
2113 continue
2114 if param.lhablock.lower() == 'decay':
2115 continue
2116 key = (param.lhablock, value)
2117 mkey = (param.lhablock, -value)
2118
2119 if key in block_value_to_var:
2120 block_value_to_var[key].append((param,1))
2121 mult_param.add(key)
2122 elif mkey in block_value_to_var:
2123 block_value_to_var[mkey].append((param,-1))
2124 mult_param.add(mkey)
2125 else:
2126 block_value_to_var[key] = [(param,1)]
2127
2128 output=[]
2129 for key in mult_param:
2130 output.append(block_value_to_var[key])
2131
2132 return output
2133
2134
2135 @staticmethod
2137 """ We have main == coeff * coupling
2138 coeff is only +1 or -1
2139 main can be either GC_X or -GC_X
2140 coupling can be either GC_Y or -GC_Y
2141 value is either GC_Y or -GC_Y
2142 the return is either GC_X or -GC_X
2143 such that we have value == OUTPUT
2144 """
2145 assert coeff in [-1,1]
2146 assert value == coupling or value == '-%s' % coupling or coupling == '-%s' % value
2147 assert isinstance(main, str)
2148 assert isinstance(coupling, str)
2149 assert isinstance(value, str)
2150 if coeff ==1:
2151 if value == coupling:
2152 return main
2153 else:
2154 if main.startswith('-'):
2155 return main[1:]
2156 else:
2157 return '-%s' % main
2158 else:
2159 if value == coupling:
2160 if main.startswith('-'):
2161 return main[1:]
2162 else:
2163 return '-%s' % main
2164 else:
2165 return main
2166
2167
2169 """merge the identical couplings in the interactions and particle
2170 counterterms"""
2171
2172
2173 logger_mod.debug(' Fuse the Following coupling (they have the same value): %s '% \
2174 ', '.join([str(obj) for obj in couplings]))
2175
2176 main = couplings[0][0]
2177 assert couplings[0][1] == 1
2178 self.del_coup += [c[0] for c in couplings[1:]]
2179
2180 for coupling, coeff in couplings[1:]:
2181
2182 if coupling not in self.coupling_pos:
2183 continue
2184
2185 vertices = [ vert for vert in self.coupling_pos[coupling] if
2186 isinstance(vert, base_objects.Interaction)]
2187 for vertex in vertices:
2188 for key, value in vertex['couplings'].items():
2189 if value == coupling or value == '-%s' % coupling or coupling == '-%s' % value:
2190 vertex['couplings'][key] = self.get_new_coupling_name(\
2191 main, coupling, value, coeff)
2192
2193
2194
2195
2196
2197 particles_ct = [ pct for pct in self.coupling_pos[coupling] if
2198 isinstance(pct, tuple)]
2199 for pct in particles_ct:
2200 for key, value in pct[0]['counterterm'][pct[1]].items():
2201 if value == coupling:
2202 pct[0]['counterterm'][pct[1]][key] = main
2203
2204
2205
2207 """return the list of block defined in the param_card"""
2208
2209 blocks = set([p.lhablock for p in self['parameters'][('external',)]])
2210 return blocks
2211
2213 """ merge the identical parameters given in argument.
2214 keep external force to keep the param_card untouched (up to comment)"""
2215
2216 logger_mod.debug('Parameters set to identical values: %s '% \
2217 ', '.join(['%s*%s' % (f, obj.name.replace('mdl_','')) for (obj,f) in parameters]))
2218
2219
2220 external_parameters = self['parameters'][('external',)]
2221 for i, (obj, factor) in enumerate(parameters):
2222
2223 if i == 0:
2224 obj.info = 'set of param :' + \
2225 ', '.join([str(f)+'*'+param.name.replace('mdl_','')
2226 for (param, f) in parameters])
2227 expr = obj.name
2228 continue
2229
2230 if factor ==1:
2231 self.rule_card.add_identical(obj.lhablock.lower(), obj.lhacode,
2232 parameters[0][0].lhacode )
2233 else:
2234 self.rule_card.add_opposite(obj.lhablock.lower(), obj.lhacode,
2235 parameters[0][0].lhacode )
2236 obj_name = obj.name
2237
2238 if not keep_external:
2239 external_parameters.remove(obj)
2240 elif obj.lhablock.upper() in ['MASS','DECAY']:
2241 external_parameters.remove(obj)
2242 else:
2243 obj.name = ''
2244 obj.info = 'MG5 will not use this value use instead %s*%s' %(factor,expr)
2245
2246 new_param = base_objects.ModelVariable(obj_name, '%s*%s' %(factor, expr), 'real')
2247 self['parameters'][()].insert(0, new_param)
2248
2249
2250
2251 if parameters[0][0].lhablock in ['MASS','DECAY']:
2252 new_name = parameters[0][0].name
2253 if parameters[0][0].lhablock == 'MASS':
2254 arg = 'mass'
2255 else:
2256 arg = 'width'
2257 change_name = [p.name for (p,f) in parameters[1:]]
2258 factor_for_name = [f for (p,f) in parameters[1:]]
2259 [p.set(arg, new_name) for p in self['particle_dict'].values()
2260 if p[arg] in change_name and
2261 factor_for_name[change_name.index(p[arg])]==1]
2262
2264 """ remove the interactions and particle counterterms
2265 associated to couplings"""
2266
2267
2268 mod_vertex = []
2269 mod_particle_ct = []
2270 for coup in zero_couplings:
2271
2272 if coup not in self.coupling_pos:
2273 continue
2274
2275
2276
2277 vertices = [ vert for vert in self.coupling_pos[coup] if
2278 isinstance(vert, base_objects.Interaction) ]
2279 for vertex in vertices:
2280 modify = False
2281 for key, coupling in vertex['couplings'].items():
2282 if coupling in zero_couplings:
2283 modify=True
2284 del vertex['couplings'][key]
2285 elif coupling.startswith('-'):
2286 coupling = coupling[1:]
2287 if coupling in zero_couplings:
2288 modify=True
2289 del vertex['couplings'][key]
2290
2291 if modify:
2292 mod_vertex.append(vertex)
2293
2294
2295 particles_ct = [ pct for pct in self.coupling_pos[coup] if
2296 isinstance(pct, tuple)]
2297 for pct in particles_ct:
2298 modify = False
2299 for key, coupling in pct[0]['counterterm'][pct[1]].items():
2300 if coupling in zero_couplings:
2301 modify=True
2302 del pct[0]['counterterm'][pct[1]][key]
2303 if modify:
2304 mod_particle_ct.append(pct)
2305
2306
2307 for vertex in mod_vertex:
2308 part_name = [part['name'] for part in vertex['particles']]
2309 orders = ['%s=%s' % (order,value) for order,value in vertex['orders'].items()]
2310
2311 if not vertex['couplings']:
2312 logger_mod.debug('remove interactions: %s at order: %s' % \
2313 (' '.join(part_name),', '.join(orders)))
2314 self['interactions'].remove(vertex)
2315 else:
2316 logger_mod.debug('modify interactions: %s at order: %s' % \
2317 (' '.join(part_name),', '.join(orders)))
2318
2319
2320 for pct in mod_particle_ct:
2321 part_name = pct[0]['name']
2322 order = pct[1][0]
2323 loop_parts = ','.join(['('+','.join([\
2324 self.get_particle(p)['name'] for p in part])+')' \
2325 for part in pct[1][1]])
2326
2327 if not pct[0]['counterterm'][pct[1]]:
2328 logger_mod.debug('remove counterterm of particle %s'%part_name+\
2329 ' with loop particles (%s)'%loop_parts+\
2330 ' perturbing order %s'%order)
2331 del pct[0]['counterterm'][pct[1]]
2332 else:
2333 logger_mod.debug('Modify counterterm of particle %s'%part_name+\
2334 ' with loop particles (%s)'%loop_parts+\
2335 ' perturbing order %s'%order)
2336
2337 return
2338
2340
2341 for name, data in self['couplings'].items():
2342 for coupling in data[:]:
2343 if coupling.name in couplings:
2344 data.remove(coupling)
2345
2346
2347 - def fix_parameter_values(self, zero_parameters, one_parameters,
2348 simplify=True, keep_external=False):
2349 """ Remove all instance of the parameters in the model and replace it by
2350 zero when needed."""
2351
2352
2353
2354 for particle in self['particles']:
2355 if particle['mass'] in zero_parameters:
2356 particle['mass'] = 'ZERO'
2357 if particle['width'] in zero_parameters:
2358 particle['width'] = 'ZERO'
2359 if particle['width'] in one_parameters:
2360 one_parameters.remove(particle['width'])
2361 if particle['mass'] in one_parameters:
2362 one_parameters.remove(particle['mass'])
2363
2364 for pdg, particle in self['particle_dict'].items():
2365 if particle['mass'] in zero_parameters:
2366 particle['mass'] = 'ZERO'
2367 if particle['width'] in zero_parameters:
2368 particle['width'] = 'ZERO'
2369
2370
2371
2372 external_parameters = self['parameters'][('external',)]
2373 for param in external_parameters[:]:
2374 value = self['parameter_dict'][param.name]
2375 block = param.lhablock.lower()
2376 if value == 0:
2377 self.rule_card.add_zero(block, param.lhacode)
2378 elif value == 1:
2379 self.rule_card.add_one(block, param.lhacode)
2380
2381 special_parameters = zero_parameters + one_parameters
2382
2383
2384
2385 if simplify:
2386
2387 re_str = '|'.join(special_parameters)
2388 if len(re_str) > 25000:
2389 split = len(special_parameters) // 2
2390 re_str = ['|'.join(special_parameters[:split]),
2391 '|'.join(special_parameters[split:])]
2392 else:
2393 re_str = [ re_str ]
2394 used = set()
2395 for expr in re_str:
2396 re_pat = re.compile(r'''\b(%s)\b''' % expr)
2397
2398 for name, coupling_list in self['couplings'].items():
2399 for coupling in coupling_list:
2400 for use in re_pat.findall(coupling.expr):
2401 used.add(use)
2402
2403
2404 for lor in self['lorentz']:
2405 if hasattr(lor, 'formfactors') and lor.formfactors:
2406 for ff in lor.formfactors:
2407 for use in re_pat.findall(ff.value):
2408 used.add(use)
2409 else:
2410 used = set([i for i in special_parameters if i])
2411
2412
2413 re_str = '|'.join([param for param in special_parameters if param not in used])
2414 if len(re_str) > 25000:
2415 split = len(special_parameters) // 2
2416 re_str = ['|'.join(special_parameters[:split]),
2417 '|'.join(special_parameters[split:])]
2418 else:
2419 re_str = [ re_str ]
2420 for expr in re_str:
2421 re_pat = re.compile(r'''\b(%s)\b''' % expr)
2422
2423 param_info = {}
2424
2425 for dep, param_list in self['parameters'].items():
2426 for tag, parameter in enumerate(param_list):
2427
2428 if parameter.name in special_parameters:
2429 param_info[parameter.name]= {'dep': dep, 'tag': tag,
2430 'obj': parameter}
2431 continue
2432
2433
2434 if isinstance(parameter, base_objects.ParamCardVariable):
2435 continue
2436
2437 if simplify:
2438 for use in re_pat.findall(parameter.expr):
2439 used.add(use)
2440
2441
2442 for param in used:
2443 if not param:
2444 continue
2445 data = self['parameters'][param_info[param]['dep']]
2446 data.remove(param_info[param]['obj'])
2447 tag = param_info[param]['tag']
2448 data = self['parameters'][()]
2449 if param in zero_parameters:
2450 data.insert(0, base_objects.ModelVariable(param, '0.0', 'real'))
2451 else:
2452 data.insert(0, base_objects.ModelVariable(param, '1.0', 'real'))
2453
2454
2455 for param in special_parameters:
2456
2457 if param in used or \
2458 (keep_external and param_info[param]['dep'] == ('external',)):
2459 logger_mod.debug('fix parameter value: %s' % param)
2460 continue
2461 logger_mod.debug('remove parameters: %s' % (param))
2462 data = self['parameters'][param_info[param]['dep']]
2463 data.remove(param_info[param]['obj'])
2464
2466
2467
2468
2469 to_lor = {}
2470 for (color, lor), coup in interaction['couplings'].items():
2471 abscoup, coeff = (coup[1:],-1) if coup.startswith('-') else (coup, 1)
2472 key = (color, abscoup)
2473 if key in to_lor:
2474 to_lor[key].append((lor,coeff))
2475 else:
2476 to_lor[key] = [(lor,coeff)]
2477
2478 nb_reduce = []
2479 optimize = False
2480 for key in to_lor:
2481 if len(to_lor[key]) >1:
2482 nb_reduce.append(len(to_lor[key])-1)
2483 optimize = True
2484
2485 if not optimize:
2486 return
2487
2488 if not hasattr(self, 'defined_lorentz_expr'):
2489 self.defined_lorentz_expr = {}
2490 self.lorentz_info = {}
2491 self.lorentz_combine = {}
2492 for lor in self.get('lorentz'):
2493 self.defined_lorentz_expr[lor.get('structure')] = lor.get('name')
2494 self.lorentz_info[lor.get('name')] = lor
2495
2496 for key in to_lor:
2497 if len(to_lor[key]) == 1:
2498 continue
2499 names = ['u%s' % interaction['lorentz'][i[0]] if i[1] ==1 else \
2500 'd%s' % interaction['lorentz'][i[0]] for i in to_lor[key]]
2501
2502 names.sort()
2503
2504
2505 if tuple(names) in self.lorentz_combine:
2506
2507 new_name = self.lorentz_combine[tuple(names)]
2508 else:
2509 new_name = self.add_merge_lorentz(names)
2510
2511
2512 color, coup = key
2513 to_remove = [(color, lor[0]) for lor in to_lor[key]]
2514 for rm in to_remove:
2515 del interaction['couplings'][rm]
2516
2517
2518 if new_name not in [l for l in interaction.get('lorentz')]:
2519 interaction.get('lorentz').append(new_name)
2520
2521
2522 new_l = interaction.get('lorentz').index(new_name)
2523
2524 interaction['couplings'][(color, new_l)] = coup
2525
2526
2527
2529 """add a lorentz structure which is the sume of the list given above"""
2530
2531
2532 ii = len(names[0])
2533 while ii>1:
2534
2535 if not all(n[1:].startswith(names[0][1:ii]) for n in names[1:]):
2536 ii -=1
2537 else:
2538 base_name = names[0][1:ii]
2539 break
2540 else:
2541 base_name = 'LMER'
2542 i = 1
2543 while '%s%s' %(base_name, i) in self.lorentz_info:
2544 i +=1
2545 new_name = '%s%s' %(base_name, i)
2546 self.lorentz_combine[tuple(names)] = new_name
2547
2548
2549 new_struct = ' + '.join([self.lorentz_info[n[1:]].get('structure') for n in names if n.startswith('u')])
2550 if any( n.startswith('d') for n in names ):
2551 new_struct += '-' + ' - '.join(['1.*(%s)' %self.lorentz_info[n[1:]].get('structure') for n in names if n.startswith('d')])
2552 spins = self.lorentz_info[names[0][1:]].get('spins')
2553 formfact = sum([ self.lorentz_info[n[1:]].get('formfactors') for n in names \
2554 if hasattr(self.lorentz_info[n[1:]], 'formfactors') \
2555 and self.lorentz_info[n[1:]].get('formfactors') \
2556 ],[])
2557
2558
2559
2560
2561 new_lor = self.add_lorentz(new_name, spins, new_struct, formfact)
2562 self.lorentz_info[new_name] = new_lor
2563
2564 return new_name
2565
2566 - def add_lorentz(self, name, spin, struct, formfact=None):
2567 """adding lorentz structure to the current model"""
2568 new = self['lorentz'][0].__class__(name = name,
2569 spins = spin,
2570 structure = struct)
2571 if formfact:
2572 new.formfactors = formfact
2573 self['lorentz'].append(new)
2574 self.create_lorentz_dict()
2575
2576 return None
2577