1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """ How to import a UFO model to the MG5 format """
16
17
18 import fractions
19 import logging
20 import os
21 import re
22 import sys
23 import time
24 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 self.interactions:
535 self.optimise_interaction(interaction)
536
537
538 self.model.set('conserved_charge', self.conservecharge)
539
540
541
542
543 all_orders = []
544 try:
545 all_orders = self.ufomodel.all_orders
546 except AttributeError:
547 if self.perturbation_couplings:
548 raise MadGraph5Error, "The loop model MG5 attemps to import does not specify the attribute 'all_order'."
549 else:
550 pass
551
552 hierarchy={}
553 try:
554 for order in all_orders:
555 hierarchy[order.name]=order.hierarchy
556 except AttributeError:
557 if self.perturbation_couplings:
558 raise MadGraph5Error, 'The loop model MG5 attemps to import does not specify an order hierarchy.'
559 else:
560 pass
561 else:
562 self.model.set('order_hierarchy', hierarchy)
563
564
565 expansion_order={}
566
567 coupling_order_counterterms={}
568 try:
569 for order in all_orders:
570 expansion_order[order.name]=order.expansion_order
571 coupling_order_counterterms[order.name]=order.expansion_order
572 except AttributeError:
573 if self.perturbation_couplings:
574 raise MadGraph5Error, 'The loop model MG5 attemps to import does not specify an expansion_order for all coupling orders.'
575 else:
576 pass
577 else:
578 self.model.set('expansion_order', expansion_order)
579 self.model.set('expansion_order', expansion_order)
580
581
582 del self.checked_lor
583
584 return self.model
585
587
588
589
590 to_lor = {}
591 for (color, lor), coup in interaction['couplings'].items():
592 key = (color, coup)
593 if key in to_lor:
594 to_lor[key].append(lor)
595 else:
596 to_lor[key] = [lor]
597
598 nb_reduce = []
599 optimize = False
600 for key in to_lor:
601 if len(to_lor[key]) >1:
602 nb_reduce.append(len(to_lor[key])-1)
603 optimize = True
604
605 if not optimize:
606 return
607
608 if not hasattr(self, 'defined_lorentz_expr'):
609 self.defined_lorentz_expr = {}
610 self.lorentz_info = {}
611 self.lorentz_combine = {}
612 for lor in self.model['lorentz']:
613 self.defined_lorentz_expr[lor.get('structure')] = lor.get('name')
614 self.lorentz_info[lor.get('name')] = lor
615
616 for key in to_lor:
617 if len(to_lor[key]) == 1:
618 continue
619 names = [interaction['lorentz'][i] for i in to_lor[key]]
620 names.sort()
621
622
623 if tuple(names) in self.lorentz_combine:
624
625 new_name = self.lorentz_combine[tuple(names)]
626 else:
627 new_name = self.add_merge_lorentz(names)
628
629
630 color, coup = key
631 to_remove = [(color, lor) for lor in to_lor[key]]
632 for rm in to_remove:
633 del interaction['couplings'][rm]
634
635
636 if new_name not in [l for l in interaction.get('lorentz')]:
637 interaction.get('lorentz').append(new_name)
638
639
640 new_l = interaction.get('lorentz').index(new_name)
641
642 interaction['couplings'][(color, new_l)] = coup
643
644
646 """add a lorentz structure which is the sume of the list given above"""
647
648
649
650 ii = len(names[0])
651 while ii>0:
652 if not all(n.startswith(names[0][:ii]) for n in names[1:]):
653 ii -=1
654 else:
655 base_name = names[0][:ii]
656 break
657 else:
658 base_name = 'LMER'
659
660 i = 1
661 while '%s%s' %(base_name, i) in self.lorentz_info:
662 i +=1
663 new_name = '%s%s' %(base_name, i)
664 self.lorentz_combine[tuple(names)] = new_name
665 assert new_name not in self.lorentz_info
666 assert new_name not in [l.name for l in self.model['lorentz']]
667
668
669 new_struct = ' + '.join([self.lorentz_info[n].get('structure') for n in names])
670 spins = self.lorentz_info[names[0]].get('spins')
671 new_lor = self.add_lorentz(new_name, spins, new_struct)
672 self.lorentz_info[new_name] = new_lor
673
674 return new_name
675
676
677
678
679
680
681
682 - def add_particle(self, particle_info):
683 """ convert and add a particle in the particle list """
684
685 loop_particles = [[[]]]
686 counterterms = {}
687
688
689
690 pdg = particle_info.pdg_code
691 if pdg in self.incoming or (pdg not in self.outcoming and pdg <0):
692 return
693
694
695 if not self.perturbation_couplings and particle_info.spin < 0:
696 return
697
698 if (aloha.unitary_gauge and 0 in self.model['gauge']) \
699 or (1 not in self.model['gauge']):
700
701
702 if hasattr(particle_info, 'GoldstoneBoson') and particle_info.GoldstoneBoson:
703 return
704 elif hasattr(particle_info, 'goldstone') and particle_info.goldstone:
705 return
706
707 particle = base_objects.Particle()
708
709
710 if (hasattr(particle_info, 'GoldstoneBoson') and particle_info.GoldstoneBoson) \
711 or (hasattr(particle_info, 'goldstoneboson') and particle_info.goldstoneboson):
712 particle.set('type', 'goldstone')
713 elif hasattr(particle_info, 'goldstone') and particle_info.goldstone:
714 particle.set('type', 'goldstone')
715
716 nb_property = 0
717
718 for key,value in particle_info.__dict__.items():
719
720 if key in base_objects.Particle.sorted_keys and not key=='counterterm':
721 nb_property +=1
722 if key in ['name', 'antiname']:
723 if not self.model['case_sensitive']:
724 particle.set(key, value.lower())
725 else:
726 particle.set(key, value)
727 elif key == 'charge':
728 particle.set(key, float(value))
729 elif key in ['mass','width']:
730 particle.set(key, str(value))
731 elif key == 'spin':
732
733
734 particle.set(key,abs(value))
735 if value<0:
736 particle.set('type','ghost')
737 elif key == 'propagating':
738 if not value:
739 particle.set('line', None)
740 elif key == 'line':
741 if particle.get('line') is None:
742 pass
743 else:
744 particle.set('line', value)
745 elif key == 'propagator':
746 if value:
747 if aloha.unitary_gauge:
748 particle.set(key, str(value[0]))
749 else:
750 particle.set(key, str(value[1]))
751 else:
752 particle.set(key, '')
753 else:
754 particle.set(key, value)
755 elif key == 'loop_particles':
756 loop_particles = value
757 elif key == 'counterterm':
758 counterterms = value
759 elif key.lower() not in ('ghostnumber','selfconjugate','goldstone',
760 'goldstoneboson','partial_widths',
761 'texname', 'antitexname', 'propagating', 'ghost'
762 ):
763
764 self.conservecharge.add(key)
765 particle.set(key,value, force=True)
766
767 if not hasattr(particle_info, 'propagator'):
768 nb_property += 1
769 if particle.get('spin') >= 3:
770 if particle.get('mass').lower() == 'zero':
771 particle.set('propagator', 0)
772 elif particle.get('spin') == 3 and not aloha.unitary_gauge:
773 particle.set('propagator', 0)
774
775 assert(10 == nb_property)
776
777
778 if particle_info.name == particle_info.antiname:
779 particle.set('self_antipart', True)
780
781
782
783 if not self.perturbation_couplings or counterterms=={}:
784 self.particles.append(particle)
785 return
786
787
788
789
790
791
792 particle_counterterms = {}
793 for key, counterterm in counterterms.items():
794
795 if len([1 for k in key[:-1] if k==1])==1 and \
796 not any(k>1 for k in key[:-1]):
797 newParticleCountertermKey=[None,\
798
799
800
801
802
803 tuple([tuple(loop_parts) for\
804 loop_parts in loop_particles[key[-1]]])]
805 for i, order in enumerate(self.ufomodel.all_orders[:-1]):
806 if key[i]==1:
807 newParticleCountertermKey[0]=order.name
808 newCouplingName='UVWfct_'+particle_info.name+'_'+str(key[-1])
809 particle_counterterms[tuple(newParticleCountertermKey)]=\
810 dict([(key,newCouplingName+('' if key==0 else '_'+str(-key)+'eps'))\
811 for key in counterterm])
812
813
814 self.ufomodel.object_library.Coupling(\
815 name = newCouplingName,
816 value = counterterm,
817 order = {newParticleCountertermKey[0]:2})
818 self.wavefunction_CT_couplings.append(self.ufomodel.all_couplings.pop())
819
820 particle.set('counterterm',particle_counterterms)
821 self.particles.append(particle)
822 return
823
825 """ This function scan each coupling to see if it contains a CT parameter.
826 when it does, it changes its value to a dictionary with the CT parameter
827 changed to a new parameter for each pole and finite part. For instance,
828 the following coupling:
829 coupling.value = '2*(myCTParam1 + myParam*(myCTParam2 + myCTParam3)'
830 with CTparameters
831 myCTParam1 = {0: Something, -1: SomethingElse}
832 myCTParam2 = {0: OtherSomething }
833 myCTParam3 = {-1: YetOtherSomething }
834 would be turned into
835 coupling.value = {0: '2*(myCTParam1_FIN_ + myParam*(myCTParam2_FIN_ + ZERO)'
836 -1: '2*(myCTParam1_EPS_ + myParam*(ZERO + myCTParam2_EPS_)'}
837
838 all_CTParameter is the list of all CTParameters in the model"""
839
840
841
842
843
844
845 CTparameter_patterns = {}
846 zero_substitution = lambda matchedObj: matchedObj.group('first')+\
847 'ZERO'+matchedObj.group('second')
848 def function_factory(arg):
849 return lambda matchedObj: \
850 matchedObj.group('first')+arg+matchedObj.group('second')
851 for CTparam in all_CTparameters:
852 pattern_finder = re.compile(r"(?P<first>\A|\*|\+|\-|\(|\s)(?P<name>"+
853 CTparam.name+r")(?P<second>\Z|\*|\+|\-|\)|/|\\|\s)")
854
855 sub_functions = [None if CTparam.pole(pole)=='ZERO' else
856 function_factory('%s_%s_'%(CTparam.name,pole_dict[-pole]))
857 for pole in range(3)]
858 CTparameter_patterns[CTparam.name] = (pattern_finder,sub_functions)
859
860 times_zero = re.compile('\*\s*-?ZERO')
861 zero_times = re.compile('ZERO\s*(\*|\/)')
862 def is_expr_zero(expresson):
863 """ Checks whether a single term (involving only the operations
864 * or / is zero. """
865 for term in expresson.split('-'):
866 for t in term.split('+'):
867 t = t.strip()
868 if t in ['ZERO','']:
869 continue
870 if not (times_zero.search(t) or zero_times.search(t)):
871 return False
872 return True
873
874 def find_parenthesis(expr):
875 end = expr.find(')')
876 if end == -1:
877 return None
878 start = expr.rfind('(',0,end+1)
879 if start ==-1:
880 raise InvalidModel,\
881 'Parenthesis of expression %s are malformed'%expr
882 return [expr[:start],expr[start+1:end],expr[end+1:]]
883
884 start_parenthesis = re.compile(r".*\s*[\+\-\*\/\)\(]\s*$")
885
886 def is_value_zero(value):
887 """Check whether an expression like ((A+B)*ZERO+C)*ZERO is zero.
888 Only +,-,/,* operations are allowed and 'ZERO' is a tag for an
889 analytically zero quantity."""
890
891 curr_value = value
892 parenthesis = find_parenthesis(curr_value)
893 while parenthesis:
894
895 if parenthesis[0].endswith('complexconjugate'):
896
897 parenthesis[0] = parenthesis[0][:-16]
898 if parenthesis[0]=='' or re.match(start_parenthesis,
899 parenthesis[0]):
900 if is_value_zero(parenthesis[1]):
901 new_parenthesis = 'ZERO'
902 else:
903 new_parenthesis = 'PARENTHESIS'
904 else:
905 new_parenthesis = '_FUNCTIONARGS'
906 curr_value = parenthesis[0]+new_parenthesis+parenthesis[2]
907 parenthesis = find_parenthesis(curr_value)
908 return is_expr_zero(curr_value)
909
910 def CTCoupling_pole(CTCoupling, pole):
911 """Compute the pole of the CTCoupling in two cases:
912 a) Its value is a dictionary, then just return the corresponding
913 entry in the dictionary.
914 b) It is expressed in terms of CTParameters which are themselves
915 dictionary so we want to substitute their expression to get
916 the value of the pole. In the current implementation, this is
917 just to see if the pole is zero or not.
918 """
919
920 if isinstance(CTCoupling.value,dict):
921 if -pole in CTCoupling.value.keys():
922 return CTCoupling.value[-pole], [], 0
923 else:
924 return 'ZERO', [], 0
925
926 new_expression = CTCoupling.value
927 CTparamNames = []
928 n_CTparams = 0
929 for paramname, value in CTparameter_patterns.items():
930 pattern = value[0]
931
932
933 if not re.search(pattern,new_expression):
934 continue
935 n_CTparams += 1
936
937
938 if not value[1][pole] is None:
939 CTparamNames.append('%s_%s_'%(paramname,pole_dict[-pole]))
940
941 substitute_function = zero_substitution if \
942 value[1][pole] is None else value[1][pole]
943 new_expression = pattern.sub(substitute_function,new_expression)
944
945
946
947 if pole!=0 and n_CTparams==0:
948 return 'ZERO', [], n_CTparams
949
950
951
952
953
954
955 if n_CTparams > 0 and is_value_zero(new_expression):
956 return 'ZERO', [], n_CTparams
957 else:
958 return new_expression, CTparamNames, n_CTparams
959
960
961 for coupl in couplings:
962 new_value = {}
963 for pole in range(0,3):
964 expression, CTparamNames, n_CTparams = CTCoupling_pole(coupl, pole)
965
966 if n_CTparams == 0:
967 break
968 elif expression!='ZERO':
969 new_value[-pole] = expression
970 couplname = coupl.name
971 if pole!=0:
972 couplname += "_%deps"%pole
973
974
975
976
977 if hasattr(self.model, 'map_CTcoup_CTparam'):
978 self.model.map_CTcoup_CTparam[couplname] = CTparamNames
979
980
981
982
983
984
985
986
987 if new_value:
988 coupl.old_value = coupl.value
989 coupl.value = new_value
990
992 """ Split this interaction in order to call add_interaction for
993 interactions for each element of the loop_particles list. Also it
994 is necessary to unfold here the contributions to the different laurent
995 expansion orders of the couplings."""
996
997
998 interaction_info=copy.copy(interaction)
999
1000 intType=''
1001 if interaction_info.type not in ['UV','UVloop','UVtree','UVmass','R2']:
1002 raise MadGraph5Error, 'MG5 only supports the following types of'+\
1003 ' vertices, R2, UV and UVmass. %s is not in this list.'%interaction_info.type
1004 else:
1005 intType=interaction_info.type
1006
1007 if interaction_info.type=='UV':
1008 if len(interaction_info.particles)==2 and interaction_info.\
1009 particles[0].name==interaction_info.particles[1].name:
1010 intType='UVmass'
1011 else:
1012 intType='UVloop'
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025 order_to_interactions= {}
1026
1027
1028
1029
1030
1031 for key, couplings in interaction_info.couplings.items():
1032 if not isinstance(couplings, list):
1033 couplings = [couplings]
1034 for coupling in couplings:
1035 order = tuple(coupling.order.items())
1036 if order not in order_to_interactions:
1037 order_to_interactions[order] = [
1038 [{} for j in range(0,3)] for i in \
1039 range(0,max(1,len(interaction_info.loop_particles)))]
1040 new_couplings = order_to_interactions[order]
1041 else:
1042 new_couplings = order_to_interactions[order]
1043
1044 for poleOrder in range(0,3):
1045 expression = coupling.pole(poleOrder)
1046 if expression!='ZERO':
1047 if poleOrder==2:
1048 raise InvalidModel, """
1049 The CT coupling %s was found with a contribution to the double pole.
1050 This is either an error in the model or a parsing error in the function 'is_value_zero'.
1051 The expression of the non-zero double pole coupling is:
1052 %s
1053 """%(coupling.name,str(coupling.value))
1054
1055
1056
1057 newCoupling = copy.copy(coupling)
1058 if poleOrder!=0:
1059 newCoupling.name=newCoupling.name+"_"+str(poleOrder)+"eps"
1060 newCoupling.value = expression
1061
1062
1063
1064
1065
1066
1067
1068 new_couplings[key[2]][poleOrder][(key[0],key[1])] = newCoupling
1069
1070 for new_couplings in order_to_interactions.values():
1071
1072 for i, all_couplings in enumerate(new_couplings):
1073 loop_particles=[[]]
1074 if len(interaction_info.loop_particles)>0:
1075 loop_particles=[[part.pdg_code for part in loop_parts] \
1076 for loop_parts in interaction_info.loop_particles[i]]
1077 for poleOrder in range(0,3):
1078 if all_couplings[poleOrder]!={}:
1079 interaction_info.couplings=all_couplings[poleOrder]
1080 self.add_interaction(interaction_info, color_info,\
1081 (intType if poleOrder==0 else (intType+str(poleOrder)+\
1082 'eps')),loop_particles)
1083
1085 """find which color are in the 3/3bar states"""
1086
1087
1088
1089
1090 if not output:
1091 output = {}
1092
1093 for interaction_info in self.ufomodel.all_vertices:
1094 if len(interaction_info.particles) != 3:
1095 continue
1096 colors = [abs(p.color) for p in interaction_info.particles]
1097 if colors[:2] == [3,3]:
1098 if 'T(3,2,1)' in interaction_info.color:
1099 color, anticolor, other = interaction_info.particles
1100 elif 'T(3,1,2)' in interaction_info.color:
1101 anticolor, color, _ = interaction_info.particles
1102 elif 'Identity(1,2)' in interaction_info.color or \
1103 'Identity(2,1)' in interaction_info.color:
1104 first, second, _ = interaction_info.particles
1105 if first.pdg_code in output:
1106 if output[first.pdg_code] == 3:
1107 color, anticolor = first, second
1108 else:
1109 color, anticolor = second, first
1110 elif second.pdg_code in output:
1111 if output[second.pdg_code] == 3:
1112 color, anticolor = second, first
1113 else:
1114 color, anticolor = first, second
1115 else:
1116 continue
1117 else:
1118 continue
1119 elif colors[1:] == [3,3]:
1120 if 'T(1,2,3)' in interaction_info.color:
1121 other, anticolor, color = interaction_info.particles
1122 elif 'T(1,3,2)' in interaction_info.color:
1123 other, color, anticolor = interaction_info.particles
1124 elif 'Identity(2,3)' in interaction_info.color or \
1125 'Identity(3,2)' in interaction_info.color:
1126 _, first, second = interaction_info.particles
1127 if first.pdg_code in output:
1128 if output[first.pdg_code] == 3:
1129 color, anticolor = first, second
1130 else:
1131 color, anticolor = second, first
1132 elif second.pdg_code in output:
1133 if output[second.pdg_code] == 3:
1134 color, anticolor = second, first
1135 else:
1136 color, anticolor = first, second
1137 else:
1138 continue
1139 else:
1140 continue
1141
1142 elif colors.count(3) == 2:
1143 if 'T(2,3,1)' in interaction_info.color:
1144 color, other, anticolor = interaction_info.particles
1145 elif 'T(2,1,3)' in interaction_info.color:
1146 anticolor, other, color = interaction_info.particles
1147 elif 'Identity(1,3)' in interaction_info.color or \
1148 'Identity(3,1)' in interaction_info.color:
1149 first, _, second = interaction_info.particles
1150 if first.pdg_code in output:
1151 if output[first.pdg_code] == 3:
1152 color, anticolor = first, second
1153 else:
1154 color, anticolor = second, first
1155 elif second.pdg_code in output:
1156 if output[second.pdg_code] == 3:
1157 color, anticolor = second, first
1158 else:
1159 color, anticolor = first, second
1160 else:
1161 continue
1162 else:
1163 continue
1164 else:
1165 continue
1166
1167
1168 if color.pdg_code in output:
1169 if output[color.pdg_code] == -3:
1170 raise InvalidModel, 'Particles %s is sometimes in the 3 and sometimes in the 3bar representations' \
1171 % color.name
1172 else:
1173 output[color.pdg_code] = 3
1174
1175
1176 if anticolor.pdg_code in output:
1177 if output[anticolor.pdg_code] == 3:
1178 raise InvalidModel, 'Particles %s is sometimes set as in the 3 and sometimes in the 3bar representations' \
1179 % anticolor.name
1180 else:
1181 output[anticolor.pdg_code] = -3
1182
1183 return output
1184
1186 """define which fermion should be incoming
1187 for that we look at F F~ X interactions
1188 """
1189 self.incoming = []
1190 self.outcoming = []
1191 for interaction_info in self.ufomodel.all_vertices:
1192
1193 pdg = [p.pdg_code for p in interaction_info.particles if p.spin in [2,4]]
1194 if len(pdg) % 2:
1195 raise InvalidModel, 'Odd number of fermion in vertex: %s' % [p.pdg_code for p in interaction_info.particles]
1196 for i in range(0, len(pdg),2):
1197 if pdg[i] == - pdg[i+1]:
1198 if pdg[i] in self.outcoming:
1199 raise InvalidModel, '%s has not coherent incoming/outcoming status between interactions' %\
1200 [p for p in interaction_info.particles if p.spin in [2,4]][i].name
1201
1202 elif not pdg[i] in self.incoming:
1203 self.incoming.append(pdg[i])
1204 self.outcoming.append(pdg[i+1])
1205
1206 - def add_interaction(self, interaction_info, color_info, type='base', loop_particles=None):
1207 """add an interaction in the MG5 model. interaction_info is the
1208 UFO vertices information."""
1209
1210 particles = [self.model.get_particle(particle.pdg_code) \
1211 for particle in interaction_info.particles]
1212 if None in particles:
1213
1214 return
1215 particles = base_objects.ParticleList(particles)
1216
1217
1218 lorentz = [helas for helas in interaction_info.lorentz]
1219
1220
1221 nb_fermion = sum([ 1 if p.is_fermion() else 0 for p in particles])
1222 try:
1223 if nb_fermion == 2:
1224
1225 [aloha_fct.check_flow_validity(helas.structure, nb_fermion) \
1226 for helas in interaction_info.lorentz
1227 if helas.name not in self.checked_lor]
1228 self.checked_lor.update(set([helas.name for helas in interaction_info.lorentz]))
1229 elif nb_fermion:
1230 if any(p.selfconjugate for p in interaction_info.particles if p.spin % 2 == 0):
1231 text = "Majorana can not be dealt in 4/6/... fermion interactions"
1232 raise InvalidModel, text
1233 except aloha_fct.WrongFermionFlow, error:
1234 text = 'Fermion Flow error for interactions %s: %s: %s\n %s' % \
1235 (', '.join([p.name for p in interaction_info.particles]),
1236 helas.name, helas.structure, error)
1237 raise InvalidModel, text
1238
1239
1240
1241
1242 lorentz = [helas.name for helas in lorentz]
1243
1244 colors = [self.treat_color(color_obj, interaction_info, color_info)
1245 for color_obj in interaction_info.color]
1246
1247
1248 order_to_int={}
1249
1250 for key, couplings in interaction_info.couplings.items():
1251 if not isinstance(couplings, list):
1252 couplings = [couplings]
1253 if interaction_info.lorentz[key[1]].name not in lorentz:
1254 continue
1255
1256 if nb_fermion > 2:
1257 flow = aloha_fct.get_fermion_flow(interaction_info.lorentz[key[1]].structure,
1258 nb_fermion)
1259 coupling_sign = self.get_sign_flow(flow, nb_fermion)
1260 else:
1261 coupling_sign = ''
1262 for coupling in couplings:
1263 order = tuple(coupling.order.items())
1264 if '1' in order:
1265 raise InvalidModel, '''Some couplings have \'1\' order.
1266 This is not allowed in MG.
1267 Please defines an additional coupling to your model'''
1268 if order in order_to_int:
1269 order_to_int[order].get('couplings')[key] = '%s%s' % \
1270 (coupling_sign,coupling.name)
1271 else:
1272
1273 interaction = base_objects.Interaction({'id':len(self.interactions)+1})
1274 interaction.set('particles', particles)
1275 interaction.set('lorentz', lorentz)
1276 interaction.set('couplings', {key:
1277 '%s%s' %(coupling_sign,coupling.name)})
1278 interaction.set('orders', coupling.order)
1279 interaction.set('color', colors)
1280 interaction.set('type', type)
1281 interaction.set('loop_particles', loop_particles)
1282 order_to_int[order] = interaction
1283
1284 self.interactions.append(interaction)
1285
1286
1287
1288 for charge in list(self.conservecharge):
1289 total = 0
1290 for part in interaction_info.particles:
1291 try:
1292 total += getattr(part, charge)
1293 except AttributeError:
1294 pass
1295 if abs(total) > 1e-12:
1296 logger.info('The model has interaction violating the charge: %s' % charge)
1297 self.conservecharge.discard(charge)
1298
1299
1300
1302 """ensure that the flow of particles/lorentz are coherent with flow
1303 and return a correct version if needed"""
1304
1305 if not flow or nb_fermion < 4:
1306 return ''
1307
1308 expected = {}
1309 for i in range(nb_fermion//2):
1310 expected[i+1] = i+2
1311
1312 if flow == expected:
1313 return ''
1314
1315 switch = {}
1316 for i in range(1, nb_fermion+1):
1317 if not i in flow:
1318 continue
1319 switch[i] = len(switch)
1320 switch[flow[i]] = len(switch)
1321
1322
1323 sign = 1
1324 done = []
1325
1326
1327
1328 new_order = []
1329 for id in range(nb_fermion):
1330 nid = switch[id+1]-1
1331
1332 new_order.append(nid)
1333
1334
1335 sign =1
1336 for k in range(len(new_order)-1):
1337 for l in range(k+1,len(new_order)):
1338 if new_order[l] < new_order[k]:
1339 sign *= -1
1340
1341 return '' if sign ==1 else '-'
1342
1344 """ Add a Lorentz expression which is not present in the UFO """
1345
1346 assert name not in [l.name for l in self.model['lorentz']]
1347 with misc.TMP_variable(self.ufomodel.object_library, 'all_lorentz',
1348 self.model['lorentz']):
1349 new = self.model['lorentz'][0].__class__(name = name,
1350 spins = spins,
1351 structure = expr)
1352 assert name in [l.name for l in self.model['lorentz']]
1353 assert name not in [l.name for l in self.ufomodel.all_lorentz]
1354
1355 self.model.create_lorentz_dict()
1356 return new
1357
1358 _pat_T = re.compile(r'T\((?P<first>\d*),(?P<second>\d*)\)')
1359 _pat_id = re.compile(r'Identity\((?P<first>\d*),(?P<second>\d*)\)')
1360
1361 - def treat_color(self, data_string, interaction_info, color_info):
1362 """ convert the string to ColorString"""
1363
1364
1365
1366
1367
1368 output = []
1369 factor = 1
1370 for term in data_string.split('*'):
1371 pattern = self._pat_id.search(term)
1372 if pattern:
1373 particle = interaction_info.particles[int(pattern.group('first'))-1]
1374 particle2 = interaction_info.particles[int(pattern.group('second'))-1]
1375 if particle.color == particle2.color and particle.color in [-6, 6]:
1376 error_msg = 'UFO model have inconsistency in the format:\n'
1377 error_msg += 'interactions for particles %s has color information %s\n'
1378 error_msg += ' but both fermion are in the same representation %s'
1379 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
1380 if particle.color == particle2.color and particle.color in [-3, 3]:
1381 if particle.pdg_code in color_info and particle2.pdg_code in color_info:
1382 if color_info[particle.pdg_code] == color_info[particle2.pdg_code]:
1383 error_msg = 'UFO model have inconsistency in the format:\n'
1384 error_msg += 'interactions for particles %s has color information %s\n'
1385 error_msg += ' but both fermion are in the same representation %s'
1386 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
1387 elif particle.pdg_code in color_info:
1388 color_info[particle2.pdg_code] = -particle.pdg_code
1389 elif particle2.pdg_code in color_info:
1390 color_info[particle.pdg_code] = -particle2.pdg_code
1391 else:
1392 error_msg = 'UFO model have inconsistency in the format:\n'
1393 error_msg += 'interactions for particles %s has color information %s\n'
1394 error_msg += ' but both fermion are in the same representation %s'
1395 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
1396
1397
1398 if particle.color == 6:
1399 output.append(self._pat_id.sub('color.T6(\g<first>,\g<second>)', term))
1400 elif particle.color == -6 :
1401 output.append(self._pat_id.sub('color.T6(\g<second>,\g<first>)', term))
1402 elif particle.color == 8:
1403 output.append(self._pat_id.sub('color.Tr(\g<first>,\g<second>)', term))
1404 factor *= 2
1405 elif particle.color in [-3,3]:
1406 if particle.pdg_code not in color_info:
1407
1408 logger.debug('fail to find 3/3bar representation: Retry to find it')
1409 color_info = self.find_color_anti_color_rep(color_info)
1410 if particle.pdg_code not in color_info:
1411 logger.debug('Not able to find the 3/3bar rep from the interactions for particle %s' % particle.name)
1412 color_info[particle.pdg_code] = particle.color
1413 else:
1414 logger.debug('succeed')
1415 if particle2.pdg_code not in color_info:
1416
1417 logger.debug('fail to find 3/3bar representation: Retry to find it')
1418 color_info = self.find_color_anti_color_rep(color_info)
1419 if particle2.pdg_code not in color_info:
1420 logger.debug('Not able to find the 3/3bar rep from the interactions for particle %s' % particle2.name)
1421 color_info[particle2.pdg_code] = particle2.color
1422 else:
1423 logger.debug('succeed')
1424
1425 if color_info[particle.pdg_code] == 3 :
1426 output.append(self._pat_id.sub('color.T(\g<second>,\g<first>)', term))
1427 elif color_info[particle.pdg_code] == -3:
1428 output.append(self._pat_id.sub('color.T(\g<first>,\g<second>)', term))
1429 else:
1430 raise MadGraph5Error, \
1431 "Unknown use of Identity for particle with color %d" \
1432 % particle.color
1433 else:
1434 output.append(term)
1435 data_string = '*'.join(output)
1436
1437
1438 p = re.compile(r'\'\w(?P<number>\d+)\'')
1439 data_string = p.sub('-\g<number>', data_string)
1440
1441
1442 new_indices = {}
1443 new_indices = dict([(j,i) for (i,j) in \
1444 enumerate(range(1,
1445 len(interaction_info.particles)+1))])
1446
1447
1448 output = data_string.split('*')
1449 output = color.ColorString([eval(data) \
1450 for data in output if data !='1'])
1451 output.coeff = fractions.Fraction(factor)
1452 for col_obj in output:
1453 col_obj.replace_indices(new_indices)
1454
1455 return output
1456
1458 """Organize the couplings/parameters of a model"""
1459
1460 track_dependant = ['aS','aEWM1','MU_R']
1461
1462
1463
1464
1465 complex_number = re.compile(r'''complex\((?P<real>[^,\(\)]+),(?P<imag>[^,\(\)]+)\)''')
1466 expo_expr = re.compile(r'''(?P<expr>[\w.]+)\s*\*\*\s*(?P<expo>[+-]?[\d.]+)''')
1467 cmath_expr = re.compile(r'''cmath.(?P<operation>\w+)\((?P<expr>\w+)\)''')
1468
1469 conj_expr = re.compile(r'''complexconjugate\((?P<expr>\w+)\)''')
1470
1471
1472 separator = re.compile(r'''[+,\-*/()\s]*''')
1473
1474
1476
1477 self.model = model
1478 self.perturbation_couplings = {}
1479 try:
1480 for order in model.all_orders:
1481 if(order.perturbative_expansion>0):
1482 self.perturbation_couplings[order.name]=order.perturbative_expansion
1483 except AttributeError:
1484 pass
1485 self.params = {}
1486 self.couplings = {}
1487 self.all_expr = {}
1488
1489 - def main(self, additional_couplings = []):
1490 """Launch the actual computation and return the associate
1491 params/couplings. Possibly consider additional_couplings in addition
1492 to those defined in the UFO model attribute all_couplings """
1493
1494 additional_params = []
1495 if hasattr(self.model,'all_CTparameters'):
1496 additional_params = self.get_additional_CTparameters()
1497
1498 self.analyze_parameters(additional_params = additional_params)
1499 self.analyze_couplings(additional_couplings = additional_couplings)
1500
1501
1502 if hasattr(self.model,'all_CTparameters'):
1503 self.revert_CTCoupling_modifications()
1504
1505 return self.params, self.couplings
1506
1508 """ Finally revert the possible modifications done by treat_couplings()
1509 in UFOMG5Converter which were useful for the add_CTinteraction() in
1510 particular. This modification consisted in expanding the value of a
1511 CTCoupling which consisted in an expression in terms of a CTParam to
1512 its corresponding dictionary (e.g
1513 CTCoupling.value = 2*CTParam ->
1514 CTCoupling.value = {-1: 2*CTParam_1EPS_, 0: 2*CTParam_FIN_}
1515 for example if CTParam had a non-zero finite and single pole."""
1516
1517 for coupl in self.model.all_couplings:
1518 if hasattr(coupl,'old_value'):
1519 coupl.value = coupl.old_value
1520 del(coupl.old_value)
1521
1523 """ For each CTparameter split it into spimple parameter for each pole
1524 and the finite part if not zero."""
1525
1526 additional_params = []
1527 for CTparam in self.model.all_CTparameters:
1528 for pole in range(3):
1529 if CTparam.pole(pole) != 'ZERO':
1530 CTparam_piece = copy.copy(CTparam)
1531 CTparam_piece.name = '%s_%s_'%(CTparam.name,pole_dict[-pole])
1532 CTparam_piece.nature = 'internal'
1533 CTparam_piece.type = CTparam.type
1534 CTparam_piece.value = CTparam.pole(pole)
1535 CTparam_piece.texname = '%s_{%s}'%\
1536 (CTparam.texname,pole_dict[-pole])
1537 additional_params.append(CTparam_piece)
1538 return additional_params
1539
1541 """ separate the parameters needed to be recomputed events by events and
1542 the others"""
1543
1544
1545
1546 present_aEWM1 = any(param.name == 'aEWM1' for param in
1547 self.model.all_parameters if param.nature == 'external')
1548
1549 if not present_aEWM1:
1550 self.track_dependant = ['aS','Gf','MU_R']
1551
1552 for param in self.model.all_parameters+additional_params:
1553 if param.nature == 'external':
1554 parameter = base_objects.ParamCardVariable(param.name, param.value, \
1555 param.lhablock, param.lhacode)
1556
1557 else:
1558 expr = self.shorten_expr(param.value)
1559 depend_on = self.find_dependencies(expr)
1560 parameter = base_objects.ModelVariable(param.name, expr, param.type, depend_on)
1561
1562 self.add_parameter(parameter)
1563
1565 """ add consistently the parameter in params and all_expr.
1566 avoid duplication """
1567
1568 assert isinstance(parameter, base_objects.ModelVariable)
1569
1570 if parameter.name in self.all_expr:
1571 return
1572
1573 self.all_expr[parameter.name] = parameter
1574 try:
1575 self.params[parameter.depend].append(parameter)
1576 except:
1577 self.params[parameter.depend] = [parameter]
1578
1580 """ add consistently the coupling in couplings and all_expr.
1581 avoid duplication """
1582
1583 assert isinstance(coupling, base_objects.ModelVariable)
1584
1585 if coupling.name in self.all_expr:
1586 return
1587 self.all_expr[coupling.value] = coupling
1588 try:
1589 self.coupling[coupling.depend].append(coupling)
1590 except:
1591 self.coupling[coupling.depend] = [coupling]
1592
1594 """creates the shortcut for all special function/parameter
1595 separate the couplings dependent of track variables of the others"""
1596
1597
1598
1599 if self.perturbation_couplings:
1600 couplings_list=[]
1601 for coupling in self.model.all_couplings + additional_couplings:
1602 if not isinstance(coupling.value,dict):
1603 couplings_list.append(coupling)
1604 else:
1605 for poleOrder in range(0,3):
1606 if coupling.pole(poleOrder)!='ZERO':
1607 newCoupling=copy.copy(coupling)
1608 if poleOrder!=0:
1609 newCoupling.name += "_%deps"%poleOrder
1610 newCoupling.value=coupling.pole(poleOrder)
1611
1612
1613
1614
1615
1616
1617
1618 couplings_list.append(newCoupling)
1619 else:
1620 couplings_list = self.model.all_couplings + additional_couplings
1621 couplings_list = [c for c in couplings_list if not isinstance(c.value, dict)]
1622
1623 for coupling in couplings_list:
1624
1625 expr = self.shorten_expr(coupling.value)
1626 depend_on = self.find_dependencies(expr)
1627 parameter = base_objects.ModelVariable(coupling.name, expr, 'complex', depend_on)
1628
1629 try:
1630 self.couplings[depend_on].append(parameter)
1631 except KeyError:
1632 self.couplings[depend_on] = [parameter]
1633 self.all_expr[coupling.value] = parameter
1634
1636 """check if an expression should be evaluated points by points or not
1637 """
1638 depend_on = set()
1639
1640
1641
1642
1643
1644
1645
1646 expr = self.separator.split(expr)
1647
1648
1649 for subexpr in expr:
1650 if subexpr in self.track_dependant:
1651 depend_on.add(subexpr)
1652
1653 elif subexpr in self.all_expr and self.all_expr[subexpr].depend:
1654 [depend_on.add(value) for value in self.all_expr[subexpr].depend
1655 if self.all_expr[subexpr].depend != ('external',)]
1656 if depend_on:
1657 return tuple(depend_on)
1658 else:
1659 return tuple()
1660
1661
1674
1675
1677 """add the short expression, and return the nice string associate"""
1678
1679 float_real = float(eval(matchobj.group('real')))
1680 float_imag = float(eval(matchobj.group('imag')))
1681 if float_real == 0 and float_imag ==1:
1682 new_param = base_objects.ModelVariable('complexi', 'complex(0,1)', 'complex')
1683 self.add_parameter(new_param)
1684 return 'complexi'
1685 else:
1686 return 'complex(%s, %s)' % (matchobj.group('real'), matchobj.group('imag'))
1687
1688
1690 """add the short expression, and return the nice string associate"""
1691
1692 expr = matchobj.group('expr')
1693 exponent = matchobj.group('expo')
1694 new_exponent = exponent.replace('.','_').replace('+','').replace('-','_m_')
1695 output = '%s__exp__%s' % (expr, new_exponent)
1696 old_expr = '%s**%s' % (expr,exponent)
1697
1698 if expr.startswith('cmath'):
1699 return old_expr
1700
1701 if expr.isdigit():
1702 output = 'nb__' + output
1703 new_param = base_objects.ModelVariable(output, old_expr,'real')
1704 else:
1705 depend_on = self.find_dependencies(expr)
1706 type = self.search_type(expr)
1707 new_param = base_objects.ModelVariable(output, old_expr, type, depend_on)
1708 self.add_parameter(new_param)
1709 return output
1710
1727
1740
1741
1742
1744 """return the type associate to the expression if define"""
1745
1746 try:
1747 return self.all_expr[expr].type
1748 except:
1749 return 'complex'
1750
1752 """ A class for restricting a model for a given param_card.
1753 rules applied:
1754 - Vertex with zero couplings are throw away
1755 - external parameter with zero/one input are changed into internal parameter.
1756 - identical coupling/mass/width are replace in the model by a unique one
1757 """
1758
1766
1767 - def restrict_model(self, param_card, rm_parameter=True, keep_external=False,
1768 complex_mass_scheme=None):
1838
1839
1841 """ create a dict couplings_name -> vertex or (particle, counterterm_key) """
1842
1843 self.coupling_pos = {}
1844 for vertex in self['interactions']:
1845 for key, coupling in vertex['couplings'].items():
1846 if coupling.startswith('-'):
1847 coupling = coupling[1:]
1848 if coupling in self.coupling_pos:
1849 if vertex not in self.coupling_pos[coupling]:
1850 self.coupling_pos[coupling].append(vertex)
1851 else:
1852 self.coupling_pos[coupling] = [vertex]
1853
1854 for particle in self['particles']:
1855 for key, coupling_dict in particle['counterterm'].items():
1856 for LaurentOrder, coupling in coupling_dict.items():
1857 if coupling in self.coupling_pos:
1858 if (particle,key) not in self.coupling_pos[coupling]:
1859 self.coupling_pos[coupling].append((particle,key))
1860 else:
1861 self.coupling_pos[coupling] = [(particle,key)]
1862
1863 return self.coupling_pos
1864
1866 """return a list with the name of all vanishing couplings"""
1867
1868 dict_value_coupling = {}
1869 iden_key = set()
1870 zero_coupling = []
1871 iden_coupling = []
1872
1873 for name, value in self['coupling_dict'].items():
1874 if value == 0:
1875 zero_coupling.append(name)
1876 continue
1877 elif not strict_zero and abs(value) < 1e-13:
1878 logger.debug('coupling with small value %s: %s treated as zero' %
1879 (name, value))
1880 zero_coupling.append(name)
1881 elif not strict_zero and abs(value) < 1e-10:
1882 return self.detect_identical_couplings(strict_zero=True)
1883
1884
1885 if value in dict_value_coupling or -1*value in dict_value_coupling:
1886 if value in dict_value_coupling:
1887 iden_key.add(value)
1888 dict_value_coupling[value].append((name,1))
1889 else:
1890 iden_key.add(-1*value)
1891 dict_value_coupling[-1*value].append((name,-1))
1892 else:
1893 dict_value_coupling[value] = [(name,1)]
1894 for key in iden_key:
1895 tmp = []
1896 if key in dict_value_coupling:
1897 tmp += dict_value_coupling[key]
1898 elif -1*key in dict_value_coupling:
1899 tmp += dict_value_coupling[-1*key]
1900 assert tmp
1901
1902
1903 ords = [self.get_coupling_order(k) for k,c in tmp]
1904 coup_by_ord = collections.defaultdict(list)
1905 for o,t in zip(ords, tmp):
1906 coup_by_ord[str(o)].append(t)
1907
1908 for tmp3 in coup_by_ord.values():
1909 if len(tmp3) > 1:
1910 if tmp3[0][1] == -1:
1911 tmp3 = [(t0,-t1) for t0, t1 in tmp3]
1912 iden_coupling.append(tmp3)
1913
1914
1915
1916
1917 return zero_coupling, iden_coupling
1918
1920 """return the coupling order associated to a coupling """
1921
1922 if cname in self.coupling_order_dict:
1923 return self.coupling_order_dict[cname]
1924
1925 for v in self['interactions']:
1926 for c in v['couplings'].values():
1927 self.coupling_order_dict[c] = v['orders']
1928
1929 if cname not in self.coupling_order_dict:
1930 self.coupling_order_dict[cname] = None
1931
1932
1933
1934 return self.coupling_order_dict[cname]
1935
1936
1937
1939 """ return the list of (name of) parameter which are zero """
1940
1941 null_parameters = []
1942 one_parameters = []
1943 for name, value in self['parameter_dict'].items():
1944 if value == 0 and name != 'ZERO':
1945 null_parameters.append(name)
1946 elif value == 1:
1947 one_parameters.append(name)
1948
1949 return null_parameters, one_parameters
1950
1953 """ Apply the conditional statement simplifications for parameters and
1954 couplings detected by 'simplify_conditional_statements'.
1955 modified_params (modified_couplings) are list of tuples (a,b) with a
1956 parameter (resp. coupling) instance and b is the simplified expression."""
1957
1958 if modified_params:
1959 logger.debug("Conditional expressions are simplified for parameters:")
1960 logger.debug(",".join("%s"%param[0].name for param in modified_params))
1961 for param, new_expr in modified_params:
1962 param.expr = new_expr
1963
1964 if modified_couplings:
1965 logger.debug("Conditional expressions are simplified for couplings:")
1966 logger.debug(",".join("%s"%coupl[0].name for coupl in modified_couplings))
1967 for coupl, new_expr in modified_couplings:
1968 coupl.expr = new_expr
1969
1972 """ Simplifies the 'if' statements in the pythonic UFO expressions
1973 of parameters using the default variables specified in the restrict card.
1974 It returns a list of objects (parameters or couplings) and the new
1975 expression that they should take. Model definitions include all definitons
1976 of the model functions and parameters."""
1977
1978 param_modifications = []
1979 coupl_modifications = []
1980 ifparser = parsers.UFOExpressionParserPythonIF(model_definitions)
1981
1982 start_param = time.time()
1983 if 'parameters' in objects:
1984 for dependences, param_list in self['parameters'].items():
1985 if 'external' in dependences:
1986 continue
1987 for param in param_list:
1988 new_expr, n_changes = ifparser.parse(param.expr)
1989 if n_changes > 0:
1990 param_modifications.append((param, new_expr))
1991
1992 end_param = time.time()
1993
1994 if 'couplings' in objects:
1995 for dependences, coupl_list in self['couplings'].items():
1996 for coupl in coupl_list:
1997 new_expr, n_changes = ifparser.parse(coupl.expr)
1998 if n_changes > 0:
1999 coupl_modifications.append((coupl, new_expr))
2000
2001 end_coupl = time.time()
2002
2003 tot_param_time = end_param-start_param
2004 tot_coupl_time = end_coupl-end_param
2005 if tot_param_time>5.0:
2006 logger.debug("Simplification of conditional statements"+\
2007 " in parameter expressions done in %s."%misc.format_time(tot_param_time))
2008 if tot_coupl_time>5.0:
2009 logger.debug("Simplification of conditional statements"+\
2010 " in couplings expressions done in %s."%misc.format_time(tot_coupl_time))
2011
2012 return param_modifications, coupl_modifications
2013
2015 """ return the list of tuple of name of parameter with the same
2016 input value """
2017
2018
2019 external_parameters = self['parameters'][('external',)]
2020
2021
2022 block_value_to_var={}
2023 mult_param = set([])
2024
2025
2026
2027 for param in external_parameters[:]:
2028 value = self['parameter_dict'][param.name]
2029 if value in [0,1,0.000001e-99,9.999999e-1]:
2030 continue
2031 if param.lhablock.lower() == 'decay':
2032 continue
2033 key = (param.lhablock, value)
2034 mkey = (param.lhablock, -value)
2035
2036 if key in block_value_to_var:
2037 block_value_to_var[key].append((param,1))
2038 mult_param.add(key)
2039 elif mkey in block_value_to_var:
2040 block_value_to_var[mkey].append((param,-1))
2041 mult_param.add(mkey)
2042 else:
2043 block_value_to_var[key] = [(param,1)]
2044
2045 output=[]
2046 for key in mult_param:
2047 output.append(block_value_to_var[key])
2048
2049 return output
2050
2051
2052 @staticmethod
2054 """ We have main == coeff * coupling
2055 coeff is only +1 or -1
2056 main can be either GC_X or -GC_X
2057 coupling can be either GC_Y or -GC_Y
2058 value is either GC_Y or -GC_Y
2059 the return is either GC_X or -GC_X
2060 such that we have value == OUTPUT
2061 """
2062 assert coeff in [-1,1]
2063 assert value == coupling or value == '-%s' % coupling or coupling == '-%s' % value
2064 assert isinstance(main, str)
2065 assert isinstance(coupling, str)
2066 assert isinstance(value, str)
2067 if coeff ==1:
2068 if value == coupling:
2069 return main
2070 else:
2071 if main.startswith('-'):
2072 return main[1:]
2073 else:
2074 return '-%s' % main
2075 else:
2076 if value == coupling:
2077 if main.startswith('-'):
2078 return main[1:]
2079 else:
2080 return '-%s' % main
2081 else:
2082 return main
2083
2084
2086 """merge the identical couplings in the interactions and particle
2087 counterterms"""
2088
2089
2090 logger_mod.debug(' Fuse the Following coupling (they have the same value): %s '% \
2091 ', '.join([str(obj) for obj in couplings]))
2092
2093 main = couplings[0][0]
2094 assert couplings[0][1] == 1
2095 self.del_coup += [c[0] for c in couplings[1:]]
2096
2097 for coupling, coeff in couplings[1:]:
2098
2099 if coupling not in self.coupling_pos:
2100 continue
2101
2102 vertices = [ vert for vert in self.coupling_pos[coupling] if
2103 isinstance(vert, base_objects.Interaction)]
2104 for vertex in vertices:
2105 for key, value in vertex['couplings'].items():
2106 if value == coupling or value == '-%s' % coupling or coupling == '-%s' % value:
2107 vertex['couplings'][key] = self.get_new_coupling_name(\
2108 main, coupling, value, coeff)
2109
2110
2111
2112
2113
2114 particles_ct = [ pct for pct in self.coupling_pos[coupling] if
2115 isinstance(pct, tuple)]
2116 for pct in particles_ct:
2117 for key, value in pct[0]['counterterm'][pct[1]].items():
2118 if value == coupling:
2119 pct[0]['counterterm'][pct[1]][key] = main
2120
2121
2122
2124 """return the list of block defined in the param_card"""
2125
2126 blocks = set([p.lhablock for p in self['parameters'][('external',)]])
2127 return blocks
2128
2130 """ merge the identical parameters given in argument.
2131 keep external force to keep the param_card untouched (up to comment)"""
2132
2133 logger_mod.debug('Parameters set to identical values: %s '% \
2134 ', '.join(['%s*%s' % (f, obj.name.replace('mdl_','')) for (obj,f) in parameters]))
2135
2136
2137 external_parameters = self['parameters'][('external',)]
2138 for i, (obj, factor) in enumerate(parameters):
2139
2140 if i == 0:
2141 obj.info = 'set of param :' + \
2142 ', '.join([str(f)+'*'+param.name.replace('mdl_','')
2143 for (param, f) in parameters])
2144 expr = obj.name
2145 continue
2146
2147 if factor ==1:
2148 self.rule_card.add_identical(obj.lhablock.lower(), obj.lhacode,
2149 parameters[0][0].lhacode )
2150 else:
2151 self.rule_card.add_opposite(obj.lhablock.lower(), obj.lhacode,
2152 parameters[0][0].lhacode )
2153 obj_name = obj.name
2154
2155 if not keep_external:
2156 external_parameters.remove(obj)
2157 elif obj.lhablock.upper() in ['MASS','DECAY']:
2158 external_parameters.remove(obj)
2159 else:
2160 obj.name = ''
2161 obj.info = 'MG5 will not use this value use instead %s*%s' %(factor,expr)
2162
2163 new_param = base_objects.ModelVariable(obj_name, '%s*%s' %(factor, expr), 'real')
2164 self['parameters'][()].insert(0, new_param)
2165
2166
2167
2168 if parameters[0][0].lhablock in ['MASS','DECAY']:
2169 new_name = parameters[0][0].name
2170 if parameters[0][0].lhablock == 'MASS':
2171 arg = 'mass'
2172 else:
2173 arg = 'width'
2174 change_name = [p.name for (p,f) in parameters[1:]]
2175 [p.set(arg, new_name) for p in self['particle_dict'].values()
2176 if p[arg] in change_name]
2177
2179 """ remove the interactions and particle counterterms
2180 associated to couplings"""
2181
2182
2183 mod_vertex = []
2184 mod_particle_ct = []
2185 for coup in zero_couplings:
2186
2187 if coup not in self.coupling_pos:
2188 continue
2189
2190
2191
2192 vertices = [ vert for vert in self.coupling_pos[coup] if
2193 isinstance(vert, base_objects.Interaction) ]
2194 for vertex in vertices:
2195 modify = False
2196 for key, coupling in vertex['couplings'].items():
2197 if coupling in zero_couplings:
2198 modify=True
2199 del vertex['couplings'][key]
2200 elif coupling.startswith('-'):
2201 coupling = coupling[1:]
2202 if coupling in zero_couplings:
2203 modify=True
2204 del vertex['couplings'][key]
2205
2206 if modify:
2207 mod_vertex.append(vertex)
2208
2209
2210 particles_ct = [ pct for pct in self.coupling_pos[coup] if
2211 isinstance(pct, tuple)]
2212 for pct in particles_ct:
2213 modify = False
2214 for key, coupling in pct[0]['counterterm'][pct[1]].items():
2215 if coupling in zero_couplings:
2216 modify=True
2217 del pct[0]['counterterm'][pct[1]][key]
2218 if modify:
2219 mod_particle_ct.append(pct)
2220
2221
2222 for vertex in mod_vertex:
2223 part_name = [part['name'] for part in vertex['particles']]
2224 orders = ['%s=%s' % (order,value) for order,value in vertex['orders'].items()]
2225
2226 if not vertex['couplings']:
2227 logger_mod.debug('remove interactions: %s at order: %s' % \
2228 (' '.join(part_name),', '.join(orders)))
2229 self['interactions'].remove(vertex)
2230 else:
2231 logger_mod.debug('modify interactions: %s at order: %s' % \
2232 (' '.join(part_name),', '.join(orders)))
2233
2234
2235 for pct in mod_particle_ct:
2236 part_name = pct[0]['name']
2237 order = pct[1][0]
2238 loop_parts = ','.join(['('+','.join([\
2239 self.get_particle(p)['name'] for p in part])+')' \
2240 for part in pct[1][1]])
2241
2242 if not pct[0]['counterterm'][pct[1]]:
2243 logger_mod.debug('remove counterterm of particle %s'%part_name+\
2244 ' with loop particles (%s)'%loop_parts+\
2245 ' perturbing order %s'%order)
2246 del pct[0]['counterterm'][pct[1]]
2247 else:
2248 logger_mod.debug('Modify counterterm of particle %s'%part_name+\
2249 ' with loop particles (%s)'%loop_parts+\
2250 ' perturbing order %s'%order)
2251
2252 return
2253
2255
2256 for name, data in self['couplings'].items():
2257 for coupling in data[:]:
2258 if coupling.name in couplings:
2259 data.remove(coupling)
2260
2261
2262 - def fix_parameter_values(self, zero_parameters, one_parameters,
2263 simplify=True, keep_external=False):
2264 """ Remove all instance of the parameters in the model and replace it by
2265 zero when needed."""
2266
2267
2268
2269 for particle in self['particles']:
2270 if particle['mass'] in zero_parameters:
2271 particle['mass'] = 'ZERO'
2272 if particle['width'] in zero_parameters:
2273 particle['width'] = 'ZERO'
2274 if particle['width'] in one_parameters:
2275 one_parameters.remove(particle['width'])
2276
2277 for pdg, particle in self['particle_dict'].items():
2278 if particle['mass'] in zero_parameters:
2279 particle['mass'] = 'ZERO'
2280 if particle['width'] in zero_parameters:
2281 particle['width'] = 'ZERO'
2282
2283
2284
2285 external_parameters = self['parameters'][('external',)]
2286 for param in external_parameters[:]:
2287 value = self['parameter_dict'][param.name]
2288 block = param.lhablock.lower()
2289 if value == 0:
2290 self.rule_card.add_zero(block, param.lhacode)
2291 elif value == 1:
2292 self.rule_card.add_one(block, param.lhacode)
2293
2294 special_parameters = zero_parameters + one_parameters
2295
2296
2297
2298 if simplify:
2299
2300 re_str = '|'.join(special_parameters)
2301 if len(re_str) > 25000:
2302 split = len(special_parameters) // 2
2303 re_str = ['|'.join(special_parameters[:split]),
2304 '|'.join(special_parameters[split:])]
2305 else:
2306 re_str = [ re_str ]
2307 used = set()
2308 for expr in re_str:
2309 re_pat = re.compile(r'''\b(%s)\b''' % expr)
2310
2311 for name, coupling_list in self['couplings'].items():
2312 for coupling in coupling_list:
2313 for use in re_pat.findall(coupling.expr):
2314 used.add(use)
2315 else:
2316 used = set([i for i in special_parameters if i])
2317
2318
2319 re_str = '|'.join([param for param in special_parameters if param not in used])
2320 if len(re_str) > 25000:
2321 split = len(special_parameters) // 2
2322 re_str = ['|'.join(special_parameters[:split]),
2323 '|'.join(special_parameters[split:])]
2324 else:
2325 re_str = [ re_str ]
2326 for expr in re_str:
2327 re_pat = re.compile(r'''\b(%s)\b''' % expr)
2328
2329 param_info = {}
2330
2331 for dep, param_list in self['parameters'].items():
2332 for tag, parameter in enumerate(param_list):
2333
2334 if parameter.name in special_parameters:
2335 param_info[parameter.name]= {'dep': dep, 'tag': tag,
2336 'obj': parameter}
2337 continue
2338
2339
2340 if isinstance(parameter, base_objects.ParamCardVariable):
2341 continue
2342
2343 if simplify:
2344 for use in re_pat.findall(parameter.expr):
2345 used.add(use)
2346
2347
2348 for param in used:
2349 if not param:
2350 continue
2351 data = self['parameters'][param_info[param]['dep']]
2352 data.remove(param_info[param]['obj'])
2353 tag = param_info[param]['tag']
2354 data = self['parameters'][()]
2355 if param in zero_parameters:
2356 data.insert(0, base_objects.ModelVariable(param, '0.0', 'real'))
2357 else:
2358 data.insert(0, base_objects.ModelVariable(param, '1.0', 'real'))
2359
2360
2361 for param in special_parameters:
2362
2363 if param in used or \
2364 (keep_external and param_info[param]['dep'] == ('external',)):
2365 logger_mod.debug('fix parameter value: %s' % param)
2366 continue
2367 logger_mod.debug('remove parameters: %s' % (param))
2368 data = self['parameters'][param_info[param]['dep']]
2369 data.remove(param_info[param]['obj'])
2370
2372
2373
2374
2375 to_lor = {}
2376 for (color, lor), coup in interaction['couplings'].items():
2377 abscoup, coeff = (coup[1:],-1) if coup.startswith('-') else (coup, 1)
2378 key = (color, abscoup)
2379 if key in to_lor:
2380 to_lor[key].append((lor,coeff))
2381 else:
2382 to_lor[key] = [(lor,coeff)]
2383
2384 nb_reduce = []
2385 optimize = False
2386 for key in to_lor:
2387 if len(to_lor[key]) >1:
2388 nb_reduce.append(len(to_lor[key])-1)
2389 optimize = True
2390
2391 if not optimize:
2392 return
2393
2394 if not hasattr(self, 'defined_lorentz_expr'):
2395 self.defined_lorentz_expr = {}
2396 self.lorentz_info = {}
2397 self.lorentz_combine = {}
2398 for lor in self.get('lorentz'):
2399 self.defined_lorentz_expr[lor.get('structure')] = lor.get('name')
2400 self.lorentz_info[lor.get('name')] = lor
2401
2402 for key in to_lor:
2403 if len(to_lor[key]) == 1:
2404 continue
2405 names = ['u%s' % interaction['lorentz'][i[0]] if i[1] ==1 else \
2406 'd%s' % interaction['lorentz'][i[0]] for i in to_lor[key]]
2407
2408 names.sort()
2409
2410
2411 if tuple(names) in self.lorentz_combine:
2412
2413 new_name = self.lorentz_combine[tuple(names)]
2414 else:
2415 new_name = self.add_merge_lorentz(names)
2416
2417
2418 color, coup = key
2419 to_remove = [(color, lor[0]) for lor in to_lor[key]]
2420 for rm in to_remove:
2421 del interaction['couplings'][rm]
2422
2423
2424 if new_name not in [l for l in interaction.get('lorentz')]:
2425 interaction.get('lorentz').append(new_name)
2426
2427
2428 new_l = interaction.get('lorentz').index(new_name)
2429
2430 interaction['couplings'][(color, new_l)] = coup
2431
2432
2433
2435 """add a lorentz structure which is the sume of the list given above"""
2436
2437
2438 ii = len(names[0])
2439 while ii>1:
2440
2441 if not all(n[1:].startswith(names[0][1:ii]) for n in names[1:]):
2442 ii -=1
2443 else:
2444 base_name = names[0][1:ii]
2445 break
2446 else:
2447 base_name = 'LMER'
2448 i = 1
2449 while '%s%s' %(base_name, i) in self.lorentz_info:
2450 i +=1
2451 new_name = '%s%s' %(base_name, i)
2452 self.lorentz_combine[tuple(names)] = new_name
2453
2454
2455 new_struct = ' + '.join([self.lorentz_info[n[1:]].get('structure') for n in names if n.startswith('u')])
2456 if any( n.startswith('d') for n in names ):
2457 new_struct += '-' + ' - '.join(['1.*(%s)' %self.lorentz_info[n[1:]].get('structure') for n in names if n.startswith('d')])
2458 spins = self.lorentz_info[names[0][1:]].get('spins')
2459 new_lor = self.add_lorentz(new_name, spins, new_struct)
2460 self.lorentz_info[new_name] = new_lor
2461
2462 return new_name
2463
2465 """adding lorentz structure to the current model"""
2466 new = self['lorentz'][0].__class__(name = name,
2467 spins = spin,
2468 structure = struct)
2469 self['lorentz'].append(new)
2470 self.create_lorentz_dict()
2471
2472 return None
2473