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 import madgraph
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 isinstance(value, (list,dict)):
816 if aloha.unitary_gauge:
817 particle.set(key, str(value[0]))
818 else:
819 particle.set(key, str(value[1]))
820 else:
821 particle.set(key, str(value))
822 else:
823 particle.set(key, '')
824 else:
825 particle.set(key, value)
826 elif key == 'loop_particles':
827 loop_particles = value
828 elif key == 'counterterm':
829 counterterms = value
830 elif key.lower() not in ('ghostnumber','selfconjugate','goldstone',
831 'goldstoneboson','partial_widths',
832 'texname', 'antitexname', 'propagating', 'ghost'
833 ):
834
835 self.conservecharge.add(key)
836 particle.set(key,value, force=True)
837
838 if not hasattr(particle_info, 'propagator'):
839 nb_property += 1
840 if particle.get('spin') >= 3:
841 if particle.get('mass').lower() == 'zero':
842 particle.set('propagator', 0)
843 elif particle.get('spin') == 3 and not aloha.unitary_gauge:
844 particle.set('propagator', 0)
845
846 assert(10 == nb_property)
847
848
849 if particle_info.name == particle_info.antiname:
850 particle.set('self_antipart', True)
851
852
853
854 if not self.perturbation_couplings or counterterms=={}:
855 self.particles.append(particle)
856 return
857
858
859
860
861
862
863 particle_counterterms = {}
864 for key, counterterm in counterterms.items():
865
866 if len([1 for k in key[:-1] if k==1])==1 and \
867 not any(k>1 for k in key[:-1]):
868 newParticleCountertermKey=[None,\
869
870
871
872
873
874 tuple([tuple(loop_parts) for\
875 loop_parts in loop_particles[key[-1]]])]
876 for i, order in enumerate(self.ufomodel.all_orders[:-1]):
877 if key[i]==1:
878 newParticleCountertermKey[0]=order.name
879 newCouplingName='UVWfct_'+particle_info.name+'_'+str(key[-1])
880 particle_counterterms[tuple(newParticleCountertermKey)]=\
881 dict([(key,newCouplingName+('' if key==0 else '_'+str(-key)+'eps'))\
882 for key in counterterm])
883
884
885 self.ufomodel.object_library.Coupling(\
886 name = newCouplingName,
887 value = counterterm,
888 order = {newParticleCountertermKey[0]:2})
889 self.wavefunction_CT_couplings.append(self.ufomodel.all_couplings.pop())
890
891 particle.set('counterterm',particle_counterterms)
892 self.particles.append(particle)
893 return
894
896 """ This function scan each coupling to see if it contains a CT parameter.
897 when it does, it changes its value to a dictionary with the CT parameter
898 changed to a new parameter for each pole and finite part. For instance,
899 the following coupling:
900 coupling.value = '2*(myCTParam1 + myParam*(myCTParam2 + myCTParam3)'
901 with CTparameters
902 myCTParam1 = {0: Something, -1: SomethingElse}
903 myCTParam2 = {0: OtherSomething }
904 myCTParam3 = {-1: YetOtherSomething }
905 would be turned into
906 coupling.value = {0: '2*(myCTParam1_FIN_ + myParam*(myCTParam2_FIN_ + ZERO)'
907 -1: '2*(myCTParam1_EPS_ + myParam*(ZERO + myCTParam2_EPS_)'}
908
909 all_CTParameter is the list of all CTParameters in the model"""
910
911
912
913
914
915
916 CTparameter_patterns = {}
917 zero_substitution = lambda matchedObj: matchedObj.group('first')+\
918 'ZERO'+matchedObj.group('second')
919 def function_factory(arg):
920 return lambda matchedObj: \
921 matchedObj.group('first')+arg+matchedObj.group('second')
922 for CTparam in all_CTparameters:
923 pattern_finder = re.compile(r"(?P<first>\A|\*|\+|\-|\(|\s)(?P<name>"+
924 CTparam.name+r")(?P<second>\Z|\*|\+|\-|\)|/|\\|\s)")
925
926 sub_functions = [None if CTparam.pole(pole)=='ZERO' else
927 function_factory('%s_%s_'%(CTparam.name,pole_dict[-pole]))
928 for pole in range(3)]
929 CTparameter_patterns[CTparam.name] = (pattern_finder,sub_functions)
930
931 times_zero = re.compile('\*\s*-?ZERO')
932 zero_times = re.compile('ZERO\s*(\*|\/)')
933 def is_expr_zero(expresson):
934 """ Checks whether a single term (involving only the operations
935 * or / is zero. """
936 for term in expresson.split('-'):
937 for t in term.split('+'):
938 t = t.strip()
939 if t in ['ZERO','']:
940 continue
941 if not (times_zero.search(t) or zero_times.search(t)):
942 return False
943 return True
944
945 def find_parenthesis(expr):
946 end = expr.find(')')
947 if end == -1:
948 return None
949 start = expr.rfind('(',0,end+1)
950 if start ==-1:
951 raise InvalidModel,\
952 'Parenthesis of expression %s are malformed'%expr
953 return [expr[:start],expr[start+1:end],expr[end+1:]]
954
955 start_parenthesis = re.compile(r".*\s*[\+\-\*\/\)\(]\s*$")
956
957 def is_value_zero(value):
958 """Check whether an expression like ((A+B)*ZERO+C)*ZERO is zero.
959 Only +,-,/,* operations are allowed and 'ZERO' is a tag for an
960 analytically zero quantity."""
961
962 curr_value = value
963 parenthesis = find_parenthesis(curr_value)
964 while parenthesis:
965
966 if parenthesis[0].endswith('complexconjugate'):
967
968 parenthesis[0] = parenthesis[0][:-16]
969 if parenthesis[0]=='' or re.match(start_parenthesis,
970 parenthesis[0]):
971 if is_value_zero(parenthesis[1]):
972 new_parenthesis = 'ZERO'
973 else:
974 new_parenthesis = 'PARENTHESIS'
975 else:
976 new_parenthesis = '_FUNCTIONARGS'
977 curr_value = parenthesis[0]+new_parenthesis+parenthesis[2]
978 parenthesis = find_parenthesis(curr_value)
979 return is_expr_zero(curr_value)
980
981 def CTCoupling_pole(CTCoupling, pole):
982 """Compute the pole of the CTCoupling in two cases:
983 a) Its value is a dictionary, then just return the corresponding
984 entry in the dictionary.
985 b) It is expressed in terms of CTParameters which are themselves
986 dictionary so we want to substitute their expression to get
987 the value of the pole. In the current implementation, this is
988 just to see if the pole is zero or not.
989 """
990
991 if isinstance(CTCoupling.value,dict):
992 if -pole in CTCoupling.value.keys():
993 return CTCoupling.value[-pole], [], 0
994 else:
995 return 'ZERO', [], 0
996
997 new_expression = CTCoupling.value
998 CTparamNames = []
999 n_CTparams = 0
1000 for paramname, value in CTparameter_patterns.items():
1001 pattern = value[0]
1002
1003
1004 if not re.search(pattern,new_expression):
1005 continue
1006 n_CTparams += 1
1007
1008
1009 if not value[1][pole] is None:
1010 CTparamNames.append('%s_%s_'%(paramname,pole_dict[-pole]))
1011
1012 substitute_function = zero_substitution if \
1013 value[1][pole] is None else value[1][pole]
1014 new_expression = pattern.sub(substitute_function,new_expression)
1015
1016
1017
1018 if pole!=0 and n_CTparams==0:
1019 return 'ZERO', [], n_CTparams
1020
1021
1022
1023
1024
1025
1026 if n_CTparams > 0 and is_value_zero(new_expression):
1027 return 'ZERO', [], n_CTparams
1028 else:
1029 return new_expression, CTparamNames, n_CTparams
1030
1031
1032 for coupl in couplings:
1033 new_value = {}
1034 for pole in range(0,3):
1035 expression, CTparamNames, n_CTparams = CTCoupling_pole(coupl, pole)
1036
1037 if n_CTparams == 0:
1038 break
1039 elif expression!='ZERO':
1040 new_value[-pole] = expression
1041 couplname = coupl.name
1042 if pole!=0:
1043 couplname += "_%deps"%pole
1044
1045
1046
1047
1048 if hasattr(self.model, 'map_CTcoup_CTparam'):
1049 self.model.map_CTcoup_CTparam[couplname] = CTparamNames
1050
1051
1052
1053
1054
1055
1056
1057
1058 if new_value:
1059 coupl.old_value = coupl.value
1060 coupl.value = new_value
1061
1063 """ Split this interaction in order to call add_interaction for
1064 interactions for each element of the loop_particles list. Also it
1065 is necessary to unfold here the contributions to the different laurent
1066 expansion orders of the couplings."""
1067
1068
1069 interaction_info=copy.copy(interaction)
1070
1071 intType=''
1072 if interaction_info.type not in ['UV','UVloop','UVtree','UVmass','R2']:
1073 raise MadGraph5Error, 'MG5 only supports the following types of'+\
1074 ' vertices, R2, UV and UVmass. %s is not in this list.'%interaction_info.type
1075 else:
1076 intType=interaction_info.type
1077
1078 if interaction_info.type=='UV':
1079 if len(interaction_info.particles)==2 and interaction_info.\
1080 particles[0].name==interaction_info.particles[1].name:
1081 intType='UVmass'
1082 else:
1083 intType='UVloop'
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096 order_to_interactions= {}
1097
1098
1099
1100
1101
1102 for key, couplings in interaction_info.couplings.items():
1103 if not isinstance(couplings, list):
1104 couplings = [couplings]
1105 for coupling in couplings:
1106 order = tuple(coupling.order.items())
1107 if order not in order_to_interactions:
1108 order_to_interactions[order] = [
1109 [{} for j in range(0,3)] for i in \
1110 range(0,max(1,len(interaction_info.loop_particles)))]
1111 new_couplings = order_to_interactions[order]
1112 else:
1113 new_couplings = order_to_interactions[order]
1114
1115 for poleOrder in range(0,3):
1116 expression = coupling.pole(poleOrder)
1117 if expression!='ZERO':
1118 if poleOrder==2:
1119 raise InvalidModel, """
1120 The CT coupling %s was found with a contribution to the double pole.
1121 This is either an error in the model or a parsing error in the function 'is_value_zero'.
1122 The expression of the non-zero double pole coupling is:
1123 %s
1124 """%(coupling.name,str(coupling.value))
1125
1126
1127
1128 newCoupling = copy.copy(coupling)
1129 if poleOrder!=0:
1130 newCoupling.name=newCoupling.name+"_"+str(poleOrder)+"eps"
1131 newCoupling.value = expression
1132
1133
1134
1135
1136
1137
1138
1139 new_couplings[key[2]][poleOrder][(key[0],key[1])] = newCoupling
1140
1141 for new_couplings in order_to_interactions.values():
1142
1143 for i, all_couplings in enumerate(new_couplings):
1144 loop_particles=[[]]
1145 if len(interaction_info.loop_particles)>0:
1146 loop_particles=[[part.pdg_code for part in loop_parts] \
1147 for loop_parts in interaction_info.loop_particles[i]]
1148 for poleOrder in range(0,3):
1149 if all_couplings[poleOrder]!={}:
1150 interaction_info.couplings=all_couplings[poleOrder]
1151 self.add_interaction(interaction_info, color_info,\
1152 (intType if poleOrder==0 else (intType+str(poleOrder)+\
1153 'eps')),loop_particles)
1154
1156 """find which color are in the 3/3bar states"""
1157
1158
1159
1160
1161 if not output:
1162 output = {}
1163
1164 for interaction_info in self.ufomodel.all_vertices:
1165 if len(interaction_info.particles) != 3:
1166 continue
1167 colors = [abs(p.color) for p in interaction_info.particles]
1168 if colors[:2] == [3,3]:
1169 if 'T(3,2,1)' in interaction_info.color:
1170 color, anticolor, other = interaction_info.particles
1171 elif 'T(3,1,2)' in interaction_info.color:
1172 anticolor, color, _ = interaction_info.particles
1173 elif 'Identity(1,2)' in interaction_info.color or \
1174 'Identity(2,1)' in interaction_info.color:
1175 first, second, _ = interaction_info.particles
1176 if first.pdg_code in output:
1177 if output[first.pdg_code] == 3:
1178 color, anticolor = first, second
1179 else:
1180 color, anticolor = second, first
1181 elif second.pdg_code in output:
1182 if output[second.pdg_code] == 3:
1183 color, anticolor = second, first
1184 else:
1185 color, anticolor = first, second
1186 else:
1187 continue
1188 else:
1189 continue
1190 elif colors[1:] == [3,3]:
1191 if 'T(1,2,3)' in interaction_info.color:
1192 other, anticolor, color = interaction_info.particles
1193 elif 'T(1,3,2)' in interaction_info.color:
1194 other, color, anticolor = interaction_info.particles
1195 elif 'Identity(2,3)' in interaction_info.color or \
1196 'Identity(3,2)' in interaction_info.color:
1197 _, first, second = interaction_info.particles
1198 if first.pdg_code in output:
1199 if output[first.pdg_code] == 3:
1200 color, anticolor = first, second
1201 else:
1202 color, anticolor = second, first
1203 elif second.pdg_code in output:
1204 if output[second.pdg_code] == 3:
1205 color, anticolor = second, first
1206 else:
1207 color, anticolor = first, second
1208 else:
1209 continue
1210 else:
1211 continue
1212
1213 elif colors.count(3) == 2:
1214 if 'T(2,3,1)' in interaction_info.color:
1215 color, other, anticolor = interaction_info.particles
1216 elif 'T(2,1,3)' in interaction_info.color:
1217 anticolor, other, color = interaction_info.particles
1218 elif 'Identity(1,3)' in interaction_info.color or \
1219 'Identity(3,1)' in interaction_info.color:
1220 first, _, second = interaction_info.particles
1221 if first.pdg_code in output:
1222 if output[first.pdg_code] == 3:
1223 color, anticolor = first, second
1224 else:
1225 color, anticolor = second, first
1226 elif second.pdg_code in output:
1227 if output[second.pdg_code] == 3:
1228 color, anticolor = second, first
1229 else:
1230 color, anticolor = first, second
1231 else:
1232 continue
1233 else:
1234 continue
1235 else:
1236 continue
1237
1238
1239 if color.pdg_code in output:
1240 if output[color.pdg_code] == -3:
1241 raise InvalidModel, 'Particles %s is sometimes in the 3 and sometimes in the 3bar representations' \
1242 % color.name
1243 else:
1244 output[color.pdg_code] = 3
1245
1246
1247 if anticolor.pdg_code in output:
1248 if output[anticolor.pdg_code] == 3:
1249 raise InvalidModel, 'Particles %s is sometimes set as in the 3 and sometimes in the 3bar representations' \
1250 % anticolor.name
1251 else:
1252 output[anticolor.pdg_code] = -3
1253
1254 return output
1255
1257 """define which fermion should be incoming
1258 for that we look at F F~ X interactions
1259 """
1260 self.incoming = []
1261 self.outcoming = []
1262 for interaction_info in self.ufomodel.all_vertices:
1263
1264 pdg = [p.pdg_code for p in interaction_info.particles if p.spin in [2,4]]
1265 if len(pdg) % 2:
1266 raise InvalidModel, 'Odd number of fermion in vertex: %s' % [p.pdg_code for p in interaction_info.particles]
1267 for i in range(0, len(pdg),2):
1268 if pdg[i] == - pdg[i+1]:
1269 if pdg[i] in self.outcoming:
1270 raise InvalidModel, '%s has not coherent incoming/outcoming status between interactions' %\
1271 [p for p in interaction_info.particles if p.spin in [2,4]][i].name
1272
1273 elif not pdg[i] in self.incoming:
1274 self.incoming.append(pdg[i])
1275 self.outcoming.append(pdg[i+1])
1276
1277 - def add_interaction(self, interaction_info, color_info, type='base', loop_particles=None):
1278 """add an interaction in the MG5 model. interaction_info is the
1279 UFO vertices information."""
1280
1281 particles = [self.model.get_particle(particle.pdg_code) \
1282 for particle in interaction_info.particles]
1283 if None in particles:
1284
1285 return
1286 particles = base_objects.ParticleList(particles)
1287
1288
1289 lorentz = [helas for helas in interaction_info.lorentz]
1290
1291
1292 nb_fermion = sum([ 1 if p.is_fermion() else 0 for p in particles])
1293 try:
1294 if nb_fermion == 2:
1295
1296 [aloha_fct.check_flow_validity(helas.structure, nb_fermion) \
1297 for helas in interaction_info.lorentz
1298 if helas.name not in self.checked_lor]
1299 self.checked_lor.update(set([helas.name for helas in interaction_info.lorentz]))
1300 elif nb_fermion:
1301 if any(p.selfconjugate for p in interaction_info.particles if p.spin % 2 == 0):
1302 text = "Majorana can not be dealt in 4/6/... fermion interactions"
1303 raise InvalidModel, text
1304 except aloha_fct.WrongFermionFlow, error:
1305 text = 'Fermion Flow error for interactions %s: %s: %s\n %s' % \
1306 (', '.join([p.name for p in interaction_info.particles]),
1307 helas.name, helas.structure, error)
1308 raise InvalidModel, text
1309
1310
1311
1312
1313
1314 lorentz = [helas.name for helas in lorentz]
1315
1316 colors = [self.treat_color(color_obj, interaction_info, color_info)
1317 for color_obj in interaction_info.color]
1318
1319
1320 order_to_int={}
1321
1322 for key, couplings in interaction_info.couplings.items():
1323 if not isinstance(couplings, list):
1324 couplings = [couplings]
1325 if interaction_info.lorentz[key[1]].name not in lorentz:
1326 continue
1327
1328 if nb_fermion > 2:
1329 flow = aloha_fct.get_fermion_flow(interaction_info.lorentz[key[1]].structure,
1330 nb_fermion)
1331 coupling_sign = self.get_sign_flow(flow, nb_fermion)
1332 else:
1333 coupling_sign = ''
1334 for coupling in couplings:
1335 order = tuple(coupling.order.items())
1336
1337 if '1' in coupling.order:
1338 raise InvalidModel, '''Some couplings have \'1\' order.
1339 This is not allowed in MG.
1340 Please defines an additional coupling to your model'''
1341
1342 if 21 in [particle.pdg_code for particle in interaction_info.particles] and\
1343 'QCD' not in coupling.order:
1344 col = [par.get('color') for par in particles]
1345 if 1 not in col:
1346 self.non_qcd_gluon_emission +=1
1347
1348 if order in order_to_int:
1349 order_to_int[order].get('couplings')[key] = '%s%s' % \
1350 (coupling_sign,coupling.name)
1351 else:
1352
1353 interaction = base_objects.Interaction({'id':len(self.interactions)+1})
1354 interaction.set('particles', particles)
1355 interaction.set('lorentz', lorentz)
1356 interaction.set('couplings', {key:
1357 '%s%s' %(coupling_sign,coupling.name)})
1358 interaction.set('orders', coupling.order)
1359 interaction.set('color', colors)
1360 interaction.set('type', type)
1361 interaction.set('loop_particles', loop_particles)
1362 order_to_int[order] = interaction
1363
1364 self.interactions.append(interaction)
1365
1366
1367
1368
1369 for charge in list(self.conservecharge):
1370 total = 0
1371 for part in interaction_info.particles:
1372 try:
1373 total += getattr(part, charge)
1374 except AttributeError:
1375 pass
1376 if abs(total) > 1e-12:
1377 logger.info('The model has interaction violating the charge: %s' % charge)
1378 self.conservecharge.discard(charge)
1379
1380
1381
1383 """ensure that the flow of particles/lorentz are coherent with flow
1384 and return a correct version if needed"""
1385
1386 if not flow or nb_fermion < 4:
1387 return ''
1388
1389 expected = {}
1390 for i in range(nb_fermion//2):
1391 expected[i+1] = i+2
1392
1393 if flow == expected:
1394 return ''
1395
1396 switch = {}
1397 for i in range(1, nb_fermion+1):
1398 if not i in flow:
1399 continue
1400 switch[i] = len(switch)
1401 switch[flow[i]] = len(switch)
1402
1403
1404 sign = 1
1405 done = []
1406
1407
1408
1409 new_order = []
1410 for id in range(nb_fermion):
1411 nid = switch[id+1]-1
1412
1413 new_order.append(nid)
1414
1415
1416 sign =1
1417 for k in range(len(new_order)-1):
1418 for l in range(k+1,len(new_order)):
1419 if new_order[l] < new_order[k]:
1420 sign *= -1
1421
1422 return '' if sign ==1 else '-'
1423
1424 - def add_lorentz(self, name, spins , expr, formfact=None):
1425 """ Add a Lorentz expression which is not present in the UFO """
1426
1427 logger.debug('MG5 converter defines %s to %s', name, expr)
1428 assert name not in [l.name for l in self.model['lorentz']]
1429 with misc.TMP_variable(self.ufomodel.object_library, 'all_lorentz',
1430 self.model['lorentz']):
1431 new = self.model['lorentz'][0].__class__(name = name,
1432 spins = spins,
1433 structure = expr)
1434 if formfact:
1435 new.formfactors = formfact
1436
1437 assert name in [l.name for l in self.model['lorentz']]
1438 assert name not in [l.name for l in self.ufomodel.all_lorentz]
1439
1440 self.model.create_lorentz_dict()
1441 return new
1442
1443 _pat_T = re.compile(r'T\((?P<first>\d*),(?P<second>\d*)\)')
1444 _pat_id = re.compile(r'Identity\((?P<first>\d*),(?P<second>\d*)\)')
1445
1446 - def treat_color(self, data_string, interaction_info, color_info):
1447 """ convert the string to ColorString"""
1448
1449
1450
1451
1452
1453 output = []
1454 factor = 1
1455 for term in data_string.split('*'):
1456 pattern = self._pat_id.search(term)
1457 if pattern:
1458 particle = interaction_info.particles[int(pattern.group('first'))-1]
1459 particle2 = interaction_info.particles[int(pattern.group('second'))-1]
1460 if particle.color == particle2.color and particle.color in [-6, 6]:
1461 error_msg = 'UFO model have inconsistency in the format:\n'
1462 error_msg += 'interactions for particles %s has color information %s\n'
1463 error_msg += ' but both fermion are in the same representation %s'
1464 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
1465 if particle.color == particle2.color and particle.color in [-3, 3]:
1466 if particle.pdg_code in color_info and particle2.pdg_code in color_info:
1467 if color_info[particle.pdg_code] == color_info[particle2.pdg_code]:
1468 error_msg = 'UFO model have inconsistency in the format:\n'
1469 error_msg += 'interactions for particles %s has color information %s\n'
1470 error_msg += ' but both fermion are in the same representation %s'
1471 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
1472 elif particle.pdg_code in color_info:
1473 color_info[particle2.pdg_code] = -particle.pdg_code
1474 elif particle2.pdg_code in color_info:
1475 color_info[particle.pdg_code] = -particle2.pdg_code
1476 else:
1477 error_msg = 'UFO model have inconsistency in the format:\n'
1478 error_msg += 'interactions for particles %s has color information %s\n'
1479 error_msg += ' but both fermion are in the same representation %s'
1480 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
1481
1482
1483 if particle.color == 6:
1484 output.append(self._pat_id.sub('color.T6(\g<first>,\g<second>)', term))
1485 elif particle.color == -6 :
1486 output.append(self._pat_id.sub('color.T6(\g<second>,\g<first>)', term))
1487 elif particle.color == 8:
1488 output.append(self._pat_id.sub('color.Tr(\g<first>,\g<second>)', term))
1489 factor *= 2
1490 elif particle.color in [-3,3]:
1491 if particle.pdg_code not in color_info:
1492
1493 logger.debug('fail to find 3/3bar representation: Retry to find it')
1494 color_info = self.find_color_anti_color_rep(color_info)
1495 if particle.pdg_code not in color_info:
1496 logger.debug('Not able to find the 3/3bar rep from the interactions for particle %s' % particle.name)
1497 color_info[particle.pdg_code] = particle.color
1498 else:
1499 logger.debug('succeed')
1500 if particle2.pdg_code not in color_info:
1501
1502 logger.debug('fail to find 3/3bar representation: Retry to find it')
1503 color_info = self.find_color_anti_color_rep(color_info)
1504 if particle2.pdg_code not in color_info:
1505 logger.debug('Not able to find the 3/3bar rep from the interactions for particle %s' % particle2.name)
1506 color_info[particle2.pdg_code] = particle2.color
1507 else:
1508 logger.debug('succeed')
1509
1510 if color_info[particle.pdg_code] == 3 :
1511 output.append(self._pat_id.sub('color.T(\g<second>,\g<first>)', term))
1512 elif color_info[particle.pdg_code] == -3:
1513 output.append(self._pat_id.sub('color.T(\g<first>,\g<second>)', term))
1514 else:
1515 raise MadGraph5Error, \
1516 "Unknown use of Identity for particle with color %d" \
1517 % particle.color
1518 else:
1519 output.append(term)
1520 data_string = '*'.join(output)
1521
1522
1523 p = re.compile(r'\'\w(?P<number>\d+)\'')
1524 data_string = p.sub('-\g<number>', data_string)
1525
1526
1527 new_indices = {}
1528 new_indices = dict([(j,i) for (i,j) in \
1529 enumerate(range(1,
1530 len(interaction_info.particles)+1))])
1531
1532
1533 output = data_string.split('*')
1534 output = color.ColorString([eval(data) \
1535 for data in output if data !='1'])
1536 output.coeff = fractions.Fraction(factor)
1537 for col_obj in output:
1538 col_obj.replace_indices(new_indices)
1539
1540 return output
1541
1543 """Organize the couplings/parameters of a model"""
1544
1545 track_dependant = ['aS','aEWM1','MU_R']
1546
1547
1548
1549
1550 complex_number = re.compile(r'''complex\((?P<real>[^,\(\)]+),(?P<imag>[^,\(\)]+)\)''')
1551 expo_expr = re.compile(r'''(?P<expr>[\w.]+)\s*\*\*\s*(?P<expo>[+-]?[\d.]+)''')
1552 cmath_expr = re.compile(r'''cmath.(?P<operation>\w+)\((?P<expr>\w+)\)''')
1553
1554 conj_expr = re.compile(r'''complexconjugate\((?P<expr>\w+)\)''')
1555
1556
1557 separator = re.compile(r'''[+,\-*/()\s]*''')
1558
1559
1561
1562 self.model = model
1563 self.perturbation_couplings = {}
1564 try:
1565 for order in model.all_orders:
1566 if(order.perturbative_expansion>0):
1567 self.perturbation_couplings[order.name]=order.perturbative_expansion
1568 except AttributeError:
1569 pass
1570 self.params = {}
1571 self.couplings = {}
1572 self.all_expr = {}
1573
1574 - def main(self, additional_couplings = []):
1575 """Launch the actual computation and return the associate
1576 params/couplings. Possibly consider additional_couplings in addition
1577 to those defined in the UFO model attribute all_couplings """
1578
1579 additional_params = []
1580 if hasattr(self.model,'all_CTparameters'):
1581 additional_params = self.get_additional_CTparameters()
1582
1583 self.analyze_parameters(additional_params = additional_params)
1584 self.analyze_couplings(additional_couplings = additional_couplings)
1585
1586
1587 if hasattr(self.model,'all_CTparameters'):
1588 self.revert_CTCoupling_modifications()
1589
1590 return self.params, self.couplings
1591
1593 """ Finally revert the possible modifications done by treat_couplings()
1594 in UFOMG5Converter which were useful for the add_CTinteraction() in
1595 particular. This modification consisted in expanding the value of a
1596 CTCoupling which consisted in an expression in terms of a CTParam to
1597 its corresponding dictionary (e.g
1598 CTCoupling.value = 2*CTParam ->
1599 CTCoupling.value = {-1: 2*CTParam_1EPS_, 0: 2*CTParam_FIN_}
1600 for example if CTParam had a non-zero finite and single pole."""
1601
1602 for coupl in self.model.all_couplings:
1603 if hasattr(coupl,'old_value'):
1604 coupl.value = coupl.old_value
1605 del(coupl.old_value)
1606
1608 """ For each CTparameter split it into spimple parameter for each pole
1609 and the finite part if not zero."""
1610
1611 additional_params = []
1612 for CTparam in self.model.all_CTparameters:
1613 for pole in range(3):
1614 if CTparam.pole(pole) != 'ZERO':
1615 CTparam_piece = copy.copy(CTparam)
1616 CTparam_piece.name = '%s_%s_'%(CTparam.name,pole_dict[-pole])
1617 CTparam_piece.nature = 'internal'
1618 CTparam_piece.type = CTparam.type
1619 CTparam_piece.value = CTparam.pole(pole)
1620 CTparam_piece.texname = '%s_{%s}'%\
1621 (CTparam.texname,pole_dict[-pole])
1622 additional_params.append(CTparam_piece)
1623 return additional_params
1624
1626 """ separate the parameters needed to be recomputed events by events and
1627 the others"""
1628
1629
1630
1631 present_aEWM1 = any(param.name == 'aEWM1' for param in
1632 self.model.all_parameters if param.nature == 'external')
1633
1634 if not present_aEWM1:
1635 self.track_dependant = ['aS','Gf','MU_R']
1636
1637 for param in self.model.all_parameters+additional_params:
1638 if param.nature == 'external':
1639 parameter = base_objects.ParamCardVariable(param.name, param.value, \
1640 param.lhablock, param.lhacode)
1641
1642 else:
1643 expr = self.shorten_expr(param.value)
1644 depend_on = self.find_dependencies(expr)
1645 parameter = base_objects.ModelVariable(param.name, expr, param.type, depend_on)
1646
1647 self.add_parameter(parameter)
1648
1650 """ add consistently the parameter in params and all_expr.
1651 avoid duplication """
1652
1653 assert isinstance(parameter, base_objects.ModelVariable)
1654
1655 if parameter.name in self.all_expr:
1656 return
1657
1658 self.all_expr[parameter.name] = parameter
1659 try:
1660 self.params[parameter.depend].append(parameter)
1661 except:
1662 self.params[parameter.depend] = [parameter]
1663
1665 """ add consistently the coupling in couplings and all_expr.
1666 avoid duplication """
1667
1668 assert isinstance(coupling, base_objects.ModelVariable)
1669
1670 if coupling.name in self.all_expr:
1671 return
1672 self.all_expr[coupling.value] = coupling
1673 try:
1674 self.coupling[coupling.depend].append(coupling)
1675 except:
1676 self.coupling[coupling.depend] = [coupling]
1677
1679 """creates the shortcut for all special function/parameter
1680 separate the couplings dependent of track variables of the others"""
1681
1682
1683
1684 if self.perturbation_couplings:
1685 couplings_list=[]
1686 for coupling in self.model.all_couplings + additional_couplings:
1687 if not isinstance(coupling.value,dict):
1688 couplings_list.append(coupling)
1689 else:
1690 for poleOrder in range(0,3):
1691 if coupling.pole(poleOrder)!='ZERO':
1692 newCoupling=copy.copy(coupling)
1693 if poleOrder!=0:
1694 newCoupling.name += "_%deps"%poleOrder
1695 newCoupling.value=coupling.pole(poleOrder)
1696
1697
1698
1699
1700
1701
1702
1703 couplings_list.append(newCoupling)
1704 else:
1705 couplings_list = self.model.all_couplings + additional_couplings
1706 couplings_list = [c for c in couplings_list if not isinstance(c.value, dict)]
1707
1708 for coupling in couplings_list:
1709
1710 expr = self.shorten_expr(coupling.value)
1711 depend_on = self.find_dependencies(expr)
1712 parameter = base_objects.ModelVariable(coupling.name, expr, 'complex', depend_on)
1713
1714 try:
1715 self.couplings[depend_on].append(parameter)
1716 except KeyError:
1717 self.couplings[depend_on] = [parameter]
1718 self.all_expr[coupling.value] = parameter
1719
1721 """check if an expression should be evaluated points by points or not
1722 """
1723 depend_on = set()
1724
1725
1726
1727
1728
1729
1730
1731 expr = self.separator.split(expr)
1732
1733
1734 for subexpr in expr:
1735 if subexpr in self.track_dependant:
1736 depend_on.add(subexpr)
1737
1738 elif subexpr in self.all_expr and self.all_expr[subexpr].depend:
1739 [depend_on.add(value) for value in self.all_expr[subexpr].depend
1740 if self.all_expr[subexpr].depend != ('external',)]
1741 if depend_on:
1742 return tuple(depend_on)
1743 else:
1744 return tuple()
1745
1746
1759
1760
1762 """add the short expression, and return the nice string associate"""
1763
1764 float_real = float(eval(matchobj.group('real')))
1765 float_imag = float(eval(matchobj.group('imag')))
1766 if float_real == 0 and float_imag ==1:
1767 new_param = base_objects.ModelVariable('complexi', 'complex(0,1)', 'complex')
1768 self.add_parameter(new_param)
1769 return 'complexi'
1770 else:
1771 return 'complex(%s, %s)' % (matchobj.group('real'), matchobj.group('imag'))
1772
1773
1775 """add the short expression, and return the nice string associate"""
1776
1777 expr = matchobj.group('expr')
1778 exponent = matchobj.group('expo')
1779 new_exponent = exponent.replace('.','_').replace('+','').replace('-','_m_')
1780 output = '%s__exp__%s' % (expr, new_exponent)
1781 old_expr = '%s**%s' % (expr,exponent)
1782
1783 if expr.startswith('cmath'):
1784 return old_expr
1785
1786 if expr.isdigit():
1787 output = 'nb__' + output
1788 new_param = base_objects.ModelVariable(output, old_expr,'real')
1789 else:
1790 depend_on = self.find_dependencies(expr)
1791 type = self.search_type(expr)
1792 new_param = base_objects.ModelVariable(output, old_expr, type, depend_on)
1793 self.add_parameter(new_param)
1794 return output
1795
1812
1825
1826
1827
1829 """return the type associate to the expression if define"""
1830
1831 try:
1832 return self.all_expr[expr].type
1833 except:
1834 return 'complex'
1835
1837 """ A class for restricting a model for a given param_card.
1838 rules applied:
1839 - Vertex with zero couplings are throw away
1840 - external parameter with zero/one input are changed into internal parameter.
1841 - identical coupling/mass/width are replace in the model by a unique one
1842 """
1843
1844 log_level = 10
1845 if madgraph.ADMIN_DEBUG:
1846 log_level = 5
1847
1855
1856 - def restrict_model(self, param_card, rm_parameter=True, keep_external=False,
1857 complex_mass_scheme=None):
1858 """apply the model restriction following param_card.
1859 rm_parameter defines if the Zero/one parameter are removed or not from
1860 the model.
1861 keep_external if the param_card need to be kept intact
1862 """
1863
1864 if self.get('name') == "mssm" and not keep_external:
1865 raise Exception
1866
1867 self.restrict_card = param_card
1868
1869 self.set('particles', self.get('particles'))
1870
1871
1872
1873 model_definitions = self.set_parameters_and_couplings(param_card,
1874 complex_mass_scheme=complex_mass_scheme)
1875
1876
1877 logger.log(self.log_level, 'Simplifying conditional expressions')
1878 modified_params, modified_couplings = \
1879 self.detect_conditional_statements_simplifications(model_definitions)
1880
1881
1882 self.apply_conditional_simplifications(modified_params, modified_couplings)
1883
1884
1885 self.locate_coupling()
1886
1887 zero_couplings, iden_couplings = self.detect_identical_couplings()
1888
1889
1890 self.remove_interactions(zero_couplings)
1891
1892
1893 for iden_coups in iden_couplings:
1894 self.merge_iden_couplings(iden_coups)
1895
1896
1897 self.del_coup += zero_couplings
1898 self.remove_couplings(self.del_coup)
1899
1900
1901 for interaction in list(self.get('interactions')):
1902 self.optimise_interaction(interaction)
1903
1904
1905 parameters = self.detect_special_parameters()
1906 self.fix_parameter_values(*parameters, simplify=rm_parameter,
1907 keep_external=keep_external)
1908
1909
1910 if not keep_external:
1911 iden_parameters = self.detect_identical_parameters()
1912 for iden_param in iden_parameters:
1913 self.merge_iden_parameters(iden_param)
1914
1915 iden_parameters = self.detect_identical_parameters()
1916 for iden_param in iden_parameters:
1917 self.merge_iden_parameters(iden_param, keep_external)
1918
1919
1920
1921
1922 for name, value in self['parameter_dict'].items():
1923 if value == 9.999999e-1:
1924 self['parameter_dict'][name] = 1
1925 elif value == 0.000001e-99:
1926 self['parameter_dict'][name] = 0
1927
1928
1930 """ create a dict couplings_name -> vertex or (particle, counterterm_key) """
1931
1932 self.coupling_pos = {}
1933 for vertex in self['interactions']:
1934 for key, coupling in vertex['couplings'].items():
1935 if coupling.startswith('-'):
1936 coupling = coupling[1:]
1937 if coupling in self.coupling_pos:
1938 if vertex not in self.coupling_pos[coupling]:
1939 self.coupling_pos[coupling].append(vertex)
1940 else:
1941 self.coupling_pos[coupling] = [vertex]
1942
1943 for particle in self['particles']:
1944 for key, coupling_dict in particle['counterterm'].items():
1945 for LaurentOrder, coupling in coupling_dict.items():
1946 if coupling in self.coupling_pos:
1947 if (particle,key) not in self.coupling_pos[coupling]:
1948 self.coupling_pos[coupling].append((particle,key))
1949 else:
1950 self.coupling_pos[coupling] = [(particle,key)]
1951
1952 return self.coupling_pos
1953
1955 """return a list with the name of all vanishing couplings"""
1956
1957 dict_value_coupling = {}
1958 iden_key = set()
1959 zero_coupling = []
1960 iden_coupling = []
1961
1962 for name, value in self['coupling_dict'].items():
1963 if value == 0:
1964 zero_coupling.append(name)
1965 continue
1966 elif not strict_zero and abs(value) < 1e-13:
1967 logger.log(self.log_level, 'coupling with small value %s: %s treated as zero' %
1968 (name, value))
1969 zero_coupling.append(name)
1970 continue
1971 elif not strict_zero and abs(value) < 1e-10:
1972 return self.detect_identical_couplings(strict_zero=True)
1973
1974
1975 if value in dict_value_coupling or -1*value in dict_value_coupling:
1976 if value in dict_value_coupling:
1977 iden_key.add(value)
1978 dict_value_coupling[value].append((name,1))
1979 else:
1980 iden_key.add(-1*value)
1981 dict_value_coupling[-1*value].append((name,-1))
1982 else:
1983 dict_value_coupling[value] = [(name,1)]
1984 for key in iden_key:
1985 tmp = []
1986 if key in dict_value_coupling:
1987 tmp += dict_value_coupling[key]
1988 elif -1*key in dict_value_coupling:
1989 tmp += dict_value_coupling[-1*key]
1990 assert tmp
1991
1992
1993 ords = [self.get_coupling_order(k) for k,c in tmp]
1994 coup_by_ord = collections.defaultdict(list)
1995 for o,t in zip(ords, tmp):
1996 coup_by_ord[str(o)].append(t)
1997
1998 for tmp3 in coup_by_ord.values():
1999 if len(tmp3) > 1:
2000 if tmp3[0][1] == -1:
2001 tmp3 = [(t0,-t1) for t0, t1 in tmp3]
2002 iden_coupling.append(tmp3)
2003
2004
2005
2006
2007 return zero_coupling, iden_coupling
2008
2010 """return the coupling order associated to a coupling """
2011
2012 if cname in self.coupling_order_dict:
2013 return self.coupling_order_dict[cname]
2014
2015 for v in self['interactions']:
2016 for c in v['couplings'].values():
2017 self.coupling_order_dict[c] = v['orders']
2018
2019 if cname not in self.coupling_order_dict:
2020 self.coupling_order_dict[cname] = None
2021
2022
2023
2024 return self.coupling_order_dict[cname]
2025
2026
2027
2029 """ return the list of (name of) parameter which are zero """
2030
2031 null_parameters = []
2032 one_parameters = []
2033 for name, value in self['parameter_dict'].items():
2034 if value == 0 and name != 'ZERO':
2035 null_parameters.append(name)
2036 elif value == 1:
2037 one_parameters.append(name)
2038
2039 return null_parameters, one_parameters
2040
2043 """ Apply the conditional statement simplifications for parameters and
2044 couplings detected by 'simplify_conditional_statements'.
2045 modified_params (modified_couplings) are list of tuples (a,b) with a
2046 parameter (resp. coupling) instance and b is the simplified expression."""
2047
2048 if modified_params:
2049 logger.log(self.log_level, "Conditional expressions are simplified for parameters:")
2050 logger.log(self.log_level, ",".join("%s"%param[0].name for param in modified_params))
2051 for param, new_expr in modified_params:
2052 param.expr = new_expr
2053
2054 if modified_couplings:
2055 logger.log(self.log_level, "Conditional expressions are simplified for couplings:")
2056 logger.log(self.log_level, ",".join("%s"%coupl[0].name for coupl in modified_couplings))
2057 for coupl, new_expr in modified_couplings:
2058 coupl.expr = new_expr
2059
2062 """ Simplifies the 'if' statements in the pythonic UFO expressions
2063 of parameters using the default variables specified in the restrict card.
2064 It returns a list of objects (parameters or couplings) and the new
2065 expression that they should take. Model definitions include all definitons
2066 of the model functions and parameters."""
2067
2068 param_modifications = []
2069 coupl_modifications = []
2070 ifparser = parsers.UFOExpressionParserPythonIF(model_definitions)
2071
2072 start_param = time.time()
2073 if 'parameters' in objects:
2074 for dependences, param_list in self['parameters'].items():
2075 if 'external' in dependences:
2076 continue
2077 for param in param_list:
2078 new_expr, n_changes = ifparser.parse(param.expr)
2079 if n_changes > 0:
2080 param_modifications.append((param, new_expr))
2081
2082 end_param = time.time()
2083
2084 if 'couplings' in objects:
2085 for dependences, coupl_list in self['couplings'].items():
2086 for coupl in coupl_list:
2087 new_expr, n_changes = ifparser.parse(coupl.expr)
2088 if n_changes > 0:
2089 coupl_modifications.append((coupl, new_expr))
2090
2091 end_coupl = time.time()
2092
2093 tot_param_time = end_param-start_param
2094 tot_coupl_time = end_coupl-end_param
2095 if tot_param_time>5.0:
2096 logger.log(self.log_level, "Simplification of conditional statements"+\
2097 " in parameter expressions done in %s."%misc.format_time(tot_param_time))
2098 if tot_coupl_time>5.0:
2099 logger.log(self.log_level, "Simplification of conditional statements"+\
2100 " in couplings expressions done in %s."%misc.format_time(tot_coupl_time))
2101
2102 return param_modifications, coupl_modifications
2103
2105 """ return the list of tuple of name of parameter with the same
2106 input value """
2107
2108
2109 external_parameters = self['parameters'][('external',)]
2110
2111
2112 block_value_to_var={}
2113 mult_param = set([])
2114
2115
2116
2117 for param in external_parameters[:]:
2118 value = self['parameter_dict'][param.name]
2119 if value in [0,1,0.000001e-99,9.999999e-1]:
2120 continue
2121 if param.lhablock.lower() == 'decay':
2122 continue
2123 key = (param.lhablock, value)
2124 mkey = (param.lhablock, -value)
2125
2126 if key in block_value_to_var:
2127 block_value_to_var[key].append((param,1))
2128 mult_param.add(key)
2129 elif mkey in block_value_to_var:
2130 block_value_to_var[mkey].append((param,-1))
2131 mult_param.add(mkey)
2132 else:
2133 block_value_to_var[key] = [(param,1)]
2134
2135 output=[]
2136 for key in mult_param:
2137 output.append(block_value_to_var[key])
2138
2139 return output
2140
2141
2142 @staticmethod
2144 """ We have main == coeff * coupling
2145 coeff is only +1 or -1
2146 main can be either GC_X or -GC_X
2147 coupling can be either GC_Y or -GC_Y
2148 value is either GC_Y or -GC_Y
2149 the return is either GC_X or -GC_X
2150 such that we have value == OUTPUT
2151 """
2152 assert coeff in [-1,1]
2153 assert value == coupling or value == '-%s' % coupling or coupling == '-%s' % value
2154 assert isinstance(main, str)
2155 assert isinstance(coupling, str)
2156 assert isinstance(value, str)
2157 if coeff ==1:
2158 if value == coupling:
2159 return main
2160 else:
2161 if main.startswith('-'):
2162 return main[1:]
2163 else:
2164 return '-%s' % main
2165 else:
2166 if value == coupling:
2167 if main.startswith('-'):
2168 return main[1:]
2169 else:
2170 return '-%s' % main
2171 else:
2172 return main
2173
2174
2176 """merge the identical couplings in the interactions and particle
2177 counterterms"""
2178
2179
2180 logger_mod.log(self.log_level, ' Fuse the Following coupling (they have the same value): %s '% \
2181 ', '.join([str(obj) for obj in couplings]))
2182
2183 main = couplings[0][0]
2184 assert couplings[0][1] == 1
2185 self.del_coup += [c[0] for c in couplings[1:]]
2186
2187 for coupling, coeff in couplings[1:]:
2188
2189 if coupling not in self.coupling_pos:
2190 continue
2191
2192 vertices = [ vert for vert in self.coupling_pos[coupling] if
2193 isinstance(vert, base_objects.Interaction)]
2194 for vertex in vertices:
2195 for key, value in vertex['couplings'].items():
2196 if value == coupling or value == '-%s' % coupling or coupling == '-%s' % value:
2197 vertex['couplings'][key] = self.get_new_coupling_name(\
2198 main, coupling, value, coeff)
2199
2200
2201
2202
2203
2204 particles_ct = [ pct for pct in self.coupling_pos[coupling] if
2205 isinstance(pct, tuple)]
2206 for pct in particles_ct:
2207 for key, value in pct[0]['counterterm'][pct[1]].items():
2208 if value == coupling:
2209 pct[0]['counterterm'][pct[1]][key] = main
2210
2211
2212
2214 """return the list of block defined in the param_card"""
2215
2216 blocks = set([p.lhablock for p in self['parameters'][('external',)]])
2217 return blocks
2218
2220 """ merge the identical parameters given in argument.
2221 keep external force to keep the param_card untouched (up to comment)"""
2222
2223 logger_mod.log(self.log_level, 'Parameters set to identical values: %s '% \
2224 ', '.join(['%s*%s' % (f, obj.name.replace('mdl_','')) for (obj,f) in parameters]))
2225
2226
2227 external_parameters = self['parameters'][('external',)]
2228 for i, (obj, factor) in enumerate(parameters):
2229
2230 if i == 0:
2231 obj.info = 'set of param :' + \
2232 ', '.join([str(f)+'*'+param.name.replace('mdl_','')
2233 for (param, f) in parameters])
2234 expr = obj.name
2235 continue
2236
2237 if factor ==1:
2238 self.rule_card.add_identical(obj.lhablock.lower(), obj.lhacode,
2239 parameters[0][0].lhacode )
2240 else:
2241 self.rule_card.add_opposite(obj.lhablock.lower(), obj.lhacode,
2242 parameters[0][0].lhacode )
2243 obj_name = obj.name
2244
2245 if not keep_external:
2246 external_parameters.remove(obj)
2247 elif obj.lhablock.upper() in ['MASS','DECAY']:
2248 external_parameters.remove(obj)
2249 else:
2250 obj.name = ''
2251 obj.info = 'MG5 will not use this value use instead %s*%s' %(factor,expr)
2252
2253 new_param = base_objects.ModelVariable(obj_name, '%s*%s' %(factor, expr), 'real')
2254 self['parameters'][()].insert(0, new_param)
2255
2256
2257
2258 if parameters[0][0].lhablock in ['MASS','DECAY']:
2259 new_name = parameters[0][0].name
2260 if parameters[0][0].lhablock == 'MASS':
2261 arg = 'mass'
2262 else:
2263 arg = 'width'
2264 change_name = [p.name for (p,f) in parameters[1:]]
2265 factor_for_name = [f for (p,f) in parameters[1:]]
2266 [p.set(arg, new_name) for p in self['particle_dict'].values()
2267 if p[arg] in change_name and
2268 factor_for_name[change_name.index(p[arg])]==1]
2269
2271 """ remove the interactions and particle counterterms
2272 associated to couplings"""
2273
2274
2275 mod_vertex = []
2276 mod_particle_ct = []
2277 for coup in zero_couplings:
2278
2279 if coup not in self.coupling_pos:
2280 continue
2281
2282
2283
2284 vertices = [ vert for vert in self.coupling_pos[coup] if
2285 isinstance(vert, base_objects.Interaction) ]
2286 for vertex in vertices:
2287 modify = False
2288 for key, coupling in vertex['couplings'].items():
2289 if coupling in zero_couplings:
2290 modify=True
2291 del vertex['couplings'][key]
2292 elif coupling.startswith('-'):
2293 coupling = coupling[1:]
2294 if coupling in zero_couplings:
2295 modify=True
2296 del vertex['couplings'][key]
2297
2298 if modify:
2299 mod_vertex.append(vertex)
2300
2301
2302 particles_ct = [ pct for pct in self.coupling_pos[coup] if
2303 isinstance(pct, tuple)]
2304 for pct in particles_ct:
2305 modify = False
2306 for key, coupling in pct[0]['counterterm'][pct[1]].items():
2307 if coupling in zero_couplings:
2308 modify=True
2309 del pct[0]['counterterm'][pct[1]][key]
2310 if modify:
2311 mod_particle_ct.append(pct)
2312
2313
2314 for vertex in mod_vertex:
2315 part_name = [part['name'] for part in vertex['particles']]
2316 orders = ['%s=%s' % (order,value) for order,value in vertex['orders'].items()]
2317
2318 if not vertex['couplings']:
2319 logger_mod.log(self.log_level, 'remove interactions: %s at order: %s' % \
2320 (' '.join(part_name),', '.join(orders)))
2321 self['interactions'].remove(vertex)
2322 else:
2323 logger_mod.log(self.log_level, 'modify interactions: %s at order: %s' % \
2324 (' '.join(part_name),', '.join(orders)))
2325
2326
2327 for pct in mod_particle_ct:
2328 part_name = pct[0]['name']
2329 order = pct[1][0]
2330 loop_parts = ','.join(['('+','.join([\
2331 self.get_particle(p)['name'] for p in part])+')' \
2332 for part in pct[1][1]])
2333
2334 if not pct[0]['counterterm'][pct[1]]:
2335 logger_mod.log(self.log_level, 'remove counterterm of particle %s'%part_name+\
2336 ' with loop particles (%s)'%loop_parts+\
2337 ' perturbing order %s'%order)
2338 del pct[0]['counterterm'][pct[1]]
2339 else:
2340 logger_mod.log(self.log_level, 'Modify counterterm of particle %s'%part_name+\
2341 ' with loop particles (%s)'%loop_parts+\
2342 ' perturbing order %s'%order)
2343
2344 return
2345
2347
2348 for name, data in self['couplings'].items():
2349 for coupling in data[:]:
2350 if coupling.name in couplings:
2351 data.remove(coupling)
2352
2353
2354 - def fix_parameter_values(self, zero_parameters, one_parameters,
2355 simplify=True, keep_external=False):
2356 """ Remove all instance of the parameters in the model and replace it by
2357 zero when needed."""
2358
2359
2360
2361 for particle in self['particles']:
2362 if particle['mass'] in zero_parameters:
2363 particle['mass'] = 'ZERO'
2364 if particle['width'] in zero_parameters:
2365 particle['width'] = 'ZERO'
2366 if particle['width'] in one_parameters:
2367 one_parameters.remove(particle['width'])
2368 if particle['mass'] in one_parameters:
2369 one_parameters.remove(particle['mass'])
2370
2371 for pdg, particle in self['particle_dict'].items():
2372 if particle['mass'] in zero_parameters:
2373 particle['mass'] = 'ZERO'
2374 if particle['width'] in zero_parameters:
2375 particle['width'] = 'ZERO'
2376
2377
2378
2379 external_parameters = self['parameters'][('external',)]
2380 for param in external_parameters[:]:
2381 value = self['parameter_dict'][param.name]
2382 block = param.lhablock.lower()
2383 if value == 0:
2384 self.rule_card.add_zero(block, param.lhacode)
2385 elif value == 1:
2386 self.rule_card.add_one(block, param.lhacode)
2387
2388 special_parameters = zero_parameters + one_parameters
2389
2390
2391
2392 if simplify:
2393
2394 re_str = '|'.join(special_parameters)
2395 if len(re_str) > 25000:
2396 split = len(special_parameters) // 2
2397 re_str = ['|'.join(special_parameters[:split]),
2398 '|'.join(special_parameters[split:])]
2399 else:
2400 re_str = [ re_str ]
2401 used = set()
2402 for expr in re_str:
2403 re_pat = re.compile(r'''\b(%s)\b''' % expr)
2404
2405 for name, coupling_list in self['couplings'].items():
2406 for coupling in coupling_list:
2407 for use in re_pat.findall(coupling.expr):
2408 used.add(use)
2409
2410
2411 for lor in self['lorentz']:
2412 if hasattr(lor, 'formfactors') and lor.formfactors:
2413 for ff in lor.formfactors:
2414 for use in re_pat.findall(ff.value):
2415 used.add(use)
2416 else:
2417 used = set([i for i in special_parameters if i])
2418
2419
2420 re_str = '|'.join([param for param in special_parameters if param not in used])
2421 if len(re_str) > 25000:
2422 split = len(special_parameters) // 2
2423 re_str = ['|'.join(special_parameters[:split]),
2424 '|'.join(special_parameters[split:])]
2425 else:
2426 re_str = [ re_str ]
2427 for expr in re_str:
2428 re_pat = re.compile(r'''\b(%s)\b''' % expr)
2429
2430 param_info = {}
2431
2432 for dep, param_list in self['parameters'].items():
2433 for tag, parameter in enumerate(param_list):
2434
2435 if parameter.name in special_parameters:
2436 param_info[parameter.name]= {'dep': dep, 'tag': tag,
2437 'obj': parameter}
2438 continue
2439
2440
2441 if isinstance(parameter, base_objects.ParamCardVariable):
2442 continue
2443
2444 if simplify:
2445 for use in re_pat.findall(parameter.expr):
2446 used.add(use)
2447
2448
2449 for param in used:
2450 if not param:
2451 continue
2452 data = self['parameters'][param_info[param]['dep']]
2453 data.remove(param_info[param]['obj'])
2454 tag = param_info[param]['tag']
2455 data = self['parameters'][()]
2456 if param in zero_parameters:
2457 data.insert(0, base_objects.ModelVariable(param, '0.0', 'real'))
2458 else:
2459 data.insert(0, base_objects.ModelVariable(param, '1.0', 'real'))
2460
2461
2462 for param in special_parameters:
2463
2464 if param in used or \
2465 (keep_external and param_info[param]['dep'] == ('external',)):
2466 logger_mod.log(self.log_level, 'fix parameter value: %s' % param)
2467 continue
2468 logger_mod.log(self.log_level,'remove parameters: %s' % (param))
2469 data = self['parameters'][param_info[param]['dep']]
2470 data.remove(param_info[param]['obj'])
2471
2473
2474
2475
2476 to_lor = {}
2477 for (color, lor), coup in interaction['couplings'].items():
2478 abscoup, coeff = (coup[1:],-1) if coup.startswith('-') else (coup, 1)
2479 key = (color, abscoup)
2480 if key in to_lor:
2481 to_lor[key].append((lor,coeff))
2482 else:
2483 to_lor[key] = [(lor,coeff)]
2484
2485 nb_reduce = []
2486 optimize = False
2487 for key in to_lor:
2488 if len(to_lor[key]) >1:
2489 nb_reduce.append(len(to_lor[key])-1)
2490 optimize = True
2491
2492 if not optimize:
2493 return
2494
2495 if not hasattr(self, 'defined_lorentz_expr'):
2496 self.defined_lorentz_expr = {}
2497 self.lorentz_info = {}
2498 self.lorentz_combine = {}
2499 for lor in self.get('lorentz'):
2500 self.defined_lorentz_expr[lor.get('structure')] = lor.get('name')
2501 self.lorentz_info[lor.get('name')] = lor
2502
2503 for key in to_lor:
2504 if len(to_lor[key]) == 1:
2505 continue
2506 names = ['u%s' % interaction['lorentz'][i[0]] if i[1] ==1 else \
2507 'd%s' % interaction['lorentz'][i[0]] for i in to_lor[key]]
2508
2509 names.sort()
2510
2511
2512 if tuple(names) in self.lorentz_combine:
2513
2514 new_name = self.lorentz_combine[tuple(names)]
2515 else:
2516 new_name = self.add_merge_lorentz(names)
2517
2518
2519 color, coup = key
2520 to_remove = [(color, lor[0]) for lor in to_lor[key]]
2521 for rm in to_remove:
2522 del interaction['couplings'][rm]
2523
2524
2525 if new_name not in [l for l in interaction.get('lorentz')]:
2526 interaction.get('lorentz').append(new_name)
2527
2528
2529 new_l = interaction.get('lorentz').index(new_name)
2530
2531 interaction['couplings'][(color, new_l)] = coup
2532
2533
2534
2536 """add a lorentz structure which is the sume of the list given above"""
2537
2538
2539 ii = len(names[0])
2540 while ii>1:
2541
2542 if not all(n[1:].startswith(names[0][1:ii]) for n in names[1:]):
2543 ii -=1
2544 else:
2545 base_name = names[0][1:ii]
2546 break
2547 else:
2548 base_name = 'LMER'
2549 i = 1
2550 while '%s%s' %(base_name, i) in self.lorentz_info:
2551 i +=1
2552 new_name = '%s%s' %(base_name, i)
2553 self.lorentz_combine[tuple(names)] = new_name
2554
2555
2556 new_struct = ' + '.join([self.lorentz_info[n[1:]].get('structure') for n in names if n.startswith('u')])
2557 if any( n.startswith('d') for n in names ):
2558 new_struct += '-' + ' - '.join(['1.*(%s)' %self.lorentz_info[n[1:]].get('structure') for n in names if n.startswith('d')])
2559 spins = self.lorentz_info[names[0][1:]].get('spins')
2560 formfact = sum([ self.lorentz_info[n[1:]].get('formfactors') for n in names \
2561 if hasattr(self.lorentz_info[n[1:]], 'formfactors') \
2562 and self.lorentz_info[n[1:]].get('formfactors') \
2563 ],[])
2564
2565
2566
2567
2568 new_lor = self.add_lorentz(new_name, spins, new_struct, formfact)
2569 self.lorentz_info[new_name] = new_lor
2570
2571 return new_name
2572
2573 - def add_lorentz(self, name, spin, struct, formfact=None):
2574 """adding lorentz structure to the current model"""
2575 new = self['lorentz'][0].__class__(name = name,
2576 spins = spin,
2577 structure = struct)
2578 if formfact:
2579 new.formfactors = formfact
2580 self['lorentz'].append(new)
2581 self.create_lorentz_dict()
2582
2583 return None
2584