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