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
18 import fractions
19 import logging
20 import os
21 import re
22 import sys
23 import time
24
25
26 from madgraph import MadGraph5Error, MG5DIR, ReadWrite
27 import madgraph.core.base_objects as base_objects
28 import madgraph.loop.loop_base_objects as loop_base_objects
29 import madgraph.core.color_algebra as color
30 import madgraph.iolibs.files as files
31 import madgraph.iolibs.save_load_object as save_load_object
32 from madgraph.core.color_algebra import *
33 import madgraph.various.misc as misc
34 import madgraph.iolibs.ufo_expression_parsers as parsers
35
36 import aloha
37 import aloha.create_aloha as create_aloha
38 import aloha.aloha_fct as aloha_fct
39
40 import models as ufomodels
41 import models.model_reader as model_reader
42 logger = logging.getLogger('madgraph.model')
43 logger_mod = logging.getLogger('madgraph.model')
44
45 root_path = os.path.dirname(os.path.realpath( __file__ ))
46 sys.path.append(root_path)
47
48 sys.path.append(os.path.join(root_path, os.path.pardir, 'Template', 'bin', 'internal'))
49 import check_param_card
50
51 pjoin = os.path.join
52 logger = logging.getLogger("madgraph.model")
53
54
55 pole_dict = {-2:'2EPS',-1:'1EPS',0:'FIN'}
56
58 """ a error class for wrong import of UFO model"""
59
61 """ a class for invalid Model """
62
64 """ find the path to a model """
65
66
67 if model_name.startswith('./') and os.path.isdir(model_name):
68 model_path = model_name
69 elif os.path.isdir(os.path.join(MG5DIR, 'models', model_name)):
70 model_path = os.path.join(MG5DIR, 'models', model_name)
71 elif os.path.isdir(model_name):
72 model_path = model_name
73 else:
74 raise UFOImportError("Path %s is not a valid pathname" % model_name)
75
76 return model_path
77
78 -def import_model(model_name, decay=False, restrict=True, prefix='mdl_',
79 complex_mass_scheme = None):
80 """ a practical and efficient way to import a model"""
81
82
83 try:
84 model_path = find_ufo_path(model_name)
85 except UFOImportError:
86 if '-' not in model_name:
87 raise
88 split = model_name.split('-')
89 model_name = '-'.join([text for text in split[:-1]])
90 model_path = find_ufo_path(model_name)
91 restrict_name = split[-1]
92
93 restrict_file = os.path.join(model_path, 'restrict_%s.dat'% restrict_name)
94
95
96 if split[-1] == 'full':
97 restrict_file = None
98 else:
99
100 restrict_name = ""
101 if restrict and os.path.exists(os.path.join(model_path,'restrict_default.dat')):
102 restrict_file = os.path.join(model_path,'restrict_default.dat')
103 else:
104 restrict_file = None
105
106 if isinstance(restrict, str):
107 if os.path.exists(os.path.join(model_path, restrict)):
108 restrict_file = os.path.join(model_path, restrict)
109 elif os.path.exists(restrict):
110 restrict_file = restrict
111 else:
112 raise Exception, "%s is not a valid path for restrict file" % restrict
113
114
115 model = import_full_model(model_path, decay, prefix)
116
117 if os.path.exists(pjoin(model_path, "README")):
118 logger.info("Please read carefully the README of the model file for instructions/restrictions of the model.",'$MG:color:BLACK')
119
120 if restrict_name:
121 model["name"] += '-' + restrict_name
122
123
124 useCMS = (complex_mass_scheme is None and aloha.complex_mass) or \
125 complex_mass_scheme==True
126
127 if restrict_file:
128 try:
129 logger.info('Restrict model %s with file %s .' % (model_name, os.path.relpath(restrict_file)))
130 except OSError:
131
132 logger.info('Restrict model %s with file %s .' % (model_name, restrict_file))
133
134 if logger_mod.getEffectiveLevel() > 10:
135 logger.info('Run \"set stdout_level DEBUG\" before import for more information.')
136
137 model = RestrictModel(model)
138
139
140
141 if useCMS:
142
143
144
145
146
147 model.set_parameters_and_couplings(param_card = restrict_file,
148 complex_mass_scheme=False)
149 model.change_mass_to_complex_scheme(toCMS=True)
150 else:
151
152
153
154 model.change_mass_to_complex_scheme(toCMS=False)
155
156 if model_name == 'mssm' or os.path.basename(model_name) == 'mssm':
157 keep_external=True
158 else:
159 keep_external=False
160 model.restrict_model(restrict_file, rm_parameter=not decay,
161 keep_external=keep_external, complex_mass_scheme=complex_mass_scheme)
162 model.path = model_path
163 else:
164
165 if useCMS:
166 model.change_mass_to_complex_scheme(toCMS=True)
167 else:
168
169 model.change_mass_to_complex_scheme(toCMS=False)
170
171
172 return model
173
174
175 _import_once = []
177 """ a practical and efficient way to import one of those models
178 (no restriction file use)"""
179
180 assert model_path == find_ufo_path(model_path)
181
182 if prefix is True:
183 prefix='mdl_'
184
185
186 files_list_prov = ['couplings.py','lorentz.py','parameters.py',
187 'particles.py', 'vertices.py', 'function_library.py',
188 'propagators.py' ]
189
190 if decay:
191 files_list_prov.append('decays.py')
192
193 files_list = []
194 for filename in files_list_prov:
195 filepath = os.path.join(model_path, filename)
196 if not os.path.isfile(filepath):
197 if filename not in ['propagators.py', 'decays.py']:
198 raise UFOImportError, "%s directory is not a valid UFO model: \n %s is missing" % \
199 (model_path, filename)
200 files_list.append(filepath)
201
202
203 if aloha.unitary_gauge:
204 pickle_name = 'model.pkl'
205 else:
206 pickle_name = 'model_Feynman.pkl'
207 if decay:
208 pickle_name = 'dec_%s' % pickle_name
209
210 allow_reload = False
211 if files.is_uptodate(os.path.join(model_path, pickle_name), files_list):
212 allow_reload = True
213 try:
214 model = save_load_object.load_from_file( \
215 os.path.join(model_path, pickle_name))
216 except Exception, error:
217 logger.info('failed to load model from pickle file. Try importing UFO from File')
218 else:
219
220 if model.has_key('version_tag') and not model.get('version_tag') is None and \
221 model.get('version_tag').startswith(os.path.realpath(model_path)) and \
222 model.get('version_tag').endswith('##' + str(misc.get_pkg_info())):
223
224 for key in model.get('parameters'):
225 for param in model['parameters'][key]:
226 value = param.name.lower()
227 if value in ['as','mu_r', 'zero','aewm1']:
228 continue
229 if prefix:
230 if value.startswith(prefix):
231 _import_once.append((model_path, aloha.unitary_gauge, prefix, decay))
232 return model
233 else:
234 logger.info('reload from .py file')
235 break
236 else:
237 if value.startswith('mdl_'):
238 logger.info('reload from .py file')
239 break
240 else:
241 _import_once.append((model_path, aloha.unitary_gauge, prefix, decay))
242 return model
243 else:
244 continue
245 break
246 else:
247 logger.info('reload from .py file')
248
249 if (model_path, aloha.unitary_gauge, prefix, decay) in _import_once and not allow_reload:
250 raise MadGraph5Error, 'This model %s is modified on disk. To reload it you need to quit/relaunch MG5_aMC ' % model_path
251
252
253 ufo_model = ufomodels.load_model(model_path, decay)
254 ufo2mg5_converter = UFOMG5Converter(ufo_model)
255 model = ufo2mg5_converter.load_model()
256 if model_path[-1] == '/': model_path = model_path[:-1]
257 model.set('name', os.path.split(model_path)[-1])
258
259
260 parameters, couplings = OrganizeModelExpression(ufo_model).main(\
261 additional_couplings =(ufo2mg5_converter.wavefunction_CT_couplings
262 if ufo2mg5_converter.perturbation_couplings else []))
263
264 model.set('parameters', parameters)
265 model.set('couplings', couplings)
266 model.set('functions', ufo_model.all_functions)
267
268
269
270
271 if decay and hasattr(ufo_model, 'all_decays') and ufo_model.all_decays:
272 start = time.time()
273 for ufo_part in ufo_model.all_particles:
274 name = ufo_part.name
275 if not model['case_sensitive']:
276 name = name.lower()
277 p = model['particles'].find_name(name)
278 if hasattr(ufo_part, 'partial_widths'):
279 p.partial_widths = ufo_part.partial_widths
280 elif p and not hasattr(p, 'partial_widths'):
281 p.partial_widths = {}
282
283 logger.debug("load width takes %s", time.time()-start)
284
285 if prefix:
286 start = time.time()
287 model.change_parameter_name_with_prefix()
288 logger.debug("model prefixing takes %s", time.time()-start)
289
290 path = os.path.dirname(os.path.realpath(model_path))
291 path = os.path.join(path, model.get('name'))
292 model.set('version_tag', os.path.realpath(path) +'##'+ str(misc.get_pkg_info()))
293
294
295 if ReadWrite:
296 save_load_object.save_to_file(os.path.join(model_path, pickle_name),
297 model, log=False)
298
299
300
301
302
303
304 return model
305
307 """Convert a UFO model to the MG5 format"""
308
310 """ initialize empty list for particles/interactions """
311
312 self.particles = base_objects.ParticleList()
313 self.interactions = base_objects.InteractionList()
314 self.wavefunction_CT_couplings = []
315
316
317
318
319 self.perturbation_couplings = {}
320 try:
321 for order in model.all_orders:
322 if(order.perturbative_expansion>0):
323 self.perturbation_couplings[order.name]=order.perturbative_expansion
324 except AttributeError,error:
325 pass
326
327 if self.perturbation_couplings!={}:
328 self.model = loop_base_objects.LoopModel({'perturbation_couplings':\
329 self.perturbation_couplings.keys()})
330 else:
331 self.model = base_objects.Model()
332 self.model.set('particles', self.particles)
333 self.model.set('interactions', self.interactions)
334 self.conservecharge = set(['charge'])
335
336 self.ufomodel = model
337 self.checked_lor = set()
338
339 if auto:
340 self.load_model()
341
343 """load the different of the model first particles then interactions"""
344
345
346
347 def_name = []
348 for param in self.ufomodel.all_parameters:
349 if param.nature == "external":
350 if len(param.lhablock.split())>1:
351 raise InvalidModel, '''LHABlock should be single word which is not the case for
352 \'%s\' parameter with lhablock \'%s\' ''' % (param.name, param.lhablock)
353 if param.name in def_name:
354 raise InvalidModel, "name %s define multiple time. Please correct the UFO model!" \
355 % (param.name)
356 else:
357 def_name.append(param.name)
358
359
360
361 if hasattr(self.ufomodel,'all_CTparameters'):
362 for CTparam in self.ufomodel.all_CTparameters:
363 for pole in pole_dict:
364 if CTparam.pole(pole)!='ZERO':
365 new_param_name = '%s_%s_'%(CTparam.name,pole_dict[pole])
366 if new_param_name in def_name:
367 raise InvalidModel, "CT name %s"% (new_param_name)+\
368 " the model. Please change its name."
369
370 if hasattr(self.ufomodel, 'gauge'):
371 self.model.set('gauge', self.ufomodel.gauge)
372 logger.info('load particles')
373
374
375 if len(set([p.name for p in self.ufomodel.all_particles] + \
376 [p.antiname for p in self.ufomodel.all_particles])) == \
377 len(set([p.name.lower() for p in self.ufomodel.all_particles] + \
378 [p.antiname.lower() for p in self.ufomodel.all_particles])):
379 self.model['case_sensitive'] = False
380
381
382
383 self.detect_incoming_fermion()
384
385 for particle_info in self.ufomodel.all_particles:
386 self.add_particle(particle_info)
387
388
389 color_info = self.find_color_anti_color_rep()
390
391
392 self.model.set('lorentz', self.ufomodel.all_lorentz)
393
394
395
396
397
398
399
400
401
402 if hasattr(self.ufomodel,'all_CTparameters'):
403 logger.debug('Handling couplings defined with CTparameters...')
404 start_treat_coupling = time.time()
405 self.treat_couplings(self.ufomodel.all_couplings,
406 self.ufomodel.all_CTparameters)
407 tot_time = time.time()-start_treat_coupling
408 if tot_time>5.0:
409 logger.debug('... done in %s'%misc.format_time(tot_time))
410
411 logger.info('load vertices')
412 for interaction_info in self.ufomodel.all_vertices:
413 self.add_interaction(interaction_info, color_info)
414
415 if self.perturbation_couplings:
416 try:
417 self.ufomodel.add_NLO()
418 except Exception, error:
419 pass
420
421 for interaction_info in self.ufomodel.all_CTvertices:
422 self.add_CTinteraction(interaction_info, color_info)
423
424 self.model.set('conserved_charge', self.conservecharge)
425
426
427
428
429 all_orders = []
430 try:
431 all_orders = self.ufomodel.all_orders
432 except AttributeError:
433 if self.perturbation_couplings:
434 raise MadGraph5Error, "The loop model MG5 attemps to import does not specify the attribute 'all_order'."
435 else:
436 pass
437
438 hierarchy={}
439 try:
440 for order in all_orders:
441 hierarchy[order.name]=order.hierarchy
442 except AttributeError:
443 if self.perturbation_couplings:
444 raise MadGraph5Error, 'The loop model MG5 attemps to import does not specify an order hierarchy.'
445 else:
446 pass
447 else:
448 self.model.set('order_hierarchy', hierarchy)
449
450
451 expansion_order={}
452
453 coupling_order_counterterms={}
454 try:
455 for order in all_orders:
456 expansion_order[order.name]=order.expansion_order
457 coupling_order_counterterms[order.name]=order.expansion_order
458 except AttributeError:
459 if self.perturbation_couplings:
460 raise MadGraph5Error, 'The loop model MG5 attemps to import does not specify an expansion_order for all coupling orders.'
461 else:
462 pass
463 else:
464 self.model.set('expansion_order', expansion_order)
465 self.model.set('expansion_order', expansion_order)
466
467
468 del self.checked_lor
469
470 return self.model
471
472
473 - def add_particle(self, particle_info):
474 """ convert and add a particle in the particle list """
475
476 loop_particles = [[[]]]
477 counterterms = {}
478
479
480
481 pdg = particle_info.pdg_code
482 if pdg in self.incoming or (pdg not in self.outcoming and pdg <0):
483 return
484
485
486 if not self.perturbation_couplings and particle_info.spin < 0:
487 return
488
489 if (aloha.unitary_gauge and 0 in self.model['gauge']) \
490 or (1 not in self.model['gauge']):
491
492
493 if hasattr(particle_info, 'GoldstoneBoson') and particle_info.GoldstoneBoson:
494 return
495 elif hasattr(particle_info, 'goldstone') and particle_info.goldstone:
496 return
497
498 particle = base_objects.Particle()
499
500
501 if hasattr(particle_info, 'GoldstoneBoson') and particle_info.GoldstoneBoson:
502 particle.set('type', 'goldstone')
503 elif hasattr(particle_info, 'goldstone') and particle_info.goldstone:
504 particle.set('type', 'goldstone')
505
506 nb_property = 0
507
508 for key,value in particle_info.__dict__.items():
509
510 if key in base_objects.Particle.sorted_keys and not key=='counterterm':
511 nb_property +=1
512 if key in ['name', 'antiname']:
513 if not self.model['case_sensitive']:
514 particle.set(key, value.lower())
515 else:
516 particle.set(key, value)
517 elif key == 'charge':
518 particle.set(key, float(value))
519 elif key in ['mass','width']:
520 particle.set(key, str(value))
521 elif key == 'spin':
522
523
524 particle.set(key,abs(value))
525 if value<0:
526 particle.set('type','ghost')
527 elif key == 'propagating':
528 if not value:
529 particle.set('line', None)
530 elif key == 'line':
531 if particle.get('line') is None:
532 pass
533 else:
534 particle.set('line', value)
535 elif key == 'propagator':
536 if value:
537 if aloha.unitary_gauge:
538 particle.set(key, str(value[0]))
539 else:
540 particle.set(key, str(value[1]))
541 else:
542 particle.set(key, '')
543 else:
544 particle.set(key, value)
545 elif key == 'loop_particles':
546 loop_particles = value
547 elif key == 'counterterm':
548 counterterms = value
549 elif key.lower() not in ('ghostnumber','selfconjugate','goldstone',
550 'goldstoneboson','partial_widths',
551 'texname', 'antitexname', 'propagating', 'ghost'
552 ):
553
554 self.conservecharge.add(key)
555 particle.set(key,value, force=True)
556
557 if not hasattr(particle_info, 'propagator'):
558 nb_property += 1
559 if particle.get('spin') >= 3:
560 if particle.get('mass').lower() == 'zero':
561 particle.set('propagator', 0)
562 elif particle.get('spin') == 3 and not aloha.unitary_gauge:
563 particle.set('propagator', 0)
564
565 assert(10 == nb_property)
566
567
568 if particle_info.name == particle_info.antiname:
569 particle.set('self_antipart', True)
570
571
572
573 if not self.perturbation_couplings or counterterms=={}:
574 self.particles.append(particle)
575 return
576
577
578
579
580
581
582 particle_counterterms = {}
583 for key, counterterm in counterterms.items():
584
585 if len([1 for k in key[:-1] if k==1])==1 and \
586 not any(k>1 for k in key[:-1]):
587 newParticleCountertermKey=[None,\
588
589
590
591
592
593 tuple([tuple(loop_parts) for\
594 loop_parts in loop_particles[key[-1]]])]
595 for i, order in enumerate(self.ufomodel.all_orders[:-1]):
596 if key[i]==1:
597 newParticleCountertermKey[0]=order.name
598 newCouplingName='UVWfct_'+particle_info.name+'_'+str(key[-1])
599 particle_counterterms[tuple(newParticleCountertermKey)]=\
600 dict([(key,newCouplingName+('' if key==0 else '_'+str(-key)+'eps'))\
601 for key in counterterm])
602
603
604 self.ufomodel.object_library.Coupling(\
605 name = newCouplingName,
606 value = counterterm,
607 order = {newParticleCountertermKey[0]:2})
608 self.wavefunction_CT_couplings.append(self.ufomodel.all_couplings.pop())
609
610 particle.set('counterterm',particle_counterterms)
611 self.particles.append(particle)
612 return
613
615 """ This function scan each coupling to see if it contains a CT parameter.
616 when it does, it changes its value to a dictionary with the CT parameter
617 changed to a new parameter for each pole and finite part. For instance,
618 the following coupling:
619 coupling.value = '2*(myCTParam1 + myParam*(myCTParam2 + myCTParam3)'
620 with CTparameters
621 myCTParam1 = {0: Something, -1: SomethingElse}
622 myCTParam2 = {0: OtherSomething }
623 myCTParam3 = {-1: YetOtherSomething }
624 would be turned into
625 coupling.value = {0: '2*(myCTParam1_FIN_ + myParam*(myCTParam2_FIN_ + ZERO)'
626 -1: '2*(myCTParam1_EPS_ + myParam*(ZERO + myCTParam2_EPS_)'}
627
628 all_CTParameter is the list of all CTParameters in the model"""
629
630
631
632
633
634
635 CTparameter_patterns = {}
636 zero_substitution = lambda matchedObj: matchedObj.group('first')+\
637 'ZERO'+matchedObj.group('second')
638 def function_factory(arg):
639 return lambda matchedObj: \
640 matchedObj.group('first')+arg+matchedObj.group('second')
641 for CTparam in all_CTparameters:
642 pattern_finder = re.compile(r"(?P<first>\A|\*|\+|\-|\(|\s)(?P<name>"+
643 CTparam.name+r")(?P<second>\Z|\*|\+|\-|\)|/|\\|\s)")
644
645 sub_functions = [None if CTparam.pole(pole)=='ZERO' else
646 function_factory('%s_%s_'%(CTparam.name,pole_dict[-pole]))
647 for pole in range(3)]
648 CTparameter_patterns[CTparam.name] = (pattern_finder,sub_functions)
649
650 times_zero = re.compile('\*\s*-?ZERO')
651 zero_times = re.compile('ZERO\s*(\*|\/)')
652 def is_expr_zero(expresson):
653 """ Checks whether a single term (involving only the operations
654 * or / is zero. """
655 for term in expresson.split('-'):
656 for t in term.split('+'):
657 t = t.strip()
658 if t in ['ZERO','']:
659 continue
660 if not (times_zero.search(t) or zero_times.search(t)):
661 return False
662 return True
663
664 def find_parenthesis(expr):
665 end = expr.find(')')
666 if end == -1:
667 return None
668 start = expr.rfind('(',0,end+1)
669 if start ==-1:
670 raise InvalidModel,\
671 'Parenthesis of expression %s are malformed'%expr
672 return [expr[:start],expr[start+1:end],expr[end+1:]]
673
674 start_parenthesis = re.compile(r".*\s*[\+\-\*\/\)\(]\s*$")
675 def is_value_zero(value):
676 """Check whether an expression like ((A+B)*ZERO+C)*ZERO is zero.
677 Only +,-,/,* operations are allowed and 'ZERO' is a tag for an
678 analytically zero quantity."""
679
680 parenthesis = find_parenthesis(value)
681 if parenthesis:
682
683 if parenthesis[0].endswith('complexconjugate'):
684
685 parenthesis[0] = parenthesis[0][:-16]
686 if parenthesis[0]=='' or re.match(start_parenthesis,
687 parenthesis[0]):
688 if is_value_zero(parenthesis[1]):
689 new_parenthesis = 'ZERO'
690 else:
691 new_parenthesis = 'PARENTHESIS'
692 else:
693 new_parenthesis = '_FUNCTIONARGS'
694 new_value = parenthesis[0]+new_parenthesis+parenthesis[2]
695 return is_value_zero(new_value)
696 else:
697 return is_expr_zero(value)
698
699 def CTCoupling_pole(CTCoupling, pole):
700 """Compute the pole of the CTCoupling in two cases:
701 a) Its value is a dictionary, then just return the corresponding
702 entry in the dictionary.
703 b) It is expressed in terms of CTParameters which are themselves
704 dictionary so we want to substitute their expression to get
705 the value of the pole. In the current implementation, this is
706 just to see if the pole is zero or not.
707 """
708
709 if isinstance(CTCoupling.value,dict):
710 if -pole in CTCoupling.value.keys():
711 return CTCoupling.value[-pole], [], 0
712 else:
713 return 'ZERO', [], 0
714
715 new_expression = CTCoupling.value
716 CTparamNames = []
717 n_CTparams = 0
718 for paramname, value in CTparameter_patterns.items():
719 pattern = value[0]
720
721
722 if not re.search(pattern,new_expression):
723 continue
724 n_CTparams += 1
725
726
727 if not value[1][pole] is None:
728 CTparamNames.append('%s_%s_'%(paramname,pole_dict[-pole]))
729
730 substitute_function = zero_substitution if \
731 value[1][pole] is None else value[1][pole]
732 new_expression = pattern.sub(substitute_function,new_expression)
733
734
735
736 if pole!=0 and n_CTparams==0:
737 return 'ZERO', [], n_CTparams
738
739
740
741
742
743
744 if n_CTparams > 0 and is_value_zero(new_expression):
745 return 'ZERO', [], n_CTparams
746 else:
747 return new_expression, CTparamNames, n_CTparams
748
749
750 for coupl in couplings:
751 new_value = {}
752 for pole in range(0,3):
753 expression, CTparamNames, n_CTparams = CTCoupling_pole(coupl, pole)
754
755 if n_CTparams == 0:
756 break
757 elif expression!='ZERO':
758 new_value[-pole] = expression
759 couplname = coupl.name
760 if pole!=0:
761 couplname += "_%deps"%pole
762
763
764
765
766 if hasattr(self.model, 'map_CTcoup_CTparam'):
767 self.model.map_CTcoup_CTparam[couplname] = CTparamNames
768
769
770
771
772
773
774
775
776 if new_value:
777 coupl.old_value = coupl.value
778 coupl.value = new_value
779
781 """ Split this interaction in order to call add_interaction for
782 interactions for each element of the loop_particles list. Also it
783 is necessary to unfold here the contributions to the different laurent
784 expansion orders of the couplings."""
785
786
787 interaction_info=copy.copy(interaction)
788
789 intType=''
790 if interaction_info.type not in ['UV','UVloop','UVtree','UVmass','R2']:
791 raise MadGraph5Error, 'MG5 only supports the following types of'+\
792 ' vertices, R2, UV and UVmass. %s is not in this list.'%interaction_info.type
793 else:
794 intType=interaction_info.type
795
796 if interaction_info.type=='UV':
797 if len(interaction_info.particles)==2 and interaction_info.\
798 particles[0].name==interaction_info.particles[1].name:
799 intType='UVmass'
800 else:
801 intType='UVloop'
802
803
804
805
806
807
808
809
810
811
812
813 new_couplings=[[{} for j in range(0,3)] for i in \
814 range(0,max(1,len(interaction_info.loop_particles)))]
815
816
817 for key, coupling in interaction_info.couplings.items():
818 for poleOrder in range(0,3):
819 expression = coupling.pole(poleOrder)
820 if expression!='ZERO':
821 if poleOrder==2:
822 raise InvalidModel, """
823 The CT coupling %s was found with a contribution to the double pole.
824 This is either an error in the model or a parsing error in the function 'is_value_zero'.
825 The expression of the non-zero double pole coupling is:
826 %s
827 """%(coupling.name,str(coupling.value))
828
829
830
831 newCoupling = copy.copy(coupling)
832 if poleOrder!=0:
833 newCoupling.name=newCoupling.name+"_"+str(poleOrder)+"eps"
834 newCoupling.value = expression
835
836
837
838
839
840
841
842 new_couplings[key[2]][poleOrder][(key[0],key[1])] = newCoupling
843
844
845 for i, all_couplings in enumerate(new_couplings):
846 loop_particles=[[]]
847 if len(interaction_info.loop_particles)>0:
848 loop_particles=[[part.pdg_code for part in loop_parts] \
849 for loop_parts in interaction_info.loop_particles[i]]
850 for poleOrder in range(0,3):
851 if all_couplings[poleOrder]!={}:
852 interaction_info.couplings=all_couplings[poleOrder]
853 self.add_interaction(interaction_info, color_info,\
854 (intType if poleOrder==0 else (intType+str(poleOrder)+\
855 'eps')),loop_particles)
856
857
859 """find which color are in the 3/3bar states"""
860
861
862
863
864 if not output:
865 output = {}
866
867 for interaction_info in self.ufomodel.all_vertices:
868 if len(interaction_info.particles) != 3:
869 continue
870 colors = [abs(p.color) for p in interaction_info.particles]
871 if colors[:2] == [3,3]:
872 if 'T(3,2,1)' in interaction_info.color:
873 color, anticolor, other = interaction_info.particles
874 elif 'T(3,1,2)' in interaction_info.color:
875 anticolor, color, _ = interaction_info.particles
876 elif 'Identity(1,2)' in interaction_info.color or \
877 'Identity(2,1)' in interaction_info.color:
878 first, second, _ = interaction_info.particles
879 if first.pdg_code in output:
880 if output[first.pdg_code] == 3:
881 color, anticolor = first, second
882 else:
883 color, anticolor = second, first
884 elif second.pdg_code in output:
885 if output[second.pdg_code] == 3:
886 color, anticolor = second, first
887 else:
888 color, anticolor = first, second
889 else:
890 continue
891 else:
892 continue
893 elif colors[1:] == [3,3]:
894 if 'T(1,2,3)' in interaction_info.color:
895 other, anticolor, color = interaction_info.particles
896 elif 'T(1,3,2)' in interaction_info.color:
897 other, color, anticolor = interaction_info.particles
898 elif 'Identity(2,3)' in interaction_info.color or \
899 'Identity(3,2)' in interaction_info.color:
900 _, first, second = interaction_info.particles
901 if first.pdg_code in output:
902 if output[first.pdg_code] == 3:
903 color, anticolor = first, second
904 else:
905 color, anticolor = second, first
906 elif second.pdg_code in output:
907 if output[second.pdg_code] == 3:
908 color, anticolor = second, first
909 else:
910 color, anticolor = first, second
911 else:
912 continue
913 else:
914 continue
915
916 elif colors.count(3) == 2:
917 if 'T(2,3,1)' in interaction_info.color:
918 color, other, anticolor = interaction_info.particles
919 elif 'T(2,1,3)' in interaction_info.color:
920 anticolor, other, color = interaction_info.particles
921 elif 'Identity(1,3)' in interaction_info.color or \
922 'Identity(3,1)' in interaction_info.color:
923 first, _, second = interaction_info.particles
924 if first.pdg_code in output:
925 if output[first.pdg_code] == 3:
926 color, anticolor = first, second
927 else:
928 color, anticolor = second, first
929 elif second.pdg_code in output:
930 if output[second.pdg_code] == 3:
931 color, anticolor = second, first
932 else:
933 color, anticolor = first, second
934 else:
935 continue
936 else:
937 continue
938 else:
939 continue
940
941
942 if color.pdg_code in output:
943 if output[color.pdg_code] == -3:
944 raise InvalidModel, 'Particles %s is sometimes in the 3 and sometimes in the 3bar representations' \
945 % color.name
946 else:
947 output[color.pdg_code] = 3
948
949
950 if anticolor.pdg_code in output:
951 if output[anticolor.pdg_code] == 3:
952 raise InvalidModel, 'Particles %s is sometimes set as in the 3 and sometimes in the 3bar representations' \
953 % anticolor.name
954 else:
955 output[anticolor.pdg_code] = -3
956
957 return output
958
960 """define which fermion should be incoming
961 for that we look at F F~ X interactions
962 """
963 self.incoming = []
964 self.outcoming = []
965 for interaction_info in self.ufomodel.all_vertices:
966
967 pdg = [p.pdg_code for p in interaction_info.particles if p.spin in [2,4]]
968 if len(pdg) % 2:
969 raise InvalidModel, 'Odd number of fermion in vertex: %s' % [p.pdg_code for p in interaction_info.particles]
970 for i in range(0, len(pdg),2):
971 if pdg[i] == - pdg[i+1]:
972 if pdg[i] in self.outcoming:
973 raise InvalidModel, '%s has not coherent incoming/outcoming status between interactions' %\
974 [p for p in interaction_info.particles if p.spin in [2,4]][i].name
975
976 elif not pdg[i] in self.incoming:
977 self.incoming.append(pdg[i])
978 self.outcoming.append(pdg[i+1])
979
980 - def add_interaction(self, interaction_info, color_info, type='base', loop_particles=None):
981 """add an interaction in the MG5 model. interaction_info is the
982 UFO vertices information."""
983
984 particles = [self.model.get_particle(particle.pdg_code) \
985 for particle in interaction_info.particles]
986 if None in particles:
987
988 return
989 particles = base_objects.ParticleList(particles)
990
991
992 lorentz = [helas for helas in interaction_info.lorentz]
993
994
995 nb_fermion = sum([ 1 if p.is_fermion() else 0 for p in particles])
996 try:
997 if nb_fermion == 2:
998
999 [aloha_fct.check_flow_validity(helas.structure, nb_fermion) \
1000 for helas in interaction_info.lorentz
1001 if helas.name not in self.checked_lor]
1002 self.checked_lor.update(set([helas.name for helas in interaction_info.lorentz]))
1003 elif nb_fermion:
1004 if any(p.selfconjugate for p in interaction_info.particles if p.spin % 2 == 0):
1005 text = "Majorana can not be dealt in 4/6/... fermion interactions"
1006 raise InvalidModel, text
1007 except aloha_fct.WrongFermionFlow, error:
1008 text = 'Fermion Flow error for interactions %s: %s: %s\n %s' % \
1009 (', '.join([p.name for p in interaction_info.particles]),
1010 helas.name, helas.structure, error)
1011 raise InvalidModel, text
1012
1013
1014
1015
1016 lorentz = [helas.name for helas in lorentz]
1017
1018 colors = [self.treat_color(color_obj, interaction_info, color_info)
1019 for color_obj in interaction_info.color]
1020
1021
1022 order_to_int={}
1023
1024 for key, couplings in interaction_info.couplings.items():
1025 if not isinstance(couplings, list):
1026 couplings = [couplings]
1027 if interaction_info.lorentz[key[1]].name not in lorentz:
1028 continue
1029
1030 if nb_fermion > 2:
1031 flow = aloha_fct.get_fermion_flow(interaction_info.lorentz[key[1]].structure,
1032 nb_fermion)
1033 coupling_sign = self.get_sign_flow(flow, nb_fermion)
1034 else:
1035 coupling_sign = ''
1036 for coupling in couplings:
1037 order = tuple(coupling.order.items())
1038 if '1' in order:
1039 raise InvalidModel, '''Some couplings have \'1\' order.
1040 This is not allowed in MG.
1041 Please defines an additional coupling to your model'''
1042 if order in order_to_int:
1043 order_to_int[order].get('couplings')[key] = '%s%s' % \
1044 (coupling_sign,coupling.name)
1045 else:
1046
1047 interaction = base_objects.Interaction({'id':len(self.interactions)+1})
1048 interaction.set('particles', particles)
1049 interaction.set('lorentz', lorentz)
1050 interaction.set('couplings', {key:
1051 '%s%s' %(coupling_sign,coupling.name)})
1052 interaction.set('orders', coupling.order)
1053 interaction.set('color', colors)
1054 interaction.set('type', type)
1055 interaction.set('loop_particles', loop_particles)
1056 order_to_int[order] = interaction
1057
1058 self.interactions.append(interaction)
1059
1060
1061
1062 for charge in list(self.conservecharge):
1063 total = 0
1064 for part in interaction_info.particles:
1065 try:
1066 total += getattr(part, charge)
1067 except AttributeError:
1068 pass
1069 if abs(total) > 1e-12:
1070 logger.info('The model has interaction violating the charge: %s' % charge)
1071 self.conservecharge.discard(charge)
1072
1073
1075 """ensure that the flow of particles/lorentz are coherent with flow
1076 and return a correct version if needed"""
1077
1078 if not flow or nb_fermion < 4:
1079 return ''
1080
1081 expected = {}
1082 for i in range(nb_fermion//2):
1083 expected[i+1] = i+2
1084
1085 if flow == expected:
1086 return ''
1087
1088 switch = {}
1089 for i in range(1, nb_fermion+1):
1090 if not i in flow:
1091 continue
1092 switch[i] = len(switch)
1093 switch[flow[i]] = len(switch)
1094
1095
1096 sign = 1
1097 done = []
1098
1099
1100
1101 new_order = []
1102 for id in range(nb_fermion):
1103 nid = switch[id+1]-1
1104
1105 new_order.append(nid)
1106
1107
1108 sign =1
1109 for k in range(len(new_order)-1):
1110 for l in range(k+1,len(new_order)):
1111 if new_order[l] < new_order[k]:
1112 sign *= -1
1113
1114 return '' if sign ==1 else '-'
1115
1116
1117
1118
1120 """ Add a Lorentz expression which is not present in the UFO """
1121
1122 new = self.model['lorentz'][0].__class__(name = name,
1123 spins = spins,
1124 structure = expr)
1125
1126 self.model['lorentz'].append(new)
1127 self.model.create_lorentz_dict()
1128 return name
1129
1130 _pat_T = re.compile(r'T\((?P<first>\d*),(?P<second>\d*)\)')
1131 _pat_id = re.compile(r'Identity\((?P<first>\d*),(?P<second>\d*)\)')
1132
1133 - def treat_color(self, data_string, interaction_info, color_info):
1134 """ convert the string to ColorString"""
1135
1136
1137
1138
1139
1140 output = []
1141 factor = 1
1142 for term in data_string.split('*'):
1143 pattern = self._pat_id.search(term)
1144 if pattern:
1145 particle = interaction_info.particles[int(pattern.group('first'))-1]
1146 particle2 = interaction_info.particles[int(pattern.group('second'))-1]
1147 if particle.color == particle2.color and particle.color in [-6, 6]:
1148 error_msg = 'UFO model have inconsistency in the format:\n'
1149 error_msg += 'interactions for particles %s has color information %s\n'
1150 error_msg += ' but both fermion are in the same representation %s'
1151 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
1152 if particle.color == particle2.color and particle.color in [-3, 3]:
1153 if particle.pdg_code in color_info and particle2.pdg_code in color_info:
1154 if color_info[particle.pdg_code] == color_info[particle2.pdg_code]:
1155 error_msg = 'UFO model have inconsistency in the format:\n'
1156 error_msg += 'interactions for particles %s has color information %s\n'
1157 error_msg += ' but both fermion are in the same representation %s'
1158 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
1159 elif particle.pdg_code in color_info:
1160 color_info[particle2.pdg_code] = -particle.pdg_code
1161 elif particle2.pdg_code in color_info:
1162 color_info[particle.pdg_code] = -particle2.pdg_code
1163 else:
1164 error_msg = 'UFO model have inconsistency in the format:\n'
1165 error_msg += 'interactions for particles %s has color information %s\n'
1166 error_msg += ' but both fermion are in the same representation %s'
1167 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
1168
1169
1170 if particle.color == 6:
1171 output.append(self._pat_id.sub('color.T6(\g<first>,\g<second>)', term))
1172 elif particle.color == -6 :
1173 output.append(self._pat_id.sub('color.T6(\g<second>,\g<first>)', term))
1174 elif particle.color == 8:
1175 output.append(self._pat_id.sub('color.Tr(\g<first>,\g<second>)', term))
1176 factor *= 2
1177 elif particle.color in [-3,3]:
1178 if particle.pdg_code not in color_info:
1179
1180 logger.debug('fail to find 3/3bar representation: Retry to find it')
1181 color_info = self.find_color_anti_color_rep(color_info)
1182 if particle.pdg_code not in color_info:
1183 logger.debug('Not able to find the 3/3bar rep from the interactions for particle %s' % particle.name)
1184 color_info[particle.pdg_code] = particle.color
1185 else:
1186 logger.debug('succeed')
1187 if particle2.pdg_code not in color_info:
1188
1189 logger.debug('fail to find 3/3bar representation: Retry to find it')
1190 color_info = self.find_color_anti_color_rep(color_info)
1191 if particle2.pdg_code not in color_info:
1192 logger.debug('Not able to find the 3/3bar rep from the interactions for particle %s' % particle2.name)
1193 color_info[particle2.pdg_code] = particle2.color
1194 else:
1195 logger.debug('succeed')
1196
1197 if color_info[particle.pdg_code] == 3 :
1198 output.append(self._pat_id.sub('color.T(\g<second>,\g<first>)', term))
1199 elif color_info[particle.pdg_code] == -3:
1200 output.append(self._pat_id.sub('color.T(\g<first>,\g<second>)', term))
1201 else:
1202 raise MadGraph5Error, \
1203 "Unknown use of Identity for particle with color %d" \
1204 % particle.color
1205 else:
1206 output.append(term)
1207 data_string = '*'.join(output)
1208
1209
1210 p = re.compile(r'\'\w(?P<number>\d+)\'')
1211 data_string = p.sub('-\g<number>', data_string)
1212
1213
1214 new_indices = {}
1215 new_indices = dict([(j,i) for (i,j) in \
1216 enumerate(range(1,
1217 len(interaction_info.particles)+1))])
1218
1219
1220 output = data_string.split('*')
1221 output = color.ColorString([eval(data) \
1222 for data in output if data !='1'])
1223 output.coeff = fractions.Fraction(factor)
1224 for col_obj in output:
1225 col_obj.replace_indices(new_indices)
1226
1227 return output
1228
1230 """Organize the couplings/parameters of a model"""
1231
1232 track_dependant = ['aS','aEWM1','MU_R']
1233
1234
1235
1236
1237 complex_number = re.compile(r'''complex\((?P<real>[^,\(\)]+),(?P<imag>[^,\(\)]+)\)''')
1238 expo_expr = re.compile(r'''(?P<expr>[\w.]+)\s*\*\*\s*(?P<expo>[+-]?[\d.]+)''')
1239 cmath_expr = re.compile(r'''cmath.(?P<operation>\w+)\((?P<expr>\w+)\)''')
1240
1241 conj_expr = re.compile(r'''complexconjugate\((?P<expr>\w+)\)''')
1242
1243
1244 separator = re.compile(r'''[+,\-*/()\s]*''')
1245
1246
1248
1249 self.model = model
1250 self.perturbation_couplings = {}
1251 try:
1252 for order in model.all_orders:
1253 if(order.perturbative_expansion>0):
1254 self.perturbation_couplings[order.name]=order.perturbative_expansion
1255 except AttributeError:
1256 pass
1257 self.params = {}
1258 self.couplings = {}
1259 self.all_expr = {}
1260
1261 - def main(self, additional_couplings = []):
1262 """Launch the actual computation and return the associate
1263 params/couplings. Possibly consider additional_couplings in addition
1264 to those defined in the UFO model attribute all_couplings """
1265
1266 additional_params = []
1267 if hasattr(self.model,'all_CTparameters'):
1268 additional_params = self.get_additional_CTparameters()
1269
1270 self.analyze_parameters(additional_params = additional_params)
1271 self.analyze_couplings(additional_couplings = additional_couplings)
1272
1273
1274 if hasattr(self.model,'all_CTparameters'):
1275 self.revert_CTCoupling_modifications()
1276
1277 return self.params, self.couplings
1278
1280 """ Finally revert the possible modifications done by treat_couplings()
1281 in UFOMG5Converter which were useful for the add_CTinteraction() in
1282 particular. This modification consisted in expanding the value of a
1283 CTCoupling which consisted in an expression in terms of a CTParam to
1284 its corresponding dictionary (e.g
1285 CTCoupling.value = 2*CTParam ->
1286 CTCoupling.value = {-1: 2*CTParam_1EPS_, 0: 2*CTParam_FIN_}
1287 for example if CTParam had a non-zero finite and single pole."""
1288
1289 for coupl in self.model.all_couplings:
1290 if hasattr(coupl,'old_value'):
1291 coupl.value = coupl.old_value
1292 del(coupl.old_value)
1293
1295 """ For each CTparameter split it into spimple parameter for each pole
1296 and the finite part if not zero."""
1297
1298 additional_params = []
1299 for CTparam in self.model.all_CTparameters:
1300 for pole in range(3):
1301 if CTparam.pole(pole) != 'ZERO':
1302 CTparam_piece = copy.copy(CTparam)
1303 CTparam_piece.name = '%s_%s_'%(CTparam.name,pole_dict[-pole])
1304 CTparam_piece.nature = 'internal'
1305 CTparam_piece.type = CTparam.type
1306 CTparam_piece.value = CTparam.pole(pole)
1307 CTparam_piece.texname = '%s_{%s}'%\
1308 (CTparam.texname,pole_dict[-pole])
1309 additional_params.append(CTparam_piece)
1310 return additional_params
1311
1313 """ separate the parameters needed to be recomputed events by events and
1314 the others"""
1315
1316
1317
1318 present_aEWM1 = any(param.name == 'aEWM1' for param in
1319 self.model.all_parameters if param.nature == 'external')
1320
1321 if not present_aEWM1:
1322 self.track_dependant = ['aS','Gf','MU_R']
1323
1324 for param in self.model.all_parameters+additional_params:
1325 if param.nature == 'external':
1326 parameter = base_objects.ParamCardVariable(param.name, param.value, \
1327 param.lhablock, param.lhacode)
1328
1329 else:
1330 expr = self.shorten_expr(param.value)
1331 depend_on = self.find_dependencies(expr)
1332 parameter = base_objects.ModelVariable(param.name, expr, param.type, depend_on)
1333
1334 self.add_parameter(parameter)
1335
1337 """ add consistently the parameter in params and all_expr.
1338 avoid duplication """
1339
1340 assert isinstance(parameter, base_objects.ModelVariable)
1341
1342 if parameter.name in self.all_expr:
1343 return
1344
1345 self.all_expr[parameter.name] = parameter
1346 try:
1347 self.params[parameter.depend].append(parameter)
1348 except:
1349 self.params[parameter.depend] = [parameter]
1350
1352 """ add consistently the coupling in couplings and all_expr.
1353 avoid duplication """
1354
1355 assert isinstance(coupling, base_objects.ModelVariable)
1356
1357 if coupling.name in self.all_expr:
1358 return
1359 self.all_expr[coupling.value] = coupling
1360 try:
1361 self.coupling[coupling.depend].append(coupling)
1362 except:
1363 self.coupling[coupling.depend] = [coupling]
1364
1366 """creates the shortcut for all special function/parameter
1367 separate the couplings dependent of track variables of the others"""
1368
1369
1370
1371 if self.perturbation_couplings:
1372 couplings_list=[]
1373 for coupling in self.model.all_couplings + additional_couplings:
1374 if not isinstance(coupling.value,dict):
1375 couplings_list.append(coupling)
1376 else:
1377 for poleOrder in range(0,3):
1378 if coupling.pole(poleOrder)!='ZERO':
1379 newCoupling=copy.copy(coupling)
1380 if poleOrder!=0:
1381 newCoupling.name += "_%deps"%poleOrder
1382 newCoupling.value=coupling.pole(poleOrder)
1383
1384
1385
1386
1387
1388
1389
1390 couplings_list.append(newCoupling)
1391 else:
1392 couplings_list = self.model.all_couplings + additional_couplings
1393 couplings_list = [c for c in couplings_list if not isinstance(c.value, dict)]
1394
1395 for coupling in couplings_list:
1396
1397 expr = self.shorten_expr(coupling.value)
1398 depend_on = self.find_dependencies(expr)
1399 parameter = base_objects.ModelVariable(coupling.name, expr, 'complex', depend_on)
1400
1401 try:
1402 self.couplings[depend_on].append(parameter)
1403 except KeyError:
1404 self.couplings[depend_on] = [parameter]
1405 self.all_expr[coupling.value] = parameter
1406
1408 """check if an expression should be evaluated points by points or not
1409 """
1410 depend_on = set()
1411
1412
1413
1414
1415
1416
1417
1418 expr = self.separator.split(expr)
1419
1420
1421 for subexpr in expr:
1422 if subexpr in self.track_dependant:
1423 depend_on.add(subexpr)
1424
1425 elif subexpr in self.all_expr and self.all_expr[subexpr].depend:
1426 [depend_on.add(value) for value in self.all_expr[subexpr].depend
1427 if self.all_expr[subexpr].depend != ('external',)]
1428 if depend_on:
1429 return tuple(depend_on)
1430 else:
1431 return tuple()
1432
1433
1446
1447
1449 """add the short expression, and return the nice string associate"""
1450
1451 float_real = float(eval(matchobj.group('real')))
1452 float_imag = float(eval(matchobj.group('imag')))
1453 if float_real == 0 and float_imag ==1:
1454 new_param = base_objects.ModelVariable('complexi', 'complex(0,1)', 'complex')
1455 self.add_parameter(new_param)
1456 return 'complexi'
1457 else:
1458 return 'complex(%s, %s)' % (matchobj.group('real'), matchobj.group('imag'))
1459
1460
1462 """add the short expression, and return the nice string associate"""
1463
1464 expr = matchobj.group('expr')
1465 exponent = matchobj.group('expo')
1466 new_exponent = exponent.replace('.','_').replace('+','').replace('-','_m_')
1467 output = '%s__exp__%s' % (expr, new_exponent)
1468 old_expr = '%s**%s' % (expr,exponent)
1469
1470 if expr.startswith('cmath'):
1471 return old_expr
1472
1473 if expr.isdigit():
1474 output = 'nb__' + output
1475 new_param = base_objects.ModelVariable(output, old_expr,'real')
1476 else:
1477 depend_on = self.find_dependencies(expr)
1478 type = self.search_type(expr)
1479 new_param = base_objects.ModelVariable(output, old_expr, type, depend_on)
1480 self.add_parameter(new_param)
1481 return output
1482
1499
1512
1513
1514
1516 """return the type associate to the expression if define"""
1517
1518 try:
1519 return self.all_expr[expr].type
1520 except:
1521 return 'complex'
1522
1524 """ A class for restricting a model for a given param_card.
1525 rules applied:
1526 - Vertex with zero couplings are throw away
1527 - external parameter with zero/one input are changed into internal parameter.
1528 - identical coupling/mass/width are replace in the model by a unique one
1529 """
1530
1537
1538 - def restrict_model(self, param_card, rm_parameter=True, keep_external=False,
1539 complex_mass_scheme=None):
1608
1609
1611 """ create a dict couplings_name -> vertex or (particle, counterterm_key) """
1612
1613 self.coupling_pos = {}
1614 for vertex in self['interactions']:
1615 for key, coupling in vertex['couplings'].items():
1616 if coupling in self.coupling_pos:
1617 if vertex not in self.coupling_pos[coupling]:
1618 self.coupling_pos[coupling].append(vertex)
1619 else:
1620 self.coupling_pos[coupling] = [vertex]
1621
1622 for particle in self['particles']:
1623 for key, coupling_dict in particle['counterterm'].items():
1624 for LaurentOrder, coupling in coupling_dict.items():
1625 if coupling in self.coupling_pos:
1626 if (particle,key) not in self.coupling_pos[coupling]:
1627 self.coupling_pos[coupling].append((particle,key))
1628 else:
1629 self.coupling_pos[coupling] = [(particle,key)]
1630
1631 return self.coupling_pos
1632
1634 """return a list with the name of all vanishing couplings"""
1635
1636 dict_value_coupling = {}
1637 iden_key = set()
1638 zero_coupling = []
1639 iden_coupling = []
1640
1641 for name, value in self['coupling_dict'].items():
1642 if value == 0:
1643 zero_coupling.append(name)
1644 continue
1645 elif not strict_zero and abs(value) < 1e-13:
1646 logger.debug('coupling with small value %s: %s treated as zero' %
1647 (name, value))
1648 zero_coupling.append(name)
1649 elif not strict_zero and abs(value) < 1e-10:
1650 return self.detect_identical_couplings(strict_zero=True)
1651
1652
1653 if value in dict_value_coupling:
1654 iden_key.add(value)
1655 dict_value_coupling[value].append(name)
1656 else:
1657 dict_value_coupling[value] = [name]
1658
1659 for key in iden_key:
1660 iden_coupling.append(dict_value_coupling[key])
1661
1662 return zero_coupling, iden_coupling
1663
1664
1666 """ return the list of (name of) parameter which are zero """
1667
1668 null_parameters = []
1669 one_parameters = []
1670 for name, value in self['parameter_dict'].items():
1671 if value == 0 and name != 'ZERO':
1672 null_parameters.append(name)
1673 elif value == 1:
1674 one_parameters.append(name)
1675
1676 return null_parameters, one_parameters
1677
1680 """ Apply the conditional statement simplifications for parameters and
1681 couplings detected by 'simplify_conditional_statements'.
1682 modified_params (modified_couplings) are list of tuples (a,b) with a
1683 parameter (resp. coupling) instance and b is the simplified expression."""
1684
1685 if modified_params:
1686 logger.debug("Conditional expressions are simplified for parameters:")
1687 logger.debug(",".join("%s"%param[0].name for param in modified_params))
1688 for param, new_expr in modified_params:
1689 param.expr = new_expr
1690
1691 if modified_couplings:
1692 logger.debug("Conditional expressions are simplified for couplings:")
1693 logger.debug(",".join("%s"%coupl[0].name for coupl in modified_couplings))
1694 for coupl, new_expr in modified_couplings:
1695 coupl.expr = new_expr
1696
1699 """ Simplifies the 'if' statements in the pythonic UFO expressions
1700 of parameters using the default variables specified in the restrict card.
1701 It returns a list of objects (parameters or couplings) and the new
1702 expression that they should take. Model definitions include all definitons
1703 of the model functions and parameters."""
1704
1705 param_modifications = []
1706 coupl_modifications = []
1707 ifparser = parsers.UFOExpressionParserPythonIF(model_definitions)
1708
1709 start_param = time.time()
1710 if 'parameters' in objects:
1711 for dependences, param_list in self['parameters'].items():
1712 if 'external' in dependences:
1713 continue
1714 for param in param_list:
1715 new_expr, n_changes = ifparser.parse(param.expr)
1716 if n_changes > 0:
1717 param_modifications.append((param, new_expr))
1718
1719 end_param = time.time()
1720
1721 if 'couplings' in objects:
1722 for dependences, coupl_list in self['couplings'].items():
1723 for coupl in coupl_list:
1724 new_expr, n_changes = ifparser.parse(coupl.expr)
1725 if n_changes > 0:
1726 coupl_modifications.append((coupl, new_expr))
1727
1728 end_coupl = time.time()
1729
1730 tot_param_time = end_param-start_param
1731 tot_coupl_time = end_coupl-end_param
1732 if tot_param_time>5.0:
1733 logger.debug("Simplification of conditional statements"+\
1734 " in parameter expressions done in %s."%misc.format_time(tot_param_time))
1735 if tot_coupl_time>5.0:
1736 logger.debug("Simplification of conditional statements"+\
1737 " in couplings expressions done in %s."%misc.format_time(tot_coupl_time))
1738
1739 return param_modifications, coupl_modifications
1740
1742 """ return the list of tuple of name of parameter with the same
1743 input value """
1744
1745
1746 external_parameters = self['parameters'][('external',)]
1747
1748
1749 block_value_to_var={}
1750 mult_param = set([])
1751
1752
1753
1754 for param in external_parameters[:]:
1755 value = self['parameter_dict'][param.name]
1756 if value in [0,1,0.000001e-99,9.999999e-1]:
1757 continue
1758 if param.lhablock.lower() == 'decay':
1759 continue
1760
1761 key = (param.lhablock, value)
1762 mkey = (param.lhablock, -value)
1763 if key in block_value_to_var:
1764 block_value_to_var[key].append((param,1))
1765 mult_param.add(key)
1766 elif mkey in block_value_to_var:
1767 block_value_to_var[mkey].append((param,-1))
1768 mult_param.add(mkey)
1769 else:
1770 block_value_to_var[key] = [(param,1)]
1771
1772 output=[]
1773 for key in mult_param:
1774 output.append(block_value_to_var[key])
1775
1776 return output
1777
1778
1780 """merge the identical couplings in the interactions and particle
1781 counterterms"""
1782
1783
1784 logger_mod.debug(' Fuse the Following coupling (they have the same value): %s '% \
1785 ', '.join([obj for obj in couplings]))
1786
1787 main = couplings[0]
1788 self.del_coup += couplings[1:]
1789
1790 for coupling in couplings[1:]:
1791
1792 if coupling not in self.coupling_pos:
1793 continue
1794
1795 vertices = [ vert for vert in self.coupling_pos[coupling] if
1796 isinstance(vert, base_objects.Interaction)]
1797 for vertex in vertices:
1798 for key, value in vertex['couplings'].items():
1799 if value == coupling:
1800 vertex['couplings'][key] = main
1801
1802
1803 particles_ct = [ pct for pct in self.coupling_pos[coupling] if
1804 isinstance(pct, tuple)]
1805 for pct in particles_ct:
1806 for key, value in pct[0]['counterterm'][pct[1]].items():
1807 if value == coupling:
1808 pct[0]['counterterm'][pct[1]][key] = main
1809
1810
1812 """ merge the identical parameters given in argument.
1813 keep external force to keep the param_card untouched (up to comment)"""
1814
1815 logger_mod.debug('Parameters set to identical values: %s '% \
1816 ', '.join(['%s*%s' % (f, obj.name.replace('mdl_','')) for (obj,f) in parameters]))
1817
1818
1819 external_parameters = self['parameters'][('external',)]
1820 for i, (obj, factor) in enumerate(parameters):
1821
1822 if i == 0:
1823 obj.info = 'set of param :' + \
1824 ', '.join([str(f)+'*'+param.name.replace('mdl_','')
1825 for (param, f) in parameters])
1826 expr = obj.name
1827 continue
1828
1829 if factor ==1:
1830 self.rule_card.add_identical(obj.lhablock.lower(), obj.lhacode,
1831 parameters[0][0].lhacode )
1832 else:
1833 self.rule_card.add_opposite(obj.lhablock.lower(), obj.lhacode,
1834 parameters[0][0].lhacode )
1835 obj_name = obj.name
1836
1837 if not keep_external:
1838 external_parameters.remove(obj)
1839 elif obj.lhablock.upper() in ['MASS','DECAY']:
1840 external_parameters.remove(obj)
1841 else:
1842 obj.name = ''
1843 obj.info = 'MG5 will not use this value use instead %s*%s' %(factor,expr)
1844
1845 new_param = base_objects.ModelVariable(obj_name, '%s*%s' %(factor, expr), 'real')
1846 self['parameters'][()].insert(0, new_param)
1847
1848
1849
1850 if parameters[0][0].lhablock in ['MASS','DECAY']:
1851 new_name = parameters[0][0].name
1852 if parameters[0][0].lhablock == 'MASS':
1853 arg = 'mass'
1854 else:
1855 arg = 'width'
1856 change_name = [p.name for (p,f) in parameters[1:]]
1857 [p.set(arg, new_name) for p in self['particle_dict'].values()
1858 if p[arg] in change_name]
1859
1861 """ remove the interactions and particle counterterms
1862 associated to couplings"""
1863
1864
1865 mod_vertex = []
1866 mod_particle_ct = []
1867 for coup in zero_couplings:
1868
1869 if coup not in self.coupling_pos:
1870 continue
1871
1872
1873
1874 vertices = [ vert for vert in self.coupling_pos[coup] if
1875 isinstance(vert, base_objects.Interaction) ]
1876 for vertex in vertices:
1877 modify = False
1878 for key, coupling in vertex['couplings'].items():
1879 if coupling in zero_couplings:
1880 modify=True
1881 del vertex['couplings'][key]
1882 if modify:
1883 mod_vertex.append(vertex)
1884
1885
1886 particles_ct = [ pct for pct in self.coupling_pos[coup] if
1887 isinstance(pct, tuple)]
1888 for pct in particles_ct:
1889 modify = False
1890 for key, coupling in pct[0]['counterterm'][pct[1]].items():
1891 if coupling in zero_couplings:
1892 modify=True
1893 del pct[0]['counterterm'][pct[1]][key]
1894 if modify:
1895 mod_particle_ct.append(pct)
1896
1897
1898 for vertex in mod_vertex:
1899 part_name = [part['name'] for part in vertex['particles']]
1900 orders = ['%s=%s' % (order,value) for order,value in vertex['orders'].items()]
1901
1902 if not vertex['couplings']:
1903 logger_mod.debug('remove interactions: %s at order: %s' % \
1904 (' '.join(part_name),', '.join(orders)))
1905 self['interactions'].remove(vertex)
1906 else:
1907 logger_mod.debug('modify interactions: %s at order: %s' % \
1908 (' '.join(part_name),', '.join(orders)))
1909
1910
1911 for pct in mod_particle_ct:
1912 part_name = pct[0]['name']
1913 order = pct[1][0]
1914 loop_parts = ','.join(['('+','.join([\
1915 self.get_particle(p)['name'] for p in part])+')' \
1916 for part in pct[1][1]])
1917
1918 if not pct[0]['counterterm'][pct[1]]:
1919 logger_mod.debug('remove counterterm of particle %s'%part_name+\
1920 ' with loop particles (%s)'%loop_parts+\
1921 ' perturbing order %s'%order)
1922 del pct[0]['counterterm'][pct[1]]
1923 else:
1924 logger_mod.debug('Modify counterterm of particle %s'%part_name+\
1925 ' with loop particles (%s)'%loop_parts+\
1926 ' perturbing order %s'%order)
1927
1928 return
1929
1931
1932 for name, data in self['couplings'].items():
1933 for coupling in data[:]:
1934 if coupling.name in couplings:
1935 data.remove(coupling)
1936
1937
1938 - def fix_parameter_values(self, zero_parameters, one_parameters,
1939 simplify=True, keep_external=False):
1940 """ Remove all instance of the parameters in the model and replace it by
1941 zero when needed."""
1942
1943
1944
1945 for particle in self['particles']:
1946 if particle['mass'] in zero_parameters:
1947 particle['mass'] = 'ZERO'
1948 if particle['width'] in zero_parameters:
1949 particle['width'] = 'ZERO'
1950 if particle['width'] in one_parameters:
1951 one_parameters.remove(particle['width'])
1952
1953 for pdg, particle in self['particle_dict'].items():
1954 if particle['mass'] in zero_parameters:
1955 particle['mass'] = 'ZERO'
1956 if particle['width'] in zero_parameters:
1957 particle['width'] = 'ZERO'
1958
1959
1960
1961 external_parameters = self['parameters'][('external',)]
1962 for param in external_parameters[:]:
1963 value = self['parameter_dict'][param.name]
1964 block = param.lhablock.lower()
1965 if value == 0:
1966 self.rule_card.add_zero(block, param.lhacode)
1967 elif value == 1:
1968 self.rule_card.add_one(block, param.lhacode)
1969
1970 special_parameters = zero_parameters + one_parameters
1971
1972
1973
1974 if simplify:
1975
1976 re_str = '|'.join(special_parameters)
1977 if len(re_str) > 25000:
1978 split = len(special_parameters) // 2
1979 re_str = ['|'.join(special_parameters[:split]),
1980 '|'.join(special_parameters[split:])]
1981 else:
1982 re_str = [ re_str ]
1983 used = set()
1984 for expr in re_str:
1985 re_pat = re.compile(r'''\b(%s)\b''' % expr)
1986
1987 for name, coupling_list in self['couplings'].items():
1988 for coupling in coupling_list:
1989 for use in re_pat.findall(coupling.expr):
1990 used.add(use)
1991 else:
1992 used = set([i for i in special_parameters if i])
1993
1994
1995 re_str = '|'.join([param for param in special_parameters if param not in used])
1996 if len(re_str) > 25000:
1997 split = len(special_parameters) // 2
1998 re_str = ['|'.join(special_parameters[:split]),
1999 '|'.join(special_parameters[split:])]
2000 else:
2001 re_str = [ re_str ]
2002 for expr in re_str:
2003 re_pat = re.compile(r'''\b(%s)\b''' % expr)
2004
2005 param_info = {}
2006
2007 for dep, param_list in self['parameters'].items():
2008 for tag, parameter in enumerate(param_list):
2009
2010 if parameter.name in special_parameters:
2011 param_info[parameter.name]= {'dep': dep, 'tag': tag,
2012 'obj': parameter}
2013 continue
2014
2015
2016 if isinstance(parameter, base_objects.ParamCardVariable):
2017 continue
2018
2019 if simplify:
2020 for use in re_pat.findall(parameter.expr):
2021 used.add(use)
2022
2023
2024 for param in used:
2025 if not param:
2026 continue
2027 data = self['parameters'][param_info[param]['dep']]
2028 data.remove(param_info[param]['obj'])
2029 tag = param_info[param]['tag']
2030 data = self['parameters'][()]
2031 if param in zero_parameters:
2032 data.insert(0, base_objects.ModelVariable(param, '0.0', 'real'))
2033 else:
2034 data.insert(0, base_objects.ModelVariable(param, '1.0', 'real'))
2035
2036
2037 for param in special_parameters:
2038
2039 if param in used or \
2040 (keep_external and param_info[param]['dep'] == ('external',)):
2041 logger_mod.debug('fix parameter value: %s' % param)
2042 continue
2043 logger_mod.debug('remove parameters: %s' % (param))
2044 data = self['parameters'][param_info[param]['dep']]
2045 data.remove(param_info[param]['obj'])
2046