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